android 仿qq 功能,Android仿QQ个性标签功能

QQ效果:

format,png

最终效果:

format,png

分析从效果大致可以看出两个规律:字体的矩形面积越来越小

字体大小越来越小很像废话吧,不是的。除了字体,我们还能看到文字有竖向排行有横向排列,而且没有规律。

2.1 问题分解

假设我们只有一个标签文字,可以选择自定义View(当然可以选择自定义ViewGroup),然后随机标签文字的left和top,文字大小从30sp开始,然后在onDraw里面绘制矩形,在矩形里面绘制文字。

绘制第一个标签文字之后,我们想绘制第二个标签文字,如果我们还在当前的View里面去随机一个Rect,可能会和第一个标签重合,那怎么办?我们想到了裁剪,看下图:

format,png

沿着标签我们可以将View切成Rect①、Rect②、Rect③、Rect④,这个时候我们分别将四块矩形看成新的View去绘制一个标签文字。这样大问题就化解成了许许多多的小问题。

2.2 如果Rect宽大于高

1. 如果标签文字的高度大于Rect的高度,我们可以递减标签文字的TextSize,一直到标签文字的高度小于Rect的高度,我们直接从Rect的Left开始绘制标签就可以,看图:format,png第一个标签绘制完成之后,继续在这个标签的右边重复绘制第一个标签大小的标签,一直到Rect剩余的空间不足以绘制一个当前的大小的标签。2. 如果文字的宽度大于Rect的宽度,同样的我们也递减标签文字的TextSize,一直到标签文字的宽度小于Rect的宽度,我们直接从Rect的Top开始绘制标签就可以,看图:format,png第一个标签绘制完成之后,继续在这个标签的下边重复绘制第一个标签大小的标签,一直到Rect剩余的空间不足以绘制一个当前的大小的标签。3. 如果以上都不满足,说明标签的宽高都远小于Rect的宽高,那就变成了我们最开始的大问题,随机标签文字的left和top,再切四个Rect出来,重复以上步骤。

2.3 如果Rect高大于宽

Rect高大于宽,标签适合竖向排列,竖向排列考虑起来比较简单,不需要随机一个位置开始竖向,就从Rect的Left开始排列,看起来整齐,看图:format,png

第一个标签绘制完成之后,继续在标签的右边重复绘制第一个标签大小的标签,一直到Rect右边剩余的空间不足以绘制一个当前的大小的标签,然后将剩下的空间切成Rect①和Rect②,重复以上步骤。

核心代码

