Android-自定义控件基础-流式布局
2018-03-28 08:45
435 查看
什么是流式布局?其实我们在平时遇到过,只是有可能叫不出它的名字。
如图:
如上图,就是一个流式布局的样式。
&esmp;这里,将记录一下怎么实现这个功能。其实实现这个功能的方法,就是自定义ViewGroup。
自定义ViewGroup的时候,要注意两点:
1.子View和父View大小的测量。
2.子View的在父View里面怎么摆放。
想要解决上面的两个问题,就得重写两个方法,分别是:onMeasure方法,在这个方法我们通常来测量子View和父View的大小;onLayout方法,在这个方法里面,我们通常来决定子View在父View的摆放。
在自定义ViewGroup的时候,一定要定义ViewGroup的LayoutParams。所以还要重写generateLayoutParams方法。
如图:
如上图,就是一个流式布局的样式。
&esmp;这里,将记录一下怎么实现这个功能。其实实现这个功能的方法,就是自定义ViewGroup。
自定义ViewGroup的时候,要注意两点:
1.子View和父View大小的测量。
2.子View的在父View里面怎么摆放。
想要解决上面的两个问题,就得重写两个方法,分别是:onMeasure方法,在这个方法我们通常来测量子View和父View的大小;onLayout方法,在这个方法里面,我们通常来决定子View在父View的摆放。
1.重写onMeasure方法
//测量父控件和子控件的大小 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int width = getMeasuredWidth(); int height = 0; int lineWidth = 0; int lineHeight = 0; int childWidth = 0; int childHeight = 0; for (int i = 0, n = getChildCount(); i < n; i++) { View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams(); Log.i("main", "width = " + child.getMeasuredWidth() + " height = " + child.getMeasuredHeight() + " leftMargin = " + marginLayoutParams.leftMargin + " rightMargin = " + marginLayoutParams.rightMargin); childWidth = child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin; childHeight = child.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin; //换行 if (lineWidth + childWidth > width) { lineWidth = childWidth; height += lineHeight; } else { lineWidth += childWidth; lineHeight = Math.max(childHeight, lineHeight); } if (i == n - 1) { height += lineHeight; } } setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height); }
2.重写onLayou方法
private List<List<View>> mAllViews = new ArrayList<List<View>>(); private List<Integer> mLineHeights = new ArrayList<Integer>(); @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllViews.clear(); mLineHeights.clear(); int width = getWidth(); // 父布局的宽度 List<View> lineViews = new ArrayList<View>(); int childWidth = 0; int childHeight = 0; int lineWidth = 0; int lineHeight = 0; Log.i("main", "childCount = " + getChildCount() + " width = " + width); for (int i = 0, n = getChildCount(); i < n; i++) { View child = getChildAt(i); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams(); childWidth = child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin; childHeight = child.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin; if (childWidth + lineWidth > width) { mAllViews.add(lineViews); mLineHeights.add(lineHeight); lineViews = new ArrayList<View>(); lineWidth = 0; lineHeight = childHeight; } lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeight); lineViews.add(child); } mAllViews.add(lineViews); mLineHeights.add(lineHeight); int top = 0; int left = 0; Log.i("main", "n = " + mAllViews.size() + " m = " + lineViews.size()); for(int i = 0, n = mAllViews.size(); i < n; i++) { lineViews = mAllViews.get(i); for(int j = 0, m = lineViews.size(); j < m; j++) { View child = lineViews.get(j); if(child.getVisibility() == View.GONE) { continue; } MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams(); int lc = left + marginLayoutParams.leftMargin; int tc = top + marginLayoutParams.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); Log.i("main", "lc = " + lc + " tc = " + tc + " rc = " + rc + " bc = " + bc); 4000 child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin; } left = 0; top += mLineHeights.get(i); } }
在自定义ViewGroup的时候,一定要定义ViewGroup的LayoutParams。所以还要重写generateLayoutParams方法。
@Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); }
相关文章推荐
- Android自定义控件--流式布局(FlowLayout)
- Android基础之自定义控件、布局以及ListView控件
- Android自定义控件--流式布局(FlowLayout)--自动适配
- Android自定义控件之流式布局
- Android自定义控件 - 标签流式布局
- Android基础入门教程——2.2.3 TableLayout(表格布局)
- 可动态布局的Android抽屉之基础
- Android自定义控件实现及其布局
- Android中常见的热门标签的流式布局的实现
- Android笔记:热门标签,流式布局
- Android自定义控件图片+文字布局
- Android开发中 流式布局
- android布局的基础学习
- Android自定义控件系列 十:利用添加自定义布局来搞定触摸事件的分发,解决组合界面中特定控件响应特定方向的事件
- Android基础_页面布局_TableLayout(表格布局)
- android自定义控件基础
- Kotlin入门(19)Android的基础布局
- Android 自定义控件-自动换行的流线性布局-DragFlowLayout
- 【Android基础入门〖1〗】UI布局
- Android基础————UI布局之UI美化分解详解