«

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

时间:2024-3-2 19:15     作者:韩俊     分类: Android


标签云效果很酷,比如最出名的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标签云反而好做因为他的标签位置可以固定。。


标签: android

热门推荐