3.1 定义Tag对象public class Tag {private String name;private int left;private int top;private int right;private int bottom;private int textsize;// 省略构造函数和setter getter}

这个class的作用类似记录器,记录每一个Tag的位置和文字大小信息。

3.2 核心函数public void computeSingleRect(List tags, int textSize, int pLeft, int pTop, int pRight, int pBottom) {if (tags == null || tags.size() == 0 || textSize < MIN_TEXT_SIZE || pBottom == 0 || pRight == 0 || pLeft >= pRight || pTop >= pBottom) {return;}int cLeft = 0;int cTop = 0;int cRight = 0;int cBottom = 0;int textWidth = 0;int textHeight = 0;int size = tags.size();int index = (int) (Math.random() * (size - 1));String name = tags.get(index);//计算当前rect的宽高int rectWidth = pRight - pLeft;int rectHeight = pBottom - pTop;if (rectWidth > rectHeight) {//父布局长大于高,横向布局合适paint.setTextSize(textSize);textWidth = (int) paint.measureText(name);textHeight = (int) (paint.getFontMetrics().bottom - paint.getFontMetrics().top);if (textHeight > rectHeight) {//记录之前的textsizeint beforeTextSize = textSize;while (textHeight > rectHeight) {textSize--;paint.setTextSize(textSize);textHeight = (int) (paint.getFontMetrics().bottom - paint.getFontMetrics().top);}textWidth = (int) paint.measureText(name);while (textWidth > rectWidth) {textSize--;paint.setTextSize(textSize);textWidth = (int) paint.measureText(name);}if(textSize < MIN_TEXT_SIZE){return;}textHeight = (int) (paint.getFontMetrics().bottom - paint.getFontMetrics().top);cLeft = pLeft;cTop = pTop;cRight = textWidth + pLeft;cBottom = textHeight + pTop;showTags.add(new Tag(name, textSize, cLeft, cTop, cRight, cBottom));textWidth = (int) paint.measureText(name);if (pRight - cRight > textWidth) {//右computeSingleRect(tags, beforeTextSize, cRight, pTop, pRight, pBottom);} else {//右computeSingleRect(tags, --textSize, cRight, pTop, pRight, pBottom);}} else {if (textWidth >= rectWidth) {while (textWidth > rectWidth) {textSize--;paint.setTextSize(textSize);textWidth = (int) paint.measureText(name);}if(textSize < MIN_TEXT_SIZE){return;}textHeight = (int) (paint.getFontMetrics().bottom - paint.getFontMetrics().top);cLeft = pLeft;cTop = pTop;cRight = pRight;cBottom = cTop + textHeight;showTags.add(new Tag(name, textSize, cLeft, cTop, cRight, cBottom));//下textSize += 4;computeSingleRect(tags, textSize, cLeft, cBottom, cRight, pBottom);} else {cLeft = (int) (Math.random() * (rectWidth / 3)) + pLeft; // 除以3是为了尽快找到合适的位置while (cLeft + textWidth > pRight) {cLeft--;}cTop = (int) (Math.random() * (rectHeight / 2)) + pTop;while (cTop + textHeight > pBottom) {cTop--;}cRight = cLeft + textWidth;cBottom = cTop + textHeight;showTags.add(new Tag(name, textSize, cLeft, cTop, cRight, cBottom));//左computeSingleRect(tags, --textSize, pLeft, pTop, cLeft, cBottom);//上computeSingleRect(tags, --textSize, cLeft, pTop, pRight, cTop);//右computeSingleRect(tags, --textSize, cRight, cTop, pRight, pBottom);//下computeSingleRect(tags, --textSize, pLeft, cBottom, cRight, pBottom);}}} else {//父布局高大于长,纵向布局合适int beforeTextSize = textSize;paint.setTextSize(textSize);textHeight = (int) (paint.getFontMetrics().bottom - paint.getFontMetrics().top);while (textHeight * name.length() > rectHeight) {textSize--;paint.setTextSize(textSize);textHeight = (int) (paint.getFontMetrics().bottom - paint.getFontMetrics().top);}if(textSize < MIN_TEXT_SIZE){return;}textWidth = (int) (paint.measureText(name) / name.length());int length = name.length();if (pLeft + textWidth > pRight) {//右 右边空间不足computeSingleRect(tags, --textSize, pLeft, pTop, pRight, pBottom);return;}for (int i = 0; i < length; i++) {cLeft = pLeft;cTop = pTop + i * textHeight;cRight = cLeft + textWidth;cBottom = cTop + textHeight;showTags.add(new Tag(String.valueOf(name.charAt(i)), textSize, cLeft, cTop, cRight, cBottom));}if (pRight - cRight > textWidth) {//右computeSingleRect(tags, beforeTextSize, cRight, pTop, pRight, cBottom);//下computeSingleRect(tags, --textSize, pLeft, cBottom, pRight, pBottom);} else {//右computeSingleRect(tags, --textSize, cRight, pTop, pRight, cBottom);//下computeSingleRect(tags, --textSize, pLeft, cBottom, pRight, pBottom);}}}很清楚的看到,是一个递归函数,一开始就是递归的结束条件。注意里面的切割Rect的方法,pLeft、pTop、pRight、pBottom代表父Rect的边界,cLeft、cTop、cRight、cBottom代表Tag的边界。里面有一个很巧妙的记录进入条件时候的TextSize,目的是让下一次递归还继续进入这个条件下,也就做到了重复绘制相同大小的Tag的目的。但是在textWidth >= rectWidth这个条件下记录TextSize却容易造成最后一个Tag绘制不出来,导致留白区域大,有一点瑕疵,但是整体目的达到了。Github地址:https://github.com/rjpacket/QQTagCloudView到这里就结束啦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值