基于ViewGroup实现自动换行标签控件
来源:互联网 发布:中文域名到期查询 编辑:程序博客网 时间:2024/06/05 18:25
在上一篇博文 基于RelativeLayout实现自动换行标签控件 中,采用了继承RelativeLayout来实现,主要是对addRule()方法的使用。
我们也可以采用继承ViewGroup来达到同样的效果。
先上效果图。
实现思路:
标签View占据的是一个矩形空间,其在父视图ViewGroup中布局位置时,是通过它的四条边距离父视图的左边距和上边距来决定的。我们只要能够计算出,每个标签左边、上边、右边和下边距离父视图的距离即可。
如图所示。
下面是代码的实现,主要是重写onMeasure()方法和onLayout()方法。
首先是在实现中会用到的一些方法的介绍。
然后来实现onMeasure()方法。
最后是onLayout()方法。
完整类的代码如下。
最后附上Demo工程下载链接:
http://download.csdn.net/detail/ruancoder/9596528
我们也可以采用继承ViewGroup来达到同样的效果。
先上效果图。
实现思路:
标签View占据的是一个矩形空间,其在父视图ViewGroup中布局位置时,是通过它的四条边距离父视图的左边距和上边距来决定的。我们只要能够计算出,每个标签左边、上边、右边和下边距离父视图的距离即可。
如图所示。
下面是代码的实现,主要是重写onMeasure()方法和onLayout()方法。
首先是在实现中会用到的一些方法的介绍。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}该方法是View类中的方法,测量View的宽度和高度。
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {}该方法是View类中的方法,必须在onMeasure()方法中调用,用来设置计算出来的当前View的宽高。
protected abstract void onLayout(boolean changed, int l, int t, int r, int b);该方法是ViewGroup类中的抽象方法,当我们继承ViewGroup时必须实现该方法。参数l,t,r,b表示该ViewGroup所占据的矩形空间的left,top,right,bottom。
public void layout(int l, int t, int r, int b) {}该方法是View类中的方法,一个View对象调用该方法可以通过传入的参数left,top,right,bottom来放置它的位置,方法中的四个参数都是相对于父容器而言的。
然后来实现onMeasure()方法。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mChildRects.clear(); // 整个TagLayout的宽度为固定值 int layoutWidth = MeasureSpec.getSize(widthMeasureSpec); // 整个TagLayout的高度,初始为0, int layoutHeight = 0; // child的数量 int childCount = getChildCount(); // child view距离父视图的左边距 int childLeft = 0; // child view距离父视图的上边距 int childTop = 0; // 遍历child view for (int i = 0; i < childCount; i++) { View child = getChildAt(i); // 测量child view,获取宽度和高度 child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); // 如果child view的左边距 + 自身宽度 > 父视图宽度,需要换行 if (childLeft + childWidth > layoutWidth) { // child view的左边距重置为0 childLeft = 0; // child view的上边距 = 自身的上边距 + 自身宽度 + 垂直间距 childTop = childTop + childHeight + CHILD_VERTICAL_MARGIN; } // 将child view的Rect添加到集合中,在onLayout()方法中使用 mChildRects.add(new Rect(childLeft, childTop, childLeft + childWidth, childTop + childHeight)); // childLeft需要在已有的基础上,加上自身宽度和水平间距,进入下一轮循环使用 childLeft += (childWidth + CHILD_HORIZONTAL_MARGIN); // 当循环到最后一个child view时,已有的childTop加上child view的自身高度,就是整个父视图的高度 if (i == childCount - 1) { layoutHeight = childTop + childHeight; } } // 最后别忘了调用setMeasuredDimension setMeasuredDimension(layoutWidth, layoutHeight); }
最后是onLayout()方法。
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 遍历已经计算出来的所有的child view的位置数据,对child view进行布局 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); Rect location = mChildRects.get(i); child.layout(location.left, location.top, location.right, location.bottom); } }
完整类的代码如下。
package net.csdn.blog.ruancoder;import android.content.Context;import android.graphics.Rect;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class TagLayout extends ViewGroup { private List<Rect> mChildRects = new ArrayList<>(); private static final int CHILD_HORIZONTAL_MARGIN = 15;// 水平间距 private static final int CHILD_VERTICAL_MARGIN = 20;// 垂直间距 public TagLayout(Context context) { super(context); } public TagLayout(Context context, AttributeSet attrs) { super(context, attrs); } public TagLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setData(List<String> tags) { for (String tag : tags) { View view = LayoutInflater.from(getContext()).inflate(R.layout.tag, null); TextView textView = (TextView) view.findViewById(R.id.text); textView.setText(tag); addView(view); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mChildRects.clear(); int layoutWidth = MeasureSpec.getSize(widthMeasureSpec); int layoutHeight = 0; int childCount = getChildCount(); int childLeft = 0; int childTop = 0; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); if (childLeft + childWidth > layoutWidth) { childLeft = 0; childTop = childTop + childHeight + CHILD_VERTICAL_MARGIN; } mChildRects.add(new Rect(childLeft, childTop, childLeft + childWidth, childTop + childHeight)); childLeft += (childWidth + CHILD_HORIZONTAL_MARGIN); if (i == childCount - 1) { layoutHeight = childTop + childHeight; } } setMeasuredDimension(layoutWidth, layoutHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); Rect location = mChildRects.get(i); child.layout(location.left, location.top, location.right, location.bottom); } }}
最后附上Demo工程下载链接:
http://download.csdn.net/detail/ruancoder/9596528
0 0
- 基于ViewGroup实现自动换行标签控件
- 基于RelativeLayout实现自动换行标签控件
- 使子控件自动换行的viewgroup
- 自定义ViewGroup实现自动换行---FlowLayout
- android商品属性选择标签控件,可实现自动换行
- 基于ViewGroup自定义自动换行的布局的实现(用于备忘)
- 自定义ViewGroup实现标签换行(动态创建标签
- 自动换行的ViewGroup
- p标签实现自动换行
- 安卓自定义控件之自动换行ViewGroup
- 自定义View-自动换行的标签控件
- 仿淘宝,自定义ViewGroup实现自动换行布局
- 自定义ViewGroup实现换行
- 自定义ViewGroup-自动换行Layout
- 自定义ViewGroup-自动换行Layout
- 自动换行的ViewGroup:FlowLayout
- 自动换行的ViewGroup:FlowLayout
- Android自定义控件实现标签的显示自动换行(一)
- HTMLParser使用
- Mysql 主键自增量设置
- 进程、线程、多线程的引入
- Java多线程:线程状态
- slave 成为master 时候执行的操作notify_master /etc/keepalived/send_master.sh
- 基于ViewGroup实现自动换行标签控件
- 交叉编译openssl不修改Makefile的方法
- Electron-引导
- viewpager实现图片轮番(本地图片)
- Testing with Xcode》第四章——Running Tests and Viewing Results
- [开源学习_MeiZhi]一个itemView中多个点击事件的实现
- Android —— TextView中的MaxLines和ellipsize属性的冲突
- leetcode_c++:Longest Valid Parentheses(032)
- Windows下文件复制到Linux系统