美文网首页
Android自定义View之自定义布局

Android自定义View之自定义布局

作者: 翟小乙 | 来源:发表于2022-04-20 18:38 被阅读0次
    自定义分为自定义View与自定义布局:
    • 需要掌握的技术:

      1. onMeasure 父子组件大小计算
      2. onLayout 组件排版
      3. onDraw
    • 知识点:

      1. getMeasureWidth()与getMeasureHeight() 在View没有展示完全获取
      2. getWidth()与getHeight()在View展示后才能获取
      3. MeasureSpec.EXACTLY 等三种类型区别
      4. 通过getChildMeasureSpec将子view的宽高转为MeasureSpec
    • 自定义布局用到前两个,我们以流式布局为例实现自定义布局:

    实现:

    思路:
    1.onMeasure中计算子View 大小
    2.右子View 大小计算出父View真是宽高
    3.记录所有行的View 与高度
    4.在Onlayout中排版

    • 创建 LiuShiLayout 继承 ViewGroup
    package com.myself.alamdding;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.ViewGroup;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class LiuShiLayout extends ViewGroup {
    
      int hWidth = 100;  // 每一行的宽度间隔
      int vHeight = 100; // 每一行的高度间隔
      private List<List<View>> listListLine = new ArrayList<>();// 记录所有行的信息
      private List<Integer> listHeight = new ArrayList<>();// 记录每一行的行高
    
       public LiuShiLayout(Context context) {
          super(context);
      }
    
      public LiuShiLayout(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
    
      public LiuShiLayout(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
      }
    
      public LiuShiLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
      }
      private void initParams(){
    
           listListLine = new ArrayList<>();// 记录所有行的信息
            listHeight = new ArrayList<>();// 记录每一行的行高
      }
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          initParams();
           // 计算自己宽高
           int lineWidth = 0; // 每一行的宽度
           int lineHeight = 0;// 每一行的高度
           int parentWith = 0;// 所有行一共宽度
           int parentHeight = 0;// 所有行一共高度
           List<View> lineViewArr = new ArrayList<>();// 每一行存储的view
           int selfWidth = MeasureSpec.getSize(widthMeasureSpec);// 容器宽度
           int selfHeight = MeasureSpec.getSize(heightMeasureSpec);// 容器高度
          // 计算子view 大小
          int paddingLeft =  getPaddingLeft();
          int paddingRight =  getPaddingRight();
          int paddingTop =  getPaddingTop();
          int paddingBottom =  getPaddingBottom();
          for (int i = 0; i < getChildCount(); i++) {
              View view = getChildAt(i);
              LayoutParams layoutParams = view.getLayoutParams();
              int childMeasureSpecWidth = getChildMeasureSpec(widthMeasureSpec, paddingLeft+paddingRight, layoutParams.width);
              int childMeasureSpecHeight = getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, layoutParams.height);
              view.measure(childMeasureSpecWidth,childMeasureSpecHeight);
    
              // 获取子view 一行宽度和一行最大高度
              int childWidth = view.getMeasuredWidth();
              int childHeight = view.getMeasuredHeight();
    
              if((lineWidth + childWidth + hWidth)> selfWidth||lineHeight==0){// 换行
                  listListLine.add(lineViewArr);// 记录每一行的view
                  listHeight.add(parentHeight);
                  // 换行之前统计一下宽高度
                  parentWith = Math.max(parentWith, lineWidth + hWidth);
                  parentHeight = parentHeight + lineHeight + vHeight;
    
    
                  lineWidth = 0;
                  lineHeight = 0;
                  lineViewArr = new ArrayList<>();
              }
    
              lineViewArr.add(view);
              lineWidth = lineWidth + childWidth + hWidth;
              lineHeight = Math.max(lineHeight,childHeight);
    
          }
          // 计算自己大小->根据子view
          int widthMode = MeasureSpec.getMode(widthMeasureSpec);
          int heightMode = MeasureSpec.getMode(heightMeasureSpec);
              // 如果父亲传过来的是确切的size就用自己,不是就用计算的
    
          listListLine.add(lineViewArr);// 记录每一行的view
          listHeight.add(parentHeight);
          parentWith = Math.max(parentWith, lineWidth + hWidth);
          parentHeight = parentHeight + lineHeight + vHeight;
    
          int realWidth = (widthMode==MeasureSpec.EXACTLY)?selfWidth:parentWith;
          int realHeight = (heightMode==MeasureSpec.EXACTLY)?selfHeight:parentHeight;
    
          setMeasuredDimension(realWidth,realHeight);
    
      }
    
      @Override
      protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
           int curLeft = getPaddingLeft();
           int curTop = getPaddingTop();
          for (int j = 0; j < listListLine.size(); j++) {
              int lineHeight = listHeight.get(j);
              List<View> viewList = listListLine.get(j);
              for (int k = 0; k < viewList.size(); k++) {
                  View view = viewList.get(k);
                  int left = curLeft;
                  int top = curTop;
                  int right = left + view.getMeasuredWidth();
                  int bottom = top + view.getMeasuredHeight();
                  view.layout(left,top,right,bottom);
                  curLeft = right + hWidth;// 画完一个View,位置右移动画下一个
              }
              curLeft = getPaddingLeft();
              curTop = curTop + lineHeight + vHeight;
          }
      }
    
      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);
      }
    }
    
    
    XML 实现:
     <com.myself.alamdding.LiuShiLayout
            android:layout_width="match_parent"
            android:background="@color/colorPrimaryDark"
            android:layout_marginTop="20dp"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:text="北京"
                android:background="@color/colorPrimary"/>
            <TextView
                android:layout_width="50dp"
                android:layout_height="wrap_content"
                android:text="石家庄"
                android:background="@color/colorPrimary"/>
        </com.myself.alamdding.LiuShiLayout>
    
    效果:
    效果.png

    相关文章

      网友评论

          本文标题:Android自定义View之自定义布局

          本文链接:https://www.haomeiwen.com/subject/jlcwertx.html