Android Customize FlowLayout

流布局相信大家应该都比较清楚,几乎每个人都写过。
开源的也是非常多!
就不过多介绍啦,这里做了一个比较简洁且支持Padding以及间隔的流布局供大家参考。
代码比较简单粗暴就不过多介绍,按照惯例上代码:

<declare-styleable name="flowLayout"> 
   <attr name="VerticalSpacer" format="integer" /> 
   <attr name="HorizontalSpacer" format="integer" />
</declare-styleable>

/** * Created by Liqingwen on 7/13/16.
 * Email: Liqingqingqingwen@163.com
 */
public class FlowLayout extends ViewGroup {   
     /**水平间距*/
     public final static int DEFAULT_HORIZONTAL_SPACER = 5;
    /**垂直间距*/ 
     public final static int DEFAULT_VERTICAL_SPACER = 5;          
     private int mHorizontalSpacer;    
     private int mVerticalSpacer;

        public FlowLayout(Context context) {     
                   super(context);  
  }   
 public FlowLayout(Context context, AttributeSet attrs) {              
         super(context, attrs); 
         TypedArray array   =  context.obtainStyledAttributes(attrs,R.styleable.flowLayout);        try {      
         mHorizontalSpacer = array.getInteger(R.styleable.flowLayout_HorizontalSpacer,DEFAULT_HORIZONTAL_SPACER);      
         mVerticalSpacer = array.getInteger(R.styleable.flowLayout_VerticalSpacer,DEFAULT_VERTICAL_SPACER);

          }finally {   
         array.recycle();        
    } 
 }


    @Override    
protected void onLayout(boolean changed, int l, int t, int r, int b) {       
     int mFlowLayoutWidth = getMeasuredWidth();     
     int mFlowLayoutPaddingLeft  = getPaddingLeft();   
     int mFlowLayoutPaddingRight = getPaddingRight();     
     int mFlowLayoutPaddingBottom = getPaddingBottom();             
     int mFlowLayoutPaddingTop  = getPaddingTop();     
     int mChildTotalWidth = mFlowLayoutPaddingLeft;    
     int mChildTotalHeight = mFlowLayoutPaddingTop ;    
     int mChildCount  =  getChildCount();  
    
 for (int i = 0; i < mChildCount ;i ++) {        
          View mChildView = getChildAt(i);        
      if (mChildView.getVisibility() == View.GONE)                    
          continue;      

int mChildViewMeasuredHeight = mChildView.getMeasuredHeight(); 
int mChildViewMeasuredWidth =  mChildView.getMeasuredWidth();       
     
if(mChildTotalWidth + mChildViewMeasuredWidth  >  mFlowLayoutWidth -  mFlowLayoutPaddingLeft - mFlowLayoutPaddingRight){      
          mChildTotalWidth =  mFlowLayoutPaddingLeft;                
          mChildTotalHeight += mVerticalSpacer + 
          mChildViewMeasuredHeight ;    
     
   }                

setChildFrame(mChildView,mChildTotalWidth,mChildTotalHeight,mChildTotalWidth + mChildViewMeasuredWidth, mChildTotalHeight + mChildViewMeasuredHeight);        
mChildTotalWidth +=  mHorizontalSpacer +  mChildViewMeasuredWidth;   

       }   
 }   
 private void setChildFrame(@NonNull View mView, int l, int t, int r, int b){     
       mView.layout(l,t,r,b); 
   }    

@Override   
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {     
    int  mFlowLayoutWidth = resolveSize(0,widthMeasureSpec);            
    int mFlowLayoutPaddingLeft  = getPaddingLeft();   
    int mFlowLayoutPaddingRight = getPaddingRight();      
    int mFlowLayoutPaddingBottom = getPaddingBottom();          
    int mFlowLayoutPaddingTop  = getPaddingTop();    
    int mChildTotalWidth  = mFlowLayoutPaddingLeft ;  
    int mTotalLineHeight = 0;     
    int mChildCount  =  getChildCount();  

  for (int i = 0; i < mChildCount ;i ++){    
        View mChildView  = getChildAt(i);         
     if(mChildView.getVisibility()  == View.GONE)                   
          continue;             
          
         measureChild(mChildView,widthMeasureSpec,heightMeasureSpec);      
     int mChildViewMeasuredHeight =  mChildView.getMeasuredHeight();         
     int mChildViewMeasuredWidth =  mChildView.getMeasuredWidth();            
     MarginLayoutParams mMarginLayoutParams = (MarginLayoutParams) mChildView.getLayoutParams();     
     mTotalLineHeight = Math.max(mTotalLineHeight,mChildViewMeasuredHeight);      
   if(mChildTotalWidth +mChildViewMeasuredWidth   >   mFlowLayoutWidth  - mFlowLayoutPaddingLeft -   mFlowLayoutPaddingRight){   
        mChildTotalWidth =  mFlowLayoutPaddingLeft;                mTotalLineHeight  += mVerticalSpacer + mChildViewMeasuredHeight ;
    }else{        
         mChildTotalWidth +=  mHorizontalSpacer + mChildViewMeasuredWidth ; 
       }             
         setMeasuredDimension(mFlowLayoutWidth,resolveSize(mFlowLayoutPaddingTop + mTotalLineHeight + mFlowLayoutPaddingBottom,heightMeasureSpec));  

      }  

  }   

 /** 
       *与当前ViewGroup对应的LayoutParams 
       * 这里想要支持Margin就必须实现generateLayoutParams 方法
       * 否则会强制转换异常!
       * 目前LayoutFlow不支持Margin 等有好点思路再加上 

@Override
 public LayoutParams generateLayoutParams(AttributeSet attrs) {      
          return new MarginLayoutParams(getContext(), attrs);  
  }
     */   
}

整体效果如下:

《Android Customize FlowLayout》 flow.jpeg

当然啦!这个布局也有点小 bug 图片如下:

《Android Customize FlowLayout》 bug.jpeg

这个bug呢我就不解决啦!
最近忙着做一个 模仿windowsPhone 主页的磁贴布局,嗯…这个bug有点像windowsPhone 主页的磁贴…..
解决的方式也比较简单只要获取上一行 判断谁的高最大ok啦!
但是流布局的字 View一般都是被当成热词使用高度都是一样的,所以这个也不算bug,不过要是你的子View款高度不确定的话那就另当别论。

下一篇 : 模仿windowsPhone 主页的磁贴

    原文作者:qingwenLi
    原文地址: https://www.jianshu.com/p/00a52849edfc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