android 流式布局简单实现
2016-12-06 18:18
435 查看
1.概述
今天看了Android自定义控件的书籍之后准备动手写个自定义控件,于是有了该篇文章。之前也看过一些大神们写的,受益匪浅。初写博客一方面是想向大神们学习,另一方面也算是自己学习的一个记录。
2.思路分析
好了废话不多扯,开始正题:流式布局肯定一个view容器也就是ViewGroup。从View的工作原理可以得知 View的绘制流程:
onMeasure —–> onLayout —–> onDraw,依次是
测量规格 —-> 确定位置 —> 绘制。 因此我们实现流式布局只需要重写前2步,即onMeasure和onLayout。
测量时需要通常需要处理测量模式为AT_MOST 对应wrap_content,这种情况需要根据子控件的宽和高来最终确认父控件的宽和高。
3.代码实现
4.运行测试
运行结果:
1.match_parent | wrap_content
![](http://img.blog.csdn.net/20161206180431293?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2g4NjcxNzkyNDQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
2.固定值(400dp)
![](http://img.blog.csdn.net/20161206180609442?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2g4NjcxNzkyNDQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
以上就实现了简单的流式布局实现。
源码下载:
[]https://github.com/ChenHaoLw/FlowLayout]
今天看了Android自定义控件的书籍之后准备动手写个自定义控件,于是有了该篇文章。之前也看过一些大神们写的,受益匪浅。初写博客一方面是想向大神们学习,另一方面也算是自己学习的一个记录。
2.思路分析
好了废话不多扯,开始正题:流式布局肯定一个view容器也就是ViewGroup。从View的工作原理可以得知 View的绘制流程:
onMeasure —–> onLayout —–> onDraw,依次是
测量规格 —-> 确定位置 —> 绘制。 因此我们实现流式布局只需要重写前2步,即onMeasure和onLayout。
测量时需要通常需要处理测量模式为AT_MOST 对应wrap_content,这种情况需要根据子控件的宽和高来最终确认父控件的宽和高。
3.代码实现
public class FlowView extends ViewGroup { public FlowView(Context context) { this(context, null); } public FlowView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measureWidth = 0; int measureHeight = 0; int childCount = getChildCount(); int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec); int measureWidthSize = MeasureSpec.getSize(widthMeasureSpec); int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec); int measureHeightSize = MeasureSpec.getSize(heightMeasureSpec); /**note: 原本写法先判断 Mode 都是Exactly的情况下不去测量 childView,从而提高效率。 * 针对onMeasure是可以的,但是onLayout中需要获取子控件width和height 时 * 还是得测量,所以此处统一测量了。 * */ //if (measureHeightMode == MeasureSpec.EXACTLY //&& measureWidthMode == MeasureSpec.EXACTLY) { // measureWidth = measureWidthSize; // measureHeight = measureHeightSize; //} else { for (int i = 0; i < childCount; i++) { View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams layoutParam = (MarginLayoutParams) child.getLayoutParams(); int cWidth = child.getMeasuredWidth() + layoutParam.leftMargin + layoutParam.rightMargin; int cHeight = child.getHeight() + layoutParam.topMargin + layoutParam.bottomMargin; /** * 思路:不换行--> width累加 height取max * 换行 --> width = 上一行累加值与当前控件width的 max值 * height = 上一行的max值 + 当前控件的height */ if (measureWidth + cWidth > measureWidthSize) { measureWidth = Math.max(measureWidth, cWidth); measureHeight += cHeight; } else { measureHeight = Math.max(measureHeight, cHeight); measureWidth += cWidth; } } setMeasuredDimension(measureWidthMode == MeasureSpec.EXACTLY ? measureWidthSize : measureWidth, measureHeightMode == MeasureSpec.EXACTLY ? measureHeightSize : measureHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); int lineWidth = 0; int lineHeight = 0; int left = 0; int top = 0; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); MarginLayoutParams layoutParam = (MarginLayoutParams) child.getLayoutParams(); int cWidth = child.getWidth() + layoutParam.leftMargin + layoutParam.rightMargin; int cHeight = child.getHeight() + layoutParam.topMargin + layoutParam.bottomMargin; //换行 if (cWidth + lineWidth > getWidth()) { if (child.getVisibility() != View.GONE) { left = 0; top = lineHeight; child.layout(left + layoutParam.leftMargin, top + layoutParam.topMargin, left + layoutParam.leftMargin + child.getMeasuredWidth(), top + layoutParam.topMargin + child.getMeasuredHeight()); left += layoutParam.leftMargin + child.getMeasuredWidth(); } lineWidth = cWidth; lineHeight += cHeight; } else { lineWidth += cWidth; lineHeight = Math.max(lineHeight, cHeight); if (child.getVisibility() != View.GONE) { child.layout(left + layoutParam.leftMargin, top + layoutParam.topMargin, left + layoutParam.leftMargin + child.getMeasuredWidth(), top + layoutParam.topMargin + child.getMeasuredHeight()); left += layoutParam.leftMargin + child.getMeasuredWidth(); } } } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
4.运行测试
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <demos.ch.com.flowlayout.FlowView android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button style="@style/btn_style" android:text="演员" /> <Button style="@style/btn_style" android:text="你还要我怎样" /> <Button style="@style/btn_style" android:text="方圆几里" /> <Button style="@style/btn_style" android:text="绅士" /> <Button style="@style/btn_style" android:text="认真的雪" /> <Button style="@style/btn_style" android:text="faded" /> <Button style="@style/btn_style" android:text="We dont talk more" /> <Button style="@style/btn_style" android:text="Jar of love" /> <Button style="@style/btn_style" android:text="可惜没如果" /> <Button style="@style/btn_style" android:text="浪费" /> <Button style="@style/btn_style" android:text="一丝不挂" /> <Button style="@style/btn_style" android:text="阴天快乐" /> <Button style="@style/btn_style" android:text="可以了" /> </demos.ch.com.flowlayout.FlowView> </LinearLayout> <---样式文件 ---> <style name="btn_style"> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> <item name="android:layout_margin">5dp</item> <item name="android:background">@color/colorBackground</item> <item name="android:textColor">#ffffff</item> <item name="android:textSize">24dp</item> </style>
运行结果:
1.match_parent | wrap_content
2.固定值(400dp)
以上就实现了简单的流式布局实现。
源码下载:
[]https://github.com/ChenHaoLw/FlowLayout]
相关文章推荐
- Android 简单实现流式布局
- Android 简单实现一个流式布局的示例
- Android 简单实现一个流式布局
- Android开发学习之卡片式布局的简单实现
- Android中常见的热门标签的流式布局的实现
- android 实现流式布局FlowLayout
- Android RecyclerView加载不同布局简单实现
- android RecyclerView 简单实现横竖布局穿插
- Android 流式布局实现方法
- Android-->FlowRadioGroup(流式布局RadioGroup, 自定义View的简单使用)
- android 自定义view实现流式布局
- Android实现热门标签的流式布局
- Android简单实现仿支付宝新年红包活动页面的动态布局效果
- Android 搜索界面提示语 根据不同字的个数实现不规则的 弹幕效果 流式布局,热门标签
- 可能是史上最简单的Android Tab布局的实现
- Android Toast带图标水平布局的简单实现
- Android中常见的热门标签的流式布局的实现
- Android自定义ViewGroup实现流式布局
- android 较高版本,页面分割线实现LinearLayoutCompat布局简单事例
- android自定义view实现流式布局(FlowLayout)和热门标签