Android实现3D云标签效果 Android实现3D云标签效果
程序猿L 人气:0一、自定义View
public class TagCloudView extends RelativeLayout { RelativeLayout navigation_bar; TextView mTextView1; private final float TOUCH_SCALE_FACTOR = .8f; private float tspeed; private TagCloud mTagCloud; private float mAngleX =0; private float mAngleY =0; private float centerX, centerY; private float radius; private Context mContext; private List<TextView> mTextView; private List<RelativeLayout.LayoutParams> mParams; private int shiftLeft; float dowx = 0; float dowy = 0; float cutx=100; float cuty=100; public TagCloudView(Context mContext, int width, int height, List<Tag> tagList) { this(mContext, width, height, tagList, 6 , 34, 1); } public TagCloudView(Context mContext, int width, int height, List<Tag> tagList, int textSizeMin, int textSizeMax, int scrollSpeed) { super(mContext); this.mContext= mContext; tspeed = scrollSpeed; centerX = width / 2; centerY = height / 2; radius = Math.min(centerX * 0.95f , centerY * 0.95f ); shiftLeft = (int)(Math.min(centerX * 0.15f , centerY * 0.15f )); mTagCloud = new TagCloud(tagList, (int) radius , textSizeMin, textSizeMax); float[] tempColor1 = {0.9412f,0.7686f,0.2f,1}; //rgb Alpha //{1f,0f,0f,1} red {0.3882f,0.21568f,0.0f,1} orange //{0.9412f,0.7686f,0.2f,1} light orange float[] tempColor2 = {1f,0f,0f,1}; //rgb Alpha //{0f,0f,1f,1} blue {0.1294f,0.1294f,0.1294f,1} grey //{0.9412f,0.7686f,0.2f,1} light orange mTagCloud.setTagColor1(tempColor1);//higher color mTagCloud.setTagColor2(tempColor2);//lower color mTagCloud.setRadius((int) radius); mTagCloud.create(true); mTagCloud.setAngleX(mAngleX); mTagCloud.setAngleY(mAngleY); mTagCloud.update(); mTextView = new ArrayList<TextView>(); mParams = new ArrayList<RelativeLayout.LayoutParams>(); Iterator<?> it=mTagCloud.iterator(); Tag tempTag; int i=0; //取出每个数据放到TexView里 while (it.hasNext()){ tempTag= (Tag) it.next(); tempTag.setParamNo(i); mTextView.add(new TextView(this.mContext)); mTextView.get(i).setText(tempTag.getText()); mParams.add(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); mParams.get(i).addRule(RelativeLayout.ALIGN_PARENT_LEFT); mParams.get(i).addRule(RelativeLayout.ALIGN_PARENT_TOP); mParams.get(i).setMargins((int) (centerX -shiftLeft + tempTag.getLoc2DX()),(int) (centerY + tempTag.getLoc2DY()),0,0); mTextView.get(i).setLayoutParams(mParams.get(i)); mTextView.get(i).setSingleLine(true); int mergedColor = Color.argb((int)(tempTag.getAlpha() * 255), (int) (tempTag.getColorR() * 255), (int) (tempTag.getColorG() * 255),(int) (tempTag.getColorB() * 255)); mTextView.get(i).setTextColor(mergedColor); mTextView.get(i).setTextSize((int)(tempTag.getTextSize() * tempTag.getScale())); addView(mTextView.get(i)); mTextView.get(i).setOnClickListener(OnTagClickListener(tempTag.getUrl())); //设置每个TexView有自己指定的标签为自己的位置,以便后期操作 mTextView.get(i).setTag(i); i++; } /** 用来自动播放的*/ new Timer().schedule(new TimerTask() { @Override public void run() { handler.sendEmptyMessage(1); } }, 0,200); } @SuppressLint("HandlerLeak") Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); mAngleX = (cuty/radius) *tspeed * TOUCH_SCALE_FACTOR; mAngleY = (-cutx/radius) *tspeed * TOUCH_SCALE_FACTOR; changPosition(); } }; @Override protected void onDraw(Canvas canvas){ super.onDraw(canvas); } /** * 触发事件 */ @Override public boolean onTouchEvent(MotionEvent e) { switch (e.getAction()) { case MotionEvent.ACTION_DOWN: dowx=e.getX(); dowy=e.getY(); break; case MotionEvent.ACTION_UP: float upx=e.getX(); float upy=e.getY(); cutx=upx-dowx; cuty=upy-dowy; break; case MotionEvent.ACTION_MOVE: mAngleX = (cuty/radius) *tspeed * TOUCH_SCALE_FACTOR; mAngleY = (-cutx/radius) *tspeed * TOUCH_SCALE_FACTOR; changPosition(); break; } return true; } /** * 改变位置 */ private void changPosition(){ mTagCloud.setAngleX(mAngleX); mTagCloud.setAngleY(mAngleY); mTagCloud.update(); Iterator<?> it=mTagCloud.iterator(); Tag tempTag; while (it.hasNext()){ tempTag= (Tag) it.next(); mParams.get(tempTag.getParamNo()).setMargins( (int) (centerX -shiftLeft + tempTag.getLoc2DX()), (int) (centerY + tempTag.getLoc2DY()), 0, 0); mTextView.get(tempTag.getParamNo()).setTextSize((int)(tempTag.getTextSize() * tempTag.getScale())); int mergedColor = Color.argb( (int) (tempTag.getAlpha() * 255), (int) (tempTag.getColorR() * 255), (int) (tempTag.getColorG() * 255), (int) (tempTag.getColorB() * 255)); mTextView.get(tempTag.getParamNo()).setTextColor(mergedColor); mTextView.get(tempTag.getParamNo()).bringToFront(); } } /** * 点击事件 * @param url * @return */ View.OnClickListener OnTagClickListener(final String url){ return new View.OnClickListener(){ @Override public void onClick(View v) { } }; } }
二、自定义迭代器
/** * 自定义的迭代器 * @author Administrator * */ public class TagCloud implements Iterable<Object>{ private List<Tag> tagCloud; private int radius; private static final int DEFAULT_RADIUS = 3; private static final int TEXT_SIZE_MAX = 30 , TEXT_SIZE_MIN= 4; private static final float[] DEFAULT_COLOR1= { 0.886f, 0.725f, 0.188f, 1f}; private static final float[] DEFAULT_COLOR2= { 0.3f, 0.3f, 0.3f, 1f}; private float[] tagColor1; private float[] tagColor2; private int textSizeMax, textSizeMin; private float sin_mAngleX,cos_mAngleX,sin_mAngleY,cos_mAngleY,sin_mAngleZ,cos_mAngleZ; private float mAngleZ=0; private float mAngleX =0; private float mAngleY =0; private int size=0; private int smallest,largest; private boolean distrEven = true; public TagCloud(){ this(new ArrayList<Tag>()); } public TagCloud(List<Tag> tags){ this(tags,DEFAULT_RADIUS); } public TagCloud(List<Tag> tags, int radius){ this( tags, radius, DEFAULT_COLOR1, DEFAULT_COLOR2, TEXT_SIZE_MIN, TEXT_SIZE_MAX); } public TagCloud(List<Tag> tags, int radius,int textSizeMin, int textSizeMax){ this( tags, radius, DEFAULT_COLOR1, DEFAULT_COLOR2, textSizeMin, textSizeMax); } public TagCloud(List<Tag> tags, int radius,float[] tagColor1, float[] tagColor2){ this( tags, radius, tagColor1, tagColor2, TEXT_SIZE_MIN, TEXT_SIZE_MAX); } public TagCloud(List<Tag> tags, int radius, float[] tagColor1, float[] tagColor2, int textSizeMin, int textSizeMax){ this.tagCloud=tags; this.radius = radius; this.tagColor1 = tagColor1; this.tagColor2 = tagColor2; this.textSizeMax = textSizeMax; this.textSizeMin = textSizeMin; } /** * 重写的方法 */ @Override public Iterator iterator() { return tagCloud.iterator(); } /** * 创建 * @param distrEven */ public void create(boolean distrEven){ this.distrEven =distrEven; positionAll(distrEven); sineCosine( mAngleX, mAngleY, mAngleZ); updateAll(); smallest = 9999; largest = 0; for (int i=0; i< tagCloud.size(); i++){ int j = tagCloud.get(i).getPopularity(); largest = Math.max(largest, j); smallest = Math.min(smallest, j); } Tag tempTag; for (int i=0; i< tagCloud.size(); i++){ tempTag = tagCloud.get(i); int j = tempTag.getPopularity(); float percentage = ( smallest == largest ) ? 1.0f : ((float)j-smallest) / ((float)largest-smallest); float[] tempColor = getColorFromGradient( percentage ); //(rgb Alpha) int tempTextSize = getTextSizeGradient( percentage ); tempTag.setColorR(tempColor[0]); tempTag.setColorG(tempColor[1]); tempTag.setColorB(tempColor[2]); tempTag.setTextSize(tempTextSize); } this.size= tagCloud.size(); } /** * create创建完,就需要update */ public void update(){ if( Math.abs(mAngleX) > .1 || Math.abs(mAngleY) > .1 ){ sineCosine( mAngleX, mAngleY, mAngleZ); updateAll(); } } /** * 计算每个Tag的 * @param distrEven 是否根据字计算位置 true为是,否则字有覆盖的 */ private void positionAll(boolean distrEven){ double phi = 0; double theta = 0; int max = tagCloud.size(); for (int i=1; i<max+1; i++){ if (distrEven){ phi = Math.acos(-1.0 + (2.0*i -1.0)/max); theta = Math.sqrt(max*Math.PI) * phi; } else{ phi = Math.random()*(Math.PI); theta = Math.random()*(2 * Math.PI); } tagCloud.get(i-1).setLocX((int)( (radius * Math.cos(theta) * Math.sin(phi)))); tagCloud.get(i-1).setLocY((int)(radius * Math.sin(theta) * Math.sin(phi))); tagCloud.get(i-1).setLocZ((int)(radius * Math.cos(phi))); } } /** * 更新所有的Tag位置 */ private void updateAll(){ int max = tagCloud.size(); for (int j=0; j<max; j++){ float rx1 = (tagCloud.get(j).getLocX()); float ry1 = (tagCloud.get(j).getLocY()) * cos_mAngleX + tagCloud.get(j).getLocZ() * -sin_mAngleX; float rz1 = (tagCloud.get(j).getLocY()) * sin_mAngleX + tagCloud.get(j).getLocZ() * cos_mAngleX; float rx2 = rx1 * cos_mAngleY + rz1 * sin_mAngleY; float ry2 = ry1; float rz2 = rx1 * -sin_mAngleY + rz1 * cos_mAngleY; float rx3 = rx2 * cos_mAngleZ + ry2 * -sin_mAngleZ; float ry3 = rx2 * sin_mAngleZ + ry2 * cos_mAngleZ; float rz3 = rz2; tagCloud.get(j).setLocX(rx3); tagCloud.get(j).setLocY(ry3); tagCloud.get(j).setLocZ(rz3); int diameter = 2 * radius; float per = diameter / (diameter+rz3); tagCloud.get(j).setLoc2DX((int)(rx3 * per)); tagCloud.get(j).setLoc2DY((int)(ry3 * per)); tagCloud.get(j).setScale(per); tagCloud.get(j).setAlpha(per / 2); } //给Tag排序 Collections.sort(tagCloud); } /** * 计算字体颜色 * @param perc * @return */ private float[] getColorFromGradient(float perc){ float[] tempRGB = new float[4]; tempRGB[0] = ( perc * ( tagColor1[0] ) ) + ( (1-perc) * ( tagColor2[0] ) ); tempRGB[1] = ( perc * ( tagColor1[1] ) ) + ( (1-perc) * ( tagColor2[1] ) ); tempRGB[2] = ( perc * ( tagColor1[2] ) ) + ( (1-perc) * ( tagColor2[2] ) ); tempRGB[3] = 1; return tempRGB; } /** * 计算字体的大小 * @param perc * @return */ private int getTextSizeGradient(float perc){ int size; size = (int)( perc*textSizeMax + (1-perc)*textSizeMin ); return size; } /** * 计算圆形的x y z坐标 * @param mAngleX * @param mAngleY * @param mAngleZ */ private void sineCosine(float mAngleX,float mAngleY,float mAngleZ) { double degToRad = (Math.PI / 180); sin_mAngleX= (float) Math.sin( mAngleX * degToRad); cos_mAngleX= (float) Math.cos( mAngleX * degToRad); sin_mAngleY= (float) Math.sin( mAngleY * degToRad); cos_mAngleY= (float) Math.cos( mAngleY * degToRad); sin_mAngleZ= (float) Math.sin( mAngleZ * degToRad); cos_mAngleZ= (float) Math.cos( mAngleZ * degToRad); } /** * 以下是get set方法 * @return */ public int getRadius() { return radius; } public void setRadius(int radius) { this.radius = radius; } public float[] getTagColor1() { return tagColor1; } public void setTagColor1(float[] tagColor) { this.tagColor1 = tagColor; } public float[] getTagColor2() { return tagColor2; } public void setTagColor2(float[] tagColor2) { this.tagColor2 = tagColor2; } public float getRvalue(float[] color) { if (color.length>0) return color[0]; else return 0; } public float getGvalue(float[] color) { if (color.length>0) return color[1]; else return 0; } public float getBvalue(float[] color) { if (color.length>0) return color[2]; else return 0; } public float getAlphaValue(float[] color) { if (color.length >= 4) return color[3]; else return 0; } public float getAngleX() { return mAngleX; } public void setAngleX(float mAngleX) { this.mAngleX = mAngleX; } public float getAngleY() { return mAngleY; } public void setAngleY(float mAngleY) { this.mAngleY = mAngleY; } public int getSize() { return size; } }
三、自定义数据
/** * Comparable接口 可以自定义排序方式 * @author Administrator * */ public class Tag implements Comparable<Tag>{ private String text, url; private int popularity; private int textSize; private float locX, locY, locZ; private float loc2DX, loc2DY; private float scale; private float colorR, colorG, colorB, alpha; private static final int DEFAULT_POPULARITY = 1; private int paramNo; public Tag(String text, int popularity) { this(text, 0f, 0f, 0f, 1.0f, popularity, ""); } public Tag(String text, int popularity, String url) { this(text, 0f, 0f, 0f, 1.0f, popularity, url); } public Tag(String text,float locX, float locY, float locZ) { this(text, locX, locY, locZ, 1.0f, DEFAULT_POPULARITY, ""); } public Tag(String text,float locX, float locY, float locZ, float scale) { this(text, locX, locY, locZ, scale, DEFAULT_POPULARITY, ""); } public Tag(String text,float locX, float locY, float locZ, float scale, int popularity, String url) { this.text = text; this.locX = locX; this.locY = locY; this.locZ = locZ; this.loc2DX = 0; this.loc2DY=0; this.colorR= 0.5f; this.colorG= 0.5f; this.colorB= 0.5f; this.alpha = 1.0f; this.scale = scale; this.popularity= popularity; this.url = url; } @Override public int compareTo(Tag another) { //排序方式 return (int)(another.locZ - locZ); } public float getLocX() { return locX; } public void setLocX(float locX) { this.locX = locX; } public float getLocY() { return locY; } public void setLocY(float locY) { this.locY = locY; } public float getLocZ() { return locZ; } public void setLocZ(float locZ) { this.locZ = locZ; } public float getScale() { return scale; } public void setScale(float scale) { this.scale = scale; } public String getText() { return text; } public void setText(String text) { this.text = text; } public float getColorR() { return colorR; } public void setColorR(float colorR) { this.colorR = colorR; } public float getColorG() { return colorG; } public void setColorG(float colorG) { this.colorG = colorG; } public float getColorB() { return colorB; } public void setColorB(float colorB) { this.colorB = colorB; } public float getAlpha() { return alpha; } public void setAlpha(float alpha) { this.alpha = alpha; } public int getPopularity() { return popularity; } public void setPopularity(int popularity) { this.popularity = popularity; } public int getTextSize() { return textSize; } public void setTextSize(int textSize) { this.textSize = textSize; } public float getLoc2DX() { return loc2DX; } public void setLoc2DX(float loc2dx) { loc2DX = loc2dx; } public float getLoc2DY() { return loc2DY; } public void setLoc2DY(float loc2dy) { loc2DY = loc2dy; } public int getParamNo() { return paramNo; } public void setParamNo(int paramNo) { this.paramNo = paramNo; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
四、调用
private TagCloudView mTagCloudView; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); Display display = getWindowManager().getDefaultDisplay(); @SuppressWarnings("deprecation") int width = display.getWidth(); @SuppressWarnings("deprecation") int height = display.getHeight(); List<Tag> myTagList= createTags(); mTagCloudView = new TagCloudView(this, width, height, myTagList ); setContentView(mTagCloudView); mTagCloudView.requestFocus(); mTagCloudView.setFocusableInTouchMode(true); } private List<Tag> createTags(){ List<Tag> tempList = new ArrayList<Tag>(); tempList.add(new Tag("Google", 7, "http://www.google.com")); tempList.add(new Tag("Yahoo", 3, "www.yahoo.com")); tempList.add(new Tag("CNN", 4, "www.cnn.com")); tempList.add(new Tag("MSNBC", 5, "www.msnbc.com")); tempList.add(new Tag("CNBC", 5, "www.CNBC.com")); tempList.add(new Tag("Facebook", 7, "www.facebook.com")); tempList.add(new Tag("Youtube", 3, "www.youtube.com")); tempList.add(new Tag("BlogSpot", 5, "www.blogspot.com")); tempList.add(new Tag("Bing", 3, "www.bing.com")); tempList.add(new Tag("Wikipedia", 8, "www.wikipedia.com")); tempList.add(new Tag("Twitter", 5, "www.twitter.com")); tempList.add(new Tag("Msn", 1, "www.msn.com")); tempList.add(new Tag("Amazon", 3, "www.amazon.com")); tempList.add(new Tag("Ebay", 7, "www.ebay.com")); tempList.add(new Tag("LinkedIn", 5, "www.linkedin.com")); tempList.add(new Tag("Live", 7, "www.live.com")); tempList.add(new Tag("Microsoft", 3, "www.microsoft.com")); tempList.add(new Tag("Flicker", 1, "www.flicker.com")); tempList.add(new Tag("Apple", 5, "www.apple.com")); tempList.add(new Tag("Paypal", 5, "www.paypal.com")); tempList.add(new Tag("Craigslist", 7, "www.craigslist.com")); tempList.add(new Tag("Imdb", 2, "www.imdb.com")); tempList.add(new Tag("Ask", 4, "www.ask.com")); tempList.add(new Tag("Weibo", 1, "www.weibo.com")); tempList.add(new Tag("Tagin!", 8, "http://scyp.idrc.ocad.ca/projects/tagin")); tempList.add(new Tag("Shiftehfar", 8, "www.shiftehfar.org")); tempList.add(new Tag("Soso", 5, "www.google.com")); tempList.add(new Tag("XVideos", 3, "www.xvideos.com")); tempList.add(new Tag("BBC", 5, "www.bbc.co.uk")); return tempList; }
源码下载地址点击打开链接
加载全部内容