您的位置:首页 > 移动开发 > Android开发

[android view]标签云原理、难点以及简单实现总结

2015-06-24 16:10 671 查看
标签云效果很酷,比如最出名的wordle,看看能否在andorid上实现,才发现并不容易,因为我是想做可视化而并不是为了分词,所以感觉难点在布局。这里有两篇博客http://book.51cto.com/art/201108/281730.htm,http://book.51cto.com/art/201108/281728.htm,写的不错第一篇博客提到了在wordle里采用的方法就是一个简单有效的算法——随机贪婪算法。你可以随意地把单词拖放到屏幕中某个期望位置附近,而如果该单词和其他单词存在交叠,就重新再试一次,直到它不再与其他单词交叠为止,第二篇与之不同的是说在调整相应位置时根据一定的路径,
在这里再推荐下http://stackoverflow.com/questions/342687/algorithm-to-implement-a-word-cloud-like-wordle 这个问题wordle原作者亲自回答~~而且还有其他人做的一些。

开始在andorid上下手, 搜了一下并且下载了一个做的还可以的源码 附上链接http://www.apkbus.com/android-232291-1-1.html 它比较好的地方是实现了动画效果,他大体是重写viewgroup 把textview放进去布局,他在找textview大体好像是要记录已经走过的xy。。如果相交,按一定的路径来找下一个可以放置的点,具体代码就我就不班门弄斧而且也没怎么看懂~写的很好,而且有些小地方我借鉴了,比如如何确定字矩形的宽度。我主要的想法是直接重写view
然后让文字直接drawtext。主要是在检测到矩形相交后随机在选择点进行计算(汗,还真是随机贪婪算法,一点路径也没考虑),直到放好所有的。。这就导致并不是所有的时候都能够完美的展现出来(BUG),而且即使摆放好也与想要的效果差好远~~(好累,不想改了真的很麻烦)除了这一点 在改进检测重复即检测碰撞算法上也可以改进,基本上上面那几个博客都有提到,我想用四叉树(http://bbs.9ria.com/thread-148625-1-1.html)改进下,结果效果反而越来越不好,(好心烦 最后我去掉了
我感觉是因为andorid屏幕太小造成的 也可能是我代码造成的),反正在安卓上放的标签也不可能太多,所以对效率影响不大。最后大体就做了这么一个东西,只能叫做东西了好丑,我也不知道200*200能放多少标签,反正自己慢慢试。。



详细代码:

package com.example.visualization;

import com.example.tools.CloudItemClickListener;
import com.example.tools.TagCloud;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

public class TagCloudActivity extends Activity {
TagCloud cloud;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.tagcloud);

cloud = (TagCloud) findViewById(R.id.tag);
cloud.addTag("ZZG");
cloud.addTag("LXH");
cloud.addTag("ZLJ");
cloud.addTag("QQ");

cloud.addTag("3D");
cloud.addTag("ZLJ");
cloud.addTag("QQ");
cloud.addTag("3D");

cloud.addTag("ZLJ");
cloud.addTag("QQ");
cloud.addTag("3D");
cloud.addTag("雅诗兰黛");

cloud.addTag("铅笔");
cloud.addTag("QQ");
cloud.addTag("SPYMouse");
cloud.setShowRect(0, 0, 300, 300);// show size
cloud.setOnCloudItemClickListener(new CloudItemClickListener() {

@Override
public void selected(int i) {
// TODO Auto-generated method stub
Toast.makeText(TagCloudActivity.this,
cloud.tags.get(i).getText(), Toast.LENGTH_SHORT).show();

}
});
cloud.start();
}

}


package com.example.tools;

import java.util.ArrayList;
import java.util.Random;

import com.example.model.Tag;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

public class TagCloud extends View {
public ArrayList<Tag> tags = new ArrayList<Tag>();
CloudItemClickListener cloudItemClickListener;
Paint paint = new Paint();
int TOP = 0;
int BOTTOM = 300;
int LEFT = 0;
int RIGHT = 300;
boolean isDraw = false;
boolean isNew = false;

// Quadtree quad;
public TagCloud(Context context) {
super(context);
// TODO Auto-generated constructor stub

}

public TagCloud(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub

}

public TagCloud(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub

}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
for (int i = 0; i < tags.size(); i++) {
Tag tag = tags.get(i);
canvas.drawText(tag.getText(), tags.get(i).getRect().left, tags
.get(i).getRect().bottom, tags.get(i).getPaint());

}
super.onDraw(canvas);
}

public void setOnCloudItemClickListener(CloudItemClickListener clickListener) {
cloudItemClickListener = clickListener;
}

public void init() {

int positionX = (BOTTOM + TOP) / 2;
int positionY = (RIGHT + LEFT) / 2;
// quad = new Quadtree(0, new Rect(LEFT,TOP,RIGHT,BOTTOM));
// ArrayList<Tag> returnObjects = new ArrayList<Tag>();
Log.e("all", "TOP" + TOP + "BOTTOM" + BOTTOM + "LEFT" + LEFT + "RIGHT"
+ RIGHT + " ," + tags.size());
for (int i = 0; i < tags.size(); i++) {
Random random = new Random();

if (i % 2 == 0) {
tags.get(i).setX(
positionX + random.nextInt((RIGHT - LEFT) / 20));
tags.get(i).setY(
positionY + random.nextInt((BOTTOM - TOP) / 20));
} else {
tags.get(i).setX(
positionX - random.nextInt((RIGHT - LEFT) / 20));
tags.get(i).setY(
positionY - random.nextInt((BOTTOM - TOP) / 20));
}

/*
* tags.get(i).setX(positionX); tags.get(i).setY(positionY);
*/
// returnObjects.clear();

// quad.retrieve(returnObjects, tags.get(i).getRect());
int x = 0;

Log.e("=======1", tags.get(i).getRect().left + ","
+ tags.get(i).getRect().top + ","
+ tags.get(i).getRect().right + ","
+ tags.get(i).getRect().bottom);

// while(x<returnObjects.size())
while (x < i) {
// Run collision detection algorithm between objects
isNew = false;

while (Rect.intersects(tags.get(i).getRect(), tags.get(x)
.getRect())) {

int ranx = random.nextInt(RIGHT + LEFT);
int rany = random.nextInt(BOTTOM + TOP);
while (ranx + tags.get(i).getRect().width() > RIGHT
|| rany + tags.get(i).getRect().height() > BOTTOM
|| ranx < LEFT || rany < TOP) {
ranx = random.nextInt(RIGHT + LEFT);
rany = random.nextInt(BOTTOM + TOP);
}
tags.get(i).setX(ranx);
tags.get(i).setY(rany);

isNew = true;
}
if (isNew) {
x = -1;
}
x++;

}

// quad.insert(tags.get(i));
Log.e("=======2", tags.get(i).getRect().left + ","
+ tags.get(i).getRect().top + ","
+ tags.get(i).getRect().right + ","
+ tags.get(i).getRect().bottom);

}
isDraw = true;

}

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
float x = event.getX();
float y = event.getY();
Log.e("Raw x y", "" + event.getX() + "," + event.getY());
for (int i = 0; i < tags.size(); i++) {
if (tags.get(i).getRect().contains((int) x, (int) y)) {
cloudItemClickListener.selected(i);
}
}
}
break;
}
return super.onTouchEvent(event);
}

public void addTag(String text) {
Tag tag = new Tag();
tag.setText(text);
tag.setPaint();
tags.add(tag);
}

public void setPositionSize() {

}

public void start() {
new Thread(new mythread()).start();
if (isDraw) {
postInvalidate();
}
}

class mythread implements Runnable {

@Override
public void run() {
// TODO Auto-generated method stub
init();

}

}

public void setShowRect(int left, int top, int right, int bottom) {
TOP = top;
LEFT = left;
RIGHT = right;
BOTTOM = bottom;
}

}


package com.example.model;

import java.util.Random;

import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;

public class Tag {
public static final int TEXT_SIZE_MAX = 25;
public static final int TEXT_SIZE_MIN = 20;
String text;
int strWidth;
Paint paint = new Paint();
float x;
float y;
int alpha;
Random random = new Random();
float scale = 25 + random.nextInt(TEXT_SIZE_MAX - TEXT_SIZE_MIN + 1);

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}

int ranColor = 0xff000000 | random.nextInt(0x0077ffff);

public float getX() {
return x;
}

public void setX(float x) {
this.x = x;
}

public float getY() {
return y;
}

public void setY(float y) {
this.y = y;
}

public int getAlpha() {
return alpha;
}

public void setAlpha(int alpha) {
this.alpha = alpha;
}

public float getScale() {
return scale;
}

public void setScale(float scale) {
this.scale = scale;
}

public Random getRandom() {
return random;
}

public void setRandom(Random random) {
this.random = random;
}

public int getRanColor() {
return ranColor;
}

public void setRanColor(int ranColor) {
this.ranColor = ranColor;
}

public Paint getPaint() {

return paint;
}

public void setPaint() {
paint.setColor(ranColor);
paint.setTextSize(scale);
strWidth = (int) Math.ceil(paint.measureText(text));

}

public Rect getRect() {

Rect rect = new Rect((int) x, (int) (y), (int) (x + strWidth),
(int) (y + scale));

return rect;
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.tools.TagCloud
android:id="@+id/tag"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#BFBFBF">
</com.example.tools.TagCloud>

</FrameLayout>


总结:感觉自己诚意不足,屁都没做出来~~先这样吧以后有机会再改进,希望对别人有点帮助,PS:感觉3D标签云反而好做因为他的标签位置可以固定。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: