zcp0118

流式布局---FlowLayout

  1 public class FlowLayout extends ViewGroup {
  2     public FlowLayout(Context context) {
  3         this(context,null);
  4     }
  5 
  6     public FlowLayout(Context context, AttributeSet attrs) {
  7         this(context, attrs,0);
  8     }
  9 
 10     public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
 11         super(context, attrs, defStyleAttr);
 12     }
 13 
 14     @Override
 15     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 16         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 17         /**
 18         * 测量=测量宽高+测量模式
 19         * */
 20         //获得容器测量宽和高
 21         int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
 22         int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
 23         //测量模式
 24         int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
 25         int heigheMeasureMode = MeasureSpec.getMode(heightMeasureSpec);
 26 
 27         //记录每一行的宽和高
 28         int lineWidth=0;//每一行中最长的一行是他的宽度
 29         int lineHeight=0;//几行的高度
 30 
 31         //wrap_content-->AT_MOST
 32         int width=0;
 33         int height=0;
 34         //获得内部元素的个数
 35         int childCount = getChildCount();
 36         //遍历得到每一个View
 37         for(int i=0;i<childCount;i++)
 38         {
 39             View child = getChildAt(i);
 40             //测量子View的宽和高
 41             measureChild(child,widthMeasureSpec,heightMeasureSpec);
 42             //流式布局只需要知道每一个子View之间的margin,故创建MarginLayoutParams
 43             //TODO
 44             MarginLayoutParams lp= (MarginLayoutParams) child.getLayoutParams();
 45             //子View占据的宽度
 46             int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
 47             //子View占据的高度
 48             int chileHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
 49             //判断:如果需要换行
 50             /**
 51              * 如果TextView设置了pading,在比较的时候sizeWidth要去掉getPadingRight和getPadingLeft
 52              */
 53 
 54             if(lineWidth+childWidth>sizeWidth)
 55             {
 56                 //第一行的宽度
 57                 width=Math.max(width,lineWidth);
 58                 lineWidth=childWidth;//因为换行,故当前的宽度就是子View的宽度
 59                 height+=lineHeight;//当前的高度就是前一行的高度加上之前的高度
 60                 lineHeight=chileHeight;//下一行的高度
 61             }else//未换行
 62                 {
 63                     lineWidth+=childWidth;//叠加行宽
 64                     lineHeight=Math.max(lineHeight,chileHeight);//得到当前行的最大高度
 65                 }
 66                 //如果到达最后一个控件
 67             if(i==childCount-1)
 68             {
 69                 width=Math.max(lineWidth,width);
 70                 height+=lineHeight;
 71             }
 72 
 73         }
 74 
 75         /**
 76         * EXACTLY:100dp,match_content
 77         * AT_MOST:wrap_content
 78         * UNSPICFIED:子控件想要多大就多大(一般不常用)
 79         *
 80         * */
 81         //如果是wrap_content
 82         /**
 83          * 如果TextView设置了pading,在比较的时候Width要加上getPadingRight和getPadingLeft
 84          * height要加上getPadingTop和getPadingBottom
 85          */
 86         setMeasuredDimension(
 87                 widthMeasureMode==MeasureSpec.EXACTLY?sizeWidth:width,
 88                 heigheMeasureMode==MeasureSpec.EXACTLY?sizeHeight:height);
 89 
 90     }
 91 
 92     //存储所有的View
 93     /**
 94      * 比如有三行,则mAllViews的长度就是3
 95      * List<View>记录每一行的View
 96      * */
 97     List<List<View>> mAllViews=new ArrayList<>();
 98 
 99     //每一行的高度
100     List<Integer> mLineHeight=new ArrayList<>();
101     @Override
102     protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
103         //该方法会调用多次,故:对List清除
104         mAllViews.clear();
105         mLineHeight.clear();
106         //当前ViewGroup的宽度和高度
107         int width = getWidth();
108         //
109         int lineWidth=0;
110         int lineHeight=0;
111         List<View> lineViews=new ArrayList<>();
112         int childCount = getChildCount();
113         //遍历
114         for(int a=0;a<childCount;a++)
115         {
116             View child = getChildAt(a);
117 
118            MarginLayoutParams lp= (MarginLayoutParams) child.getLayoutParams();
119             int childHeight = child.getMeasuredHeight();
120             int childWidth = child.getMeasuredWidth();
121             //换行
122             /**
123              * 如果TextView设置了pading,,在比较的时候Width要加上getPadingRight和getPadingLeft
124              * top是getPadingTop
125              */
126             if(childWidth+lp.leftMargin+lp.rightMargin+lineWidth>width)
127             {
128 
129                 //记录lineHeight
130                 mLineHeight.add(lineHeight);
131                 mAllViews.add(lineViews);
132 
133                 //重置
134                 lineWidth=0;
135                 lineHeight=childHeight+lp.topMargin+lp.bottomMargin;
136                 //重置View的集合
137                 lineViews=new ArrayList<>();
138             }
139             lineWidth+=childWidth+lp.leftMargin+lp.rightMargin;
140             lineHeight=Math.max(lineHeight,childHeight+lp.topMargin+lp.bottomMargin);
141             lineViews.add(child);
142         }
143 
144         //处理最后一行
145         mLineHeight.add(lineHeight);
146         mAllViews.add(lineViews);
147 
148         /**
149          * 如果TextView设置了pading,left是getPadingLeft
150          * top是getPadingTop
151          */
152         //设置子View的位置
153         int left=0;int top=0;
154         int lineNums=mAllViews.size();
155         for(int a=0;a<lineNums;a++)
156         {
157             //当前行的所有View
158             lineViews=mAllViews.get(a);
159             lineHeight=mLineHeight.get(a);
160             for(int j=0;j<lineViews.size();j++)
161             {
162                 View child=lineViews.get(j);
163                 if(child.getVisibility()==View.GONE)
164                 {
165                     continue;
166                 }
167                 MarginLayoutParams lp= (MarginLayoutParams) child.getLayoutParams();
168                 //获取上下左右
169                 int lc=left+lp.leftMargin;
170                 int tc=top+lp.topMargin;
171                 int rc=lc+child.getMeasuredWidth();
172                 int bc=tc+child.getMeasuredHeight();
173 
174                 //为子View进行布局
175                 child.layout(lc,tc,rc,bc);
176                 left+=child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;
177             }
178             /**
179              * 如果TextView设置了pading,left是getPadingLeft
180              */
181             left=0;
182             top+=lineHeight;
183         }
184     }
185     每一个ViewGroup都会对应一个LayoutParams,在这里,我们只需要知道每一个子View之间的偏移量,故而只需要创建MarginLayoutParams,
186     //与当前的ViewGroup对应的LayoutParams,这个方法一定要写
187     @Override
188     public LayoutParams generateLayoutParams(AttributeSet attrs) {
189         return new MarginLayoutParams(getContext(),attrs);
190     }
191 }

以下是对应的xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.z.flowlayout.MainActivity">

    <com.example.z.flowlayout.FlowLayout
        android:id="@+id/id_flowLayout"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"></com.example.z.flowlayout.FlowLayout>

</RelativeLayout>

以下是MainActivity的全部代码

public class MainActivity extends AppCompatActivity {

    private String[] views=new String[]{
            "Hello World","Android","PHP","java",
            "UI","Welcome", "TAKE CLASS","Lisa",
            "Marry","Willen","Mark","Henry","Thank",
            "No","Yes","Sorry"};
    private FlowLayout flowLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        flowLayout = (FlowLayout) findViewById(R.id.id_flowLayout);
        initData();
    }

    private void initData() {

        for(int i=0;i<views.length;i++)
        {
            TextView tv = (TextView) LayoutInflater.from(this).inflate(R.layout.tv, flowLayout,false);
            tv.setText(views[i]);
            flowLayout.addView(tv);
        }

    }
}

 

posted on 2017-08-25 14:31  萌主不是盟主  阅读(220)  评论(0编辑  收藏  举报
 

分类:

技术点:

相关文章:

  • 2022-12-23
  • 2021-11-06
  • 2022-02-02
  • 2021-11-21
  • 2021-12-13
  • 2021-06-23
  • 2021-08-01
  • 2022-03-01
猜你喜欢
  • 2021-11-29
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-21
  • 2021-04-30
  • 2021-11-23
相关资源
相似解决方案