Android -- 自定义ViewGroup实现FlowLayout效果
1,在开发的时候,常在我们的需求中会有这种效果,添加一个商品的一些热门标签,效果图如下:
2,从上面效果可以看得出来,这是一个自定义的ViewGroup,然后实现换行效果,让我们一起来实现一下
- 自定义属性
从上面的效果来看,我们需要动态的设置每个lable的宽度和高度,所以我们编写如下的自定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlowLayout">
<!-- 标签之间的间距-->
<attr name="lineSpace" format="dimension"/>
<!-- 每一行之间的间距-->
<attr name="rowSpace" format="dimension"/>
</declare-styleable>
</resources>
在布局文件中使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:flowlayout="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.qianmo.flowlayout.FlowLayout
android:id="@+id/flowLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dip"
flowlayout:lineSpace="20dip"
flowlayout:rowSpace="10dip"/>
</LinearLayout>
在类中获取自定义属性
public class FlowLayout extends ViewGroup {
private static String TAG = "FlowLayout";
//自定义属性
private int LINE_SPACE;
private int ROW_SPACE;
//放置标签的集合
private List<String> lables;
private List<String> lableSelects;
public FlowLayout(Context context) {
this(context, null);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
LINE_SPACE = a.getDimensionPixelSize(R.styleable.FlowLayout_lineSpace, 10);
ROW_SPACE = a.getDimensionPixelSize(R.styleable.FlowLayout_rowSpace, 10);
a.recycle();
}
}
- 初始化数据数据源
向FlowLayout类中添加数据
/**
* 添加标签
*
* @param lables 标签集合
* @param isAdd 是否添加
*/
public void setLables(List<String> lables, boolean isAdd) {
if (this.lables == null) {
this.lables = new ArrayList<>();
}
if (this.lableSelects == null) {
this.lableSelects = new ArrayList<>();
}
if (isAdd) {
this.lables.addAll(lables);
} else {
this.lables.clear();
this.lables = lables;
}
if (lables != null && lables.size() > 0) {
for (final String lable : lables) {
final TextView tv = new TextView(getContext());
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
tv.setText(lable);
tv.setTextSize(20);
tv.setBackgroundResource(R.drawable.shape_item_lable_bg);
tv.setTextColor(Color.BLACK);
tv.setGravity(Gravity.CENTER);
tv.setPadding(12, 5, 12, 5); //判断是否选中
if (lableSelects.contains(lable)) {
tv.setSelected(true);
tv.setTextColor(getResources().getColor(R.color.tv_blue));
} else {
tv.setSelected(false);
tv.setTextColor(getResources().getColor(R.color.tv_gray));
} //点击之后选中标签
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tv.setSelected(tv.isSelected() ? false : true);
if (tv.isSelected()) {
tv.setTextColor(getResources().getColor(R.color.tv_blue));
lableSelects.add(lable);
} else {
tv.setTextColor(getResources().getColor(R.color.tv_gray));
lableSelects.remove(lable);
}
}
}); //添加到容器中
addView(tv);
}
}
}
下面的代码是textview的背景选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<!--选中效果-->
<item android:state_selected="true">
<shape >
<solid android:color="#ffffff" />
<stroke android:color="@color/tv_blue"
android:width="2px"/>
<corners android:radius="10000dip"/>
</shape>
</item>
<!--默认效果-->
<item>
<shape >
<solid android:color="#ffffff" />
<stroke android:color="@color/divider_gray"
android:width="2px"/>
<corners android:radius="10000dip"/>
</shape>
</item>
</selector>
- 重写onMeasure方法
本布局在宽度上是使用的建议的宽度(填充父窗体或者具体的size),如果需要wrap_content的效果,还需要重新计算,当然这种需求是非常少见的,所以直接用建议宽度即可;布局的高度就得看其中的标签需要占据多少行(row ),那么高度就为row * 单个标签的高度+(row -1) * 行距,代码如下:
/**
* 通过测量子控件高度,来设置自身控件的高度
* 主要是计算
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//测量所有子view的宽高
measureChildren(widthMeasureSpec, heightMeasureSpec); //获取view的宽高测量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec); //这里的宽度建议使用match_parent或者具体值,当然当使用wrap_content的时候没有重写的话也是match_parent所以这里的宽度就直接使用测量的宽度
int width = widthSize; int height;
//判断宽度
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
int row = 1;
int widthSpace = width; //宽度剩余空间
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
//获取标签宽度
int childW = view.getMeasuredWidth();
//判断剩余宽度是否大于此标签宽度
if (widthSpace >= childW) {
widthSpace -= childW;
} else {
row++;
widthSpace = width - childW;
}
//减去两边间距
widthSpace -= LINE_SPACE;
}
//获取子控件的高度
int childH = getChildAt(0).getMeasuredHeight();
//测算最终所需要的高度
height = (childH * row) + (row - 1) * ROW_SPACE;
} //保存测量高度
setMeasuredDimension(width, height);
}
- 重写OnLayout方法
onLayout(boolean changed, int l, int t, int r, int b)方法是一个抽象方法,自定义ViewGroup时必须实现它,用于给布局中的子控件分配位置,其中的参数l,t,r,b分别代表本ViewGroup的可用空间(除去margin和padding后的剩余空间)的左、上、右、下的坐标(相对于自身),相当于一个约束,如果子控件摆放的位置超过这个范围,超出的部分将不可见。
/**
* 摆放子view
*
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int row = 0;
int right = 0;
int bottom = 0;
for (int i = 0; i < getChildCount(); i++) {
View chileView = getChildAt(i);
int childW = chileView.getMeasuredWidth();
int childH = chileView.getMeasuredHeight();
right += childW;
bottom = (childH + ROW_SPACE) * row + childH;
if (right > (r - LINE_SPACE)) {
row++;
right = childW;
bottom = (childH + ROW_SPACE) * row + childH;
}
chileView.layout(right - childW, bottom - childH, right, bottom);
right += LINE_SPACE;
}
}
看一下实现的效果图
ok,这样我们就全部实现了,需要源码的同学可以在这里去下载
Android -- 自定义ViewGroup实现FlowLayout效果的更多相关文章
- android自定义viewgroup之我也玩瀑布流
先看效果图吧, 继上一篇<android自定义viewgroup实现等分格子布局>中实现的布局效果,这里稍微有些区别,每个格子的高度不规则,就是传说的瀑布流布局,一般实现这种效果,要么用第 ...
- Android 自定义ViewGroup 实战篇 -> 实现FlowLayout
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38352503 ,本文出自[张鸿洋的博客] 1.概述 上一篇已经基本给大家介绍了如 ...
- android自定义viewgroup实现等分格子布局
先上效果图: 实现这样的效果: 一般的思路就是,直接写布局文件,用LinearLayout 嵌套多层子LinearLayout,然后根据权重layout_weight可以达到上面的效果 还有就是利用g ...
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这里我简单说明一下用自定义ViewGroup来实现. 实现方法:我们自定义一个ViewGroup实现左右滑动, ...
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu[转]
http://blog.csdn.net/jj120522/article/details/8095852 示意图就不展示了,和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉,在这 ...
- android 自定义view之侧滑效果
效果图: 看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来.但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的. 知识点: 1.Vi ...
- Android自定义ViewGroup(四、打造自己的布局容器)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51500304 本文出自:[openXu的博客] 目录: 简单实现水平排列效果 自定义Layo ...
- android自定义viewgroup初步之一----抽屉菜单
转载请注明出处 http://blog.csdn.net/wingichoy/article/details/47832151 几天前在慕课网上看到鸿洋老师的 自定义卫星菜单,感觉很有意思,于是看完视 ...
- Android 自定义ViewGroup手把手教你实现ArcMenu
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37567907 逛eoe发现这样的UI效果,感觉很不错,后来知道github上有这 ...
随机推荐
- 用github搭建网站
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- python之gunicorn的配置
https://www.cnblogs.com/cwp-bg/p/8780204.html python常见的web部署搭配nginx+gunicorn,下面记录一下gunicorn的配置使用. 安装 ...
- delphi中的 IntToHex()
Delphi 自带函数 IntToHex 功能说明:该函数用于将“十进制”转换成“十六进制”.该函数有二个参数.第一个参数为要转换的十进制数据,第二个参数是指定使用多少位来显示十六进制数据. 参考实例 ...
- LeetCode 897 Increasing Order Search Tree 解题报告
题目要求 Given a tree, rearrange the tree in in-order so that the leftmost node in the tree is now the r ...
- Asp.net Mvc post表单提交多个实体模型
上一遍说道用Tuple实现Asp.net Mvc action返回多个模型实体给view,此篇发过来,实现view表单提交多个实体模型到action. 1.view代码: @{ Layout = nu ...
- 【托业】【新托业TOEIC新题型真题】学习笔记10-题库七-P7
1.to request a review of information 要求审查资料 2.inform of 将…告知(某人); 3.flammable [ˈflæməbl]adj.易燃的,可燃的; ...
- Github上Laravel开源排行榜Star数前30名
Github上Laravel开源排行榜前30名,罗列所有 Laravel 开源扩展包,含 Github Star 数量,下载数量和项目简介.默认排序是按Star数量从多到少来排 1.cachethq/ ...
- Codeforces Round #FF (Div. 2) 题解
比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit p ...
- linux相关介绍
1.linux的简介 (1)linux是一个开源.免费的操作系统,其稳定性.安全性.处理多并发(基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU) 的操作系统.linux是一个Unix类 ...
- 20165236 2017-2018-2 《Java程序设计》结对编程练习_四则运算
20165236 2017-2018-2 <Java程序设计>结对编程练习_四则运算 结对小组:叶佺.郭金涛 一.需求分析: 1.能随机生成n道四则运算题目,n由使用者输入: 2.支持多种 ...