温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何在Android中实现一个流式布局

发布时间:2021-04-08 17:50:53 来源:亿速云 阅读:205 作者:Leah 栏目:移动开发

本篇文章为大家展示了如何在Android中实现一个流式布局,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

现下流式布局:

  1. onMeasure

  2. onLayout

通过以上两个方法我们就可以完成对流式布局的基本操作:

onMeasure

  @Override   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {     super.onMeasure(widthMeasureSpec, heightMeasureSpec);     // 获得它的父容器为它设置的测量模式和大小     int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);     int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);     int modeWidth = MeasureSpec.getMode(widthMeasureSpec);     int modeHeight = MeasureSpec.getMode(heightMeasureSpec);     // 如果是warp_content情况下,记录宽和高     int width = 0;     int height = 0;     //记录每一行的宽度,width不断取最大宽度     int lineWidth = 0;     //记录每一行的宽度,不断累加每行最大高度获取height     int lineHeight = 0;     //获取子View的数量     int childCount = getChildCount();     //遍历每个子元素     for (int i = 0; i < childCount; i++) {       //获取每一个子View       View childView = getChildAt(i);       //测量每一个子View的宽和高       measureChild(childView,widthMeasureSpec,heightMeasureSpec);       //得到子View的lp       LayoutParam lp = (LayoutParam) childView.getLayoutParams();       //当前子View实际占据的宽度       int childWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;       //当前子View实际占据的高度       int childHeight = childView.getMeasuredHeight() + lp.bottomMargin + lp.topMargin;       //如果加入当前childView,超出最大宽度,则得到目前最大宽度给width,类加height 然后开启新行       if (lineWidth + childWidth > sizeWidth) {         // 取最大的宽度         width = Math.max(lineWidth, childWidth);         //重新开启新行,重新计算         lineWidth = childWidth;         //叠加当前高度         height += childHeight;         //记录下一行高度         lineHeight = childHeight;       }else {         // 累加值lineWidth,lineHeight取最大高度         lineWidth += childWidth;         lineHeight = Math.max(lineHeight,childHeight);       }       // 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较       if (i == childCount - 1) {         width = Math.max(width,lineWidth);         height += lineHeight;       }     }     setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY?sizeWidth:width,modeHeight == MeasureSpec.EXACTLY?sizeHeight:height);   }

在onMeasure方法中负责设置子控件的测量模式和大小 根据所有子控件设置自己的宽和高,一旦宽度超出最大宽度便进行换行处理。高度不断累加从而获取最终高度。

onLayout

  //存储所有的View,按行记录   private List<List<View>> mAllViews = new ArrayList<>();   //记录每一行的最大高度   private List<Integer> mLineHeight = new ArrayList<>();   @Override   protected void onLayout(boolean changed, int l, int t, int r, int b) {     mAllViews.clear();     mLineHeight.clear();     int lineWidth = 0;     int lineHeight = 0;     int width = getWidth();     int childCount = getChildCount();     // 存储每一行所有的childView     List<View> lineViews = new ArrayList<>();     for (int i = 0; i < childCount; i++) {       View childView = getChildAt(i);       LayoutParam lp = (LayoutParam) childView.getLayoutParams();       int childWidth = childView.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;       int childHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;       if (lineWidth + childWidth > width) {         // 记录这一行所有的View以及最大高度         mLineHeight.add(lineHeight);         // 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView         mAllViews.add(lineViews);         lineWidth = 0;         lineViews = new ArrayList<>();       }       //如果不需要换行,则累加       lineWidth += childWidth;       lineHeight = Math.max(lineHeight,childHeight);       lineViews.add(childView);     }     // 记录最后一行     mAllViews.add(lineViews);     mLineHeight.add(lineHeight);     int left = 0;     int top = 0;     // 得到总行数     int size = mAllViews.size();     for (int i = 0; i < size; i++) {       // 每一行的所有的views       lineViews = mAllViews.get(i);       // 当前行的最大高度       lineHeight = mLineHeight.get(i);       for (View view : lineViews) {         LayoutParam lp = (LayoutParam) view.getLayoutParams();         //计算childView的left,top,right,bottom         int lc = left + lp.leftMargin;         int tc = top + lp.topMargin;         int rc = lc + view.getMeasuredWidth();         int bc = tc + view.getMeasuredHeight();         view.layout(lc,tc,rc,bc);         left += view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;       }       left = 0;       top += lineHeight;     }   }

通过onLayout方法给子View布局,前提,我们必须得知道每个子View的宽度和高度。所以我们先要在onMeasure的时候,测量一下每个子View的具体大小。

测试

public class MainActivity extends AppCompatActivity {   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     FlowLayout flowLayout = ((FlowLayout) findViewById(R.id.flowLayout));     FlowLayout.LayoutParam params = new    FlowLayout.LayoutParam(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);     params.setMargins(10,10,10,10);     for (int i = 0; i < 10; i++) {       TextView textView = new TextView(this);       textView.setPadding(i * 10,10,i * 10,10);       textView.setBackgroundColor(Color.BLUE);       textView.setText("哈哈哈哈");       textView.setTextColor(Color.WHITE);       textView.setLayoutParams(params);       flowLayout.addView(textView);     }   } }

这里我们要注意下FlowLayout.LayoutParam params = new FlowLayout.LayoutParam(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);这个方法,有的小伙伴在写的过程中可能点不出来这个方法,那是因为这个方法是需要我们自己写一个静态内部类来实现。

@Override   protected LayoutParams generateDefaultLayoutParams() {     return new LayoutParam(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);   }   @Override   public LayoutParams generateLayoutParams(AttributeSet attrs) {     return new LayoutParam(getContext(),attrs);   }   @Override   protected LayoutParams generateLayoutParams(LayoutParams p) {     return new LayoutParam(p);   }   public static class LayoutParam extends MarginLayoutParams{     public LayoutParam(Context c, AttributeSet attrs) {       super(c, attrs);     }     public LayoutParam(@Px int width, @Px int height) {       super(width, height);     }     public LayoutParam(MarginLayoutParams source) {       super(source);     }     public LayoutParam(LayoutParams source) {       super(source);     }   }

上述内容就是如何在Android中实现一个流式布局,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI