- 浏览: 69282 次
- 性别:
- 来自: 北京
最新评论
转载请注明:http://renyuan-1991.iteye.com/blog/2232463
具体实现步骤:
1.继承ViewGroup,实现三个构造方法
2.通过generateLayoutParams给自定义的控件指定参数
3.实现onMeasure方法
a.在这个方法里面首先要做是要知道自己的大小,onMeasure方法会通过父类获取具体的模式和大小。通过getMode方法获得模式(三种模式就不详细说了),然后通过getSize方法获取具体的尺寸。
b.通过遍历子控件得到ViewGroup显示时的高度。当子控件(即标签)的宽度之和大于父控件的时候开启行并累加高度
c.setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
: width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
: height); 方法确定我们ViewGroup最终的大小
4.重写onLayout方法
a.同样的需要遍历子控件,根据宽度控制是否换行。并将每一行的空间用一个列表记录下来,并记录高度从而决定下一行需要显示的位置。
b.上面已经将标签以行为单位分别放到适当的list里面。这里就是将list里面的控件显示出来。说到底其实就是一个道理:不管通过什么样的算法,只要知道子控件正确的显示位置即可。
c.确定完位置后调用child.layout(lc, tc, rc, bc); 方法将它画出来即可。需要注意的地方是最后一行我们需要特殊处理。通过上面的判断我们实际的最后一行是永远不会大于ViewGroup的宽度的,而这一行的高度同样需要记录下来
完整的代码如下:
在界面中调用的方法
下载连接:http://download.csdn.net/detail/u010419467/8956027
希望爱好编程的小伙伴能加这个群,互相帮助,共同学习。群号: 141877583
最后附上完整项目(不需要积分)(ps:项目中的类请以博客中为准)
具体实现步骤:
1.继承ViewGroup,实现三个构造方法
2.通过generateLayoutParams给自定义的控件指定参数
3.实现onMeasure方法
a.在这个方法里面首先要做是要知道自己的大小,onMeasure方法会通过父类获取具体的模式和大小。通过getMode方法获得模式(三种模式就不详细说了),然后通过getSize方法获取具体的尺寸。
b.通过遍历子控件得到ViewGroup显示时的高度。当子控件(即标签)的宽度之和大于父控件的时候开启行并累加高度
c.setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
: width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
: height); 方法确定我们ViewGroup最终的大小
4.重写onLayout方法
a.同样的需要遍历子控件,根据宽度控制是否换行。并将每一行的空间用一个列表记录下来,并记录高度从而决定下一行需要显示的位置。
b.上面已经将标签以行为单位分别放到适当的list里面。这里就是将list里面的控件显示出来。说到底其实就是一个道理:不管通过什么样的算法,只要知道子控件正确的显示位置即可。
c.确定完位置后调用child.layout(lc, tc, rc, bc); 方法将它画出来即可。需要注意的地方是最后一行我们需要特殊处理。通过上面的判断我们实际的最后一行是永远不会大于ViewGroup的宽度的,而这一行的高度同样需要记录下来
完整的代码如下:
package com.xiaoying.widget; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.xiaoying.common.util.Utils; import com.xiaoying.cuishou.R; /** * @author Roy * @version V1.0 date:2017/11/30 下午6:07 */ public class MyFlowLayout extends ViewGroup { private MarkClickListener markClickListener; public MyFlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MyFlowLayout(Context context, AttributeSet attrs) { super(context, attrs); } public MyFlowLayout(Context context) { super(context); } public void setData(String[] data){ createChild(data,10, 15, 10, 15, 10, 0, 12, 12 , 0); } public void setData(String[] data, int textSize,int pl,int pt,int pr,int pb,int ml,int mt,int mr,int mb){ createChild(data,textSize, pl, pt, pr, pb, ml, mt, mr, mb); } public void setData(List<String> data){ String[] mydata = null; if(data!=null){ int length = data.size(); mydata = new String[length]; for(int i = 0 ; i<length;i++){ mydata[i] = data.get(i); } } setData(mydata); } public void setData(List<String> data,int textSize,int pl,int pt,int pr,int pb,int ml,int mt,int mr,int mb){ String[] mydata = null; if(data!=null){ int length = data.size(); mydata = new String[length]; for(int i = 0 ; i<length;i++){ mydata[i] = data.get(i); } } setData(mydata, textSize,pl, pt, pr, pb, ml, mt, mr, mb); } public void setOnClickListener(MarkClickListener markClickListener){ this.markClickListener = markClickListener; } public interface MarkClickListener{ void onRemarkClick(String str); } private void createChild(String[] data,int textSize,int pl,int pt,int pr,int pb,int ml,int mt,int mr,int mb){ int size = data.length; for(int i = 0;i<size;i++){ String text = data[i]; TextView btn = new TextView(getContext()); btn.setClickable(true); btn.setGravity(Gravity.CENTER); btn.setText(text); btn.setTag(text); btn.setTextSize(textSize); btn.setPadding(Utils.dip2px(getContext(), pl), Utils.dip2px(getContext(), pt), Utils.dip2px(getContext(), pr), Utils.dip2px(getContext(), pb)); btn.setTextColor(0xff2b3041); /*btn.setTextColor(getResources().getColorStateList(R.color.selector_button_tc));*/ btn.setBackgroundResource(R.drawable.mark_green); MarginLayoutParams params = new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT); params.setMargins(Utils.dip2px(getContext(), ml), Utils.dip2px(getContext(), mt), Utils.dip2px(getContext(), mr), Utils.dip2px(getContext(), mb)); btn.setLayoutParams(params); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { markClickListener.onRemarkClick(((TextView)v).getText().toString()); } }); this.addView(btn); } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int childCount = getChildCount(); int lineWidth = 0; int lineHeight = 0; int width = 0;//warpcontet是需要记录的宽度 int height = 0; for(int i = 0 ; i< childCount;i++){ View child = getChildAt(i); // 测量每一个child的宽和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin; int childHeight = child.getMeasuredHeight()+lp.topMargin+lp.bottomMargin; if(lineWidth+childWidth>widthSize){ //这种情况就是排除单个标签很长的情况 width = Math.max(lineWidth, childWidth); //开启新行 lineWidth = childWidth; //记录总行高 height += lineHeight; //因为开了新行,所以这行的高度要记录一下 lineHeight = childHeight; }else{ lineWidth += childWidth; //记录行高 lineHeight = Math.max(lineHeight, childHeight); } // 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较 if (i == childCount - 1) { //宽度 width = Math.max(width, lineWidth); height += lineHeight; } } setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? widthSize : width, (heightMode == MeasureSpec.EXACTLY) ? heightSize : height); } /** * 存储所有的View,按行记录 */ private List<List<View>> mAllViews = new ArrayList<List<View>>(); /** * 记录每一行的最大高度 */ private List<Integer> mLineHeight = new ArrayList<Integer>(); //onLayout中完成对所有childView的位置以及大小的指定 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //清空子控件列表 mAllViews.clear(); //清空高度记录列表 mLineHeight.clear(); //得到当前控件的宽度(在onmeasure方法中已经测量出来了) int width = getWidth(); int childCount = getChildCount(); // 存储每一行所有的childView List<View> lineViews = new ArrayList<View>(); //行高 int lineWidth = 0; //总行高 int lineHeight = 0; for(int i = 0 ; i<childCount;i++){ View child = getChildAt(i); //得到属性参数 MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); // 如果需要换行 if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width) { mLineHeight.add(lineHeight); // 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView mAllViews.add(lineViews); // 重置行宽 lineWidth = 0; lineHeight = 0; lineViews = new ArrayList<View>(); } /** * 如果不需要换行,则累加 */ lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin); lineViews.add(child); } // 记录最后一行 (因为最后一行肯定大于父布局的宽度,所以添加最后一行是必要的) mLineHeight.add(lineHeight); mAllViews.add(lineViews); int left = 0; int top = 0; int lineNums = mAllViews.size(); for(int i = 0;i<lineNums;i++){ // 每一行的所有的views lineViews = mAllViews.get(i); // 当前行的最大高度 lineHeight = mLineHeight.get(i); for(int j = 0 ;j < lineViews.size() ; j++){ View lineChild = lineViews.get(j); if(lineChild.getVisibility() == View.GONE){ continue; } MarginLayoutParams lp = (MarginLayoutParams) lineChild.getLayoutParams(); //开始画标签了。左边和上边的距离是要根据累计的数确定的。 int lc = left + lp.leftMargin; int tc = top+lp.topMargin; int rc = lc+lineChild.getMeasuredWidth(); int bc = tc+lineChild.getMeasuredHeight(); lineChild.layout(lc, tc, rc, bc); left += lineChild.getMeasuredWidth() + lp.rightMargin + lp.leftMargin; } //将left归零 left = 0; top += lineHeight; } } }
在界面中调用的方法
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyFlowLayout myview = (MyFlowLayout) findViewById(R.id.myview); String[] myData = {"one","two","dkfjdkf","kdfkdfj","jdkfdfkjdkfdkfkdkdfj","kdjkfdjkjkjskkjkd"}; myview.setData(myData, this, 15, 10, 10, 10, 10, 10, 10, 10, 10); }
下载连接:http://download.csdn.net/detail/u010419467/8956027
希望爱好编程的小伙伴能加这个群,互相帮助,共同学习。群号: 141877583
最后附上完整项目(不需要积分)(ps:项目中的类请以博客中为准)
- FlowLayout_mark.zip (1.9 MB)
- 下载次数: 6
发表评论
-
通过Url打开app页面并传递参数
2017-12-09 17:56 3916转载请注明出处:http:// ... -
Retrofit+RxJava搭建网络请求和数据解析框架
2017-06-29 18:20 0好久没写博客了,实话说,这一年相比往年可以说没什么进步,工作四 ... -
viewpager指示器
2016-11-08 16:04 0viewpager指示器 实现该需求的几种方法的基本原理和缺点 ... -
Android Studio模板,省去界面重复部分的开发
2016-07-06 16:05 0Android Studio模板,省去界面重复部分的开发 -
android studio 运行java代码
2016-06-21 17:50 2371转载请注明出处: http://renyuan-1991.it ... -
自定义组合控件的总结
2016-06-21 16:27 1490自定义组合控件的总结 转载请注明出处:http://renyu ... -
只显示年月的DatePicker
2016-06-12 17:30 3295转载请注明出处:http://renyuan-1991.ite ... -
Android的约束布局ConstaintLayout
2016-06-24 15:05 9842ConstaintLayout的初次使用总结 转载请注明出处 ... -
Android遮罩层引导页的实现
2016-06-03 16:28 0实现遮罩层引导页可以通过以下几种方式,本文主要记录张洪洋Hig ... -
手势密码
2016-05-24 14:52 0我们公司做的是理财产品,所以手势密码这个东西少不了,在写手势密 ... -
线性布局的权重weight使用详解
2016-01-20 14:29 2355对线性布局中权重的理解 转载请注明出处:http://ren ... -
setBackgroundResource导致Padding失效,settextsize
2016-01-18 19:50 1531通过setBackground设置9 patc ... -
NestedScrolling的使用及ScrollView的惯性滑动
2015-12-08 18:14 21444NestedScrolling的使用及ScrollView的惯 ... -
android-async-http使用和取消请求
2015-10-15 12:06 4936android-async-http使用总结 下载最新的包可以 ... -
触摸屏幕取消键盘
2015-10-13 18:09 1542当点击文本框和发送按钮的时候不需要取消键盘,点击屏幕其他按钮或 ... -
四种方式实现ListView中的倒计时一()
2015-09-29 12:33 0的奋斗奋斗奋斗 -
SQLite详解
2015-10-10 15:07 1056概述 SQLite是D.Richar ... -
android 的屏幕适配问题,dp与px的换算
2015-08-08 19:11 1712在进入正题之前先了解 ... -
Android第三方框架之xListView的使用方法
2014-11-09 19:18 5099==最近向用xListView实现刷新效果,在网上没有找到相关 ...
相关推荐
自定义ViewGroup实现瀑布流,图片加载,图片回收,跟改列数,滑动加载。
可以自动换行,如果一行放不下,可换行,还可以支持滚动布局。
今天看到很多app都有Title自动隐藏功能,1.这是一个Gradle工程,Gradle的版本是2.10,项目的Compile sdk Version是 23 , Build ...Android自定义ViewGroup实现Title自动隐藏功能源代码分享,Android开发者必看示例。
自定义ViewGroup,根据手势滑动界面
Android 标签,可以自动换行的ViewGroup
NULL 博文链接:https://345757144.iteye.com/blog/1968377
前面在学习鸿洋大神的一些自定义的View文章,看到了自定义ViewGroup实现浮动标签,初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup。目前实现的可以动态添加标签、可点击。效果图如下:...
自定义ViewGroup学习 最简单的模式,显示一个TextView到自定义ViewGroup中
android自定义viewgroup实现等分格子布局
自定义ViewGroup实现流式布局demo
自定义ViewGroup+Adapter
自定义ViewGroup实现流式布局
该资源包含了一个利用自定义的viewgroup实现的slidingmenu,简单易懂。
只需要传入一个数组或一个list就能创建出能换行的标签。其中标签的样式及点击时的效果可以根据自己的需求更改
自定义VIewGroup组合控件,包括事件的处理,可以运行,值得学习
仿照X宝的商品详情页, 拉到页面底部时有一个粘滞效果,如果用户继续向上拉的话就进入下一页
自定义Viewgroup,其中包括三个listview,但拖拽中间listview的上部,3个listview一起运动。
主要介绍了Android自定义ViewGroup实现FlowLayout标签流容器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
自定义ViewGroup进一步学习,显示两个TextView到自定义控件中,对两个TextView进行布局