Chinaunix首页 | 论坛 | 博客
  • 博客访问: 418671
  • 博文数量: 121
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1393
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-11 12:17
个人简介

www.vibexie.com vibexie@qq.com

文章分类

全部博文(121)

文章存档

2015年(55)

2014年(66)

我的朋友

分类: Android平台

2015-04-15 10:28:43


FlowLayout.java

  1. package cn.com.xiebiao.flowlayout;

  2. import android.content.Context;
  3. import android.util.AttributeSet;
  4. import android.view.View;
  5. import android.view.ViewGroup;

  6. import java.util.ArrayList;
  7. import java.util.List;

  8. /**
  9.  * Created by vibexie on 3/26/15.
  10.  */
  11. public class FlowLayout extends ViewGroup{

  12.     //三个构造方法
  13.     public FlowLayout(Context context) {
  14.         //super(context);
  15.         this(context,null);
  16.     }

  17.     public FlowLayout(Context context, AttributeSet attrs) {
  18.         //super(context, attrs);
  19.         this(context,attrs,0);

  20.     }

  21.     public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  22.         super(context, attrs, defStyleAttr);
  23.     }

  24.     //当前ViewGroup对应的LayoutParams
  25.     @Override
  26.     public LayoutParams generateLayoutParams(AttributeSet attrs) {
  27.         return new MarginLayoutParams(getContext(),attrs);
  28.     }

  29.     /*widthMeasureSpec,heightMeasureSpec分别为
  30.      *android:layout_width="match_parent" android:layout_height="match_parent">
  31.      * 也就是父ViewGroup传递进来的值
  32.      */
  33.     @Override
  34.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  35.         /*容器ViewGroup的宽度和模式,android:layout_width="match_parent"对应模式MeasureSpec.EXACTLY;
  36.           android:layout_width="match_parent"对应模式MeasureSpec.AT_MOST;
  37.           还有一种模式不常用MeasureSpec.UNSPECIFIED
  38.          */
  39.         int sizeWidth=MeasureSpec.getSize(widthMeasureSpec);
  40.         int modeWidth=MeasureSpec.getMode(widthMeasureSpec);
  41.         /*容器ViewGroup的宽度和模式,同width*/
  42.         int sizeHeigth=MeasureSpec.getSize(heightMeasureSpec);
  43.         int modeHeigth=MeasureSpec.getMode(heightMeasureSpec);

  44.         /*如上,是match_parent的时候,sizeWidth和sizeHeigth可以在父viewGroup中得到
  45.              但是如果是warp_content时,就需要自己计算sizeWidth和sizeHeigth
  46.              */
  47.         //记录最大宽度和最大高度对应的宽和高
  48.         int width=0;
  49.         int heigth=0;
  50.         //记录每一行的宽度和高度
  51.         int lineWidth=0;
  52.         int lineHeigth=0;
  53.         //得到内部元素的个数
  54.         int cCount=getChildCount();

  55.         //遍历子View
  56.         for(int i=0;i<cCount;i++){
  57.             View child=getChildAt(i);

  58.             /*测量子view的宽和高
  59.               protected void measureChild(android.view.View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
  60.              */
  61.             measureChild(child,widthMeasureSpec,heightMeasureSpec);

  62.             /*得到LayoutParams,必须由于父View的LayoutParams相一致,
  63.               即与public LayoutParams generateLayoutParams(AttributeSet attrs)返回的一致
  64.               */
  65.             MarginLayoutParams layoutParams=(MarginLayoutParams)child.getLayoutParams();

  66.             //子View占据的宽度
  67.             int childWidth=child.getMeasuredWidth()+layoutParams.leftMargin+layoutParams.rightMargin;
  68.             //子View占据的高度
  69.             int childHeigth=child.getMeasuredHeight()+layoutParams.topMargin+layoutParams.bottomMargin;

  70.             if((lineWidth+childWidth)>sizeWidth){
  71.                 //如果此行的宽度+下一个子View的宽度大于容器ViewGroup的宽度,则换行
  72.                 //记录的最大宽度width和本行的宽度lineWidth比较,得到最大的宽度再记录
  73.                 width=Math.max(width,lineWidth);
  74.                 //重置lineWidth
  75.                 lineWidth=childWidth;
  76.                 //记录行高
  77.                 heigth+=lineHeigth;
  78.                 //重置lineHeigth
  79.                 lineHeigth=childHeigth;
  80.             }else {
  81.                 //不换行
  82.                 //叠加行宽
  83.                 lineWidth+=childWidth;
  84.                 //得到当前行最到的高度
  85.                 lineHeigth=Math.max(lineHeigth,childHeigth);
  86.             }

  87.             if(i==cCount-1){
  88.                 //到达最后一个子view
  89.                 width=Math.max(lineWidth,width);
  90.                 heigth+=lineHeigth;
  91.             }
  92.         }

  93.         //设定最终尺寸
  94.         setMeasuredDimension(modeWidth==MeasureSpec.EXACTLY?sizeWidth:width,modeHeigth==MeasureSpec.EXACTLY?sizeHeigth:heigth);

  95.         //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  96.     }

  97.     //保存所有的View,以分行的方式保存
  98.     private List<List<View>> mAllViews=new ArrayList<List<View>>();

  99.     //每一行的高度
  100.     private List<Integer> mLineHeigth=new ArrayList<Integer>();

  101.     @Override
  102.     protected void onLayout(boolean b, int i, int i2, int i3, int i4) {
  103.         //调用多次onlayout方法时,清空保存的内容
  104.         mAllViews.clear();
  105.         mLineHeigth.clear();

  106.         //当前ViewGroup的宽度,之前已经执行了onMesure()方法
  107.         int width=getWidth();

  108.         int lineWidth=0;
  109.         int lineHeigth=0;

  110.         //存放每一行的View
  111.         List<View> lineViews=new ArrayList<View>();

  112.         //子View的个数
  113.         int cCount=getChildCount();

  114.         for(int j=0;j<cCount;j++){
  115.             View child=getChildAt(j);
  116.             MarginLayoutParams layoutParams=(MarginLayoutParams)child.getLayoutParams();

  117.             int childWidth=child.getMeasuredWidth();
  118.             int childHeigth=child.getMeasuredHeight();

  119.             //如果需要换行
  120.             if((childWidth+lineWidth+layoutParams.leftMargin+layoutParams.rightMargin)>width){
  121.                 //记录lineHeigth
  122.                 mLineHeigth.add(lineHeigth);
  123.                 //记录当前的view
  124.                 mAllViews.add(lineViews);

  125.                 //重置行宽和行高
  126.                 lineWidth=0;
  127.                 lineHeigth=childHeigth+layoutParams.topMargin+layoutParams.bottomMargin;

  128.                 //重置lineViews集合
  129.                 lineViews=new ArrayList<View>();
  130.             }

  131.             //不换行则将child加入lineViews中
  132.             lineWidth+=childWidth+layoutParams.leftMargin+layoutParams.rightMargin;
  133.             lineHeigth=Math.max(lineHeigth,childHeigth+layoutParams.topMargin+layoutParams.bottomMargin);
  134.             lineViews.add(child);
  135.         }

  136.         //处理最后一行
  137.         mLineHeigth.add(lineHeigth);
  138.         mAllViews.add(lineViews);


  139.         //处理子View的位置
  140.         int left=0;
  141.         int top=0;

  142.         //行数
  143.         int lineNum=mAllViews.size();

  144.         for(int j=0;j<lineNum;j++){
  145.             //当前行的所有View
  146.             lineViews=mAllViews.get(j);
  147.             lineHeigth=mLineHeigth.get(j);

  148.             for(int k=0;k<lineViews.size();k++){
  149.                 View child=lineViews.get(k);

  150.                 //判断child的状态
  151.                 if(child.getVisibility()==View.GONE){
  152.                     continue;
  153.                 }

  154.                 MarginLayoutParams layoutParams=(MarginLayoutParams)child.getLayoutParams();

  155.                 int lc=left+layoutParams.leftMargin;
  156.                 int tc=top+layoutParams.topMargin;
  157.                 int rc=lc+child.getMeasuredWidth();
  158.                 int bc=tc+child.getMeasuredHeight();

  159.                 //为子View布局
  160.                 child.layout(lc,tc,rc,bc);

  161.                 left+=child.getMeasuredWidth()+layoutParams.leftMargin+layoutParams.rightMargin;
  162.             }

  163.             //到达下一行
  164.             left=0;
  165.             top+=lineHeigth;
  166.         }
  167.     }
  168. }

activity_main.xml

  1. <RelativeLayout xmlns:android=""
  2.     xmlns:tools="" android:layout_width="match_parent"
  3.     android:layout_height="match_parent" >

  4.     <cn.com.xiebiao.flowlayout.FlowLayout
  5.         android:layout_width="wrap_content"
  6.         android:layout_height="wrap_content">
  7.         <Button
  8.             android:layout_width="wrap_content"
  9.             android:layout_height="wrap_content"
  10.             android:text="hello"/>
  11.         <Button
  12.             android:layout_width="wrap_content"
  13.             android:layout_height="wrap_content"
  14.             android:text="welocom"/>
  15.         <Button
  16.             android:layout_width="wrap_content"
  17.             android:layout_height="wrap_content"
  18.             android:text="fdsfsd"/>
  19.         <Button
  20.             android:layout_width="wrap_content"
  21.             android:layout_height="wrap_content"
  22.             android:text="fdsfdsgdgdfgdfgf"/>
  23.         <Button
  24.             android:layout_width="wrap_content"
  25.             android:layout_height="wrap_content"
  26.             android:text="ghfdhdgfhdfghdgfh"/>
  27.         <Button
  28.             android:layout_width="wrap_content"
  29.             android:layout_height="wrap_content"
  30.             android:text="ggg"/>

  31.     </cn.com.xiebiao.flowlayout.FlowLayout>

  32. </RelativeLayout>

MainActivity.java

  1. package cn.com.xiebiao.flowlayout;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.Menu;
  5. import android.view.MenuItem;


  6. public class MainActivity extends Activity {

  7.     @Override
  8.     protected void onCreate(Bundle savedInstanceState) {
  9.         super.onCreate(savedInstanceState);
  10.         setContentView(R.layout.activity_main);
  11.     }


  12.     @Override
  13.     public boolean onCreateOptionsMenu(Menu menu) {
  14.         // Inflate the menu; this adds items to the action bar if it is present.
  15.         getMenuInflater().inflate(R.menu.menu_main, menu);
  16.         return true;
  17.     }

  18.     @Override
  19.     public boolean onOptionsItemSelected(MenuItem item) {
  20.         // Handle action bar item clicks here. The action bar will
  21.         // automatically handle clicks on the Home/Up button, so long
  22.         // as you specify a parent activity in AndroidManifest.xml.
  23.         int id = item.getItemId();

  24.         //noinspection SimplifiableIfStatement
  25.         if (id == R.id.action_settings) {
  26.             return true;
  27.         }

  28.         return super.onOptionsItemSelected(item);
  29.     }
  30. }


阅读(1436) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~