您的位置:首页 > 其它

自定义流式布局(应用:热门标签,照片)

2015-11-18 23:52 351 查看
流式布局(应用:热门标签,照片)

自定义ViewGroup

1.onMeasure:测量子View的宽和高,设置自己的宽和高

onMeasure根据子View的布局文件,为子View设置测量模式和测量值。

测量:包括测量模式和测量值

测量模式包裹以下三种模式:

1.EXACTLY:是指显示指定大小时,例如:100dp,match_parent

2.AT_MOST:wrap_content

3.UNSPCIFIED:子View想要多大就给他多大,一般出现在ScroolView中,很少见

2.onLayout:设置子View的位置

ViewGroup会对应一个LayoutParams

子View.getLayoutParams()获得的是父控件的LayoutParameters

这里我们只需要知道子空间之间的间距,所以我们只需要指定我们LayoutParams为MarginLayoutParameters即可,

当然在实际开发中我们应该根据需要来选择LayoutParams,也可以自定义LayoutParams。

效果:



代码如下:

package com.example.liaoli.customflowlayout.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
* Created by liaoli on 2015/11/16.
*/
public class FlawLayout extends ViewGroup {
public FlawLayout(Context context) {
super(context);
}

public FlawLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}

public FlawLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

/**
* 測量子類的寬和高,以便確定自己的寬和高
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int mWidth = MeasureSpec.getSize(widthMeasureSpec);
int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);

int mHeight = MeasureSpec.getSize(heightMeasureSpec);
int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);

int childCount = getChildCount();

//記錄wrap_content時候FlawLayout的寬和高
int wrapContentWidth = 0;
int wrapContentHeight= 0;

//記錄每一行的寬度和高度
int lineWidth = 0;
int lineHeight = 0;
for(int i = 0;i < childCount;i++){
View child = getChildAt(i);

//測量每一個子View的寬和高
measureChild(child, widthMeasureSpec, heightMeasureSpec);

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

//得到計算子View佔據的寬度和高度

int childWidthInParent = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
int childHeightInParent = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;

if (lineWidth + childWidthInParent > mWidth - getPaddingLeft() - getPaddingRight()) {

//此時要換行,行的高度增加
wrapContentHeight += lineHeight;

//此時一行的寬度已經可以確定,如果行寬比原來的最大行寬大,則寬度變為大的
wrapContentWidth = Math.max(lineWidth,wrapContentWidth);

//換行后充值行寬和行高
lineHeight = childHeightInParent;
lineWidth = childWidthInParent;

}else {

//不換行,本行寬度增加
lineWidth += childWidthInParent;
//不換行,本行高度有可能變化
lineHeight = Math.max(lineHeight,childHeightInParent);
}

if(i == childCount -1){
//如果是最後一個Child,要將此次View所在的行高加上
wrapContentHeight += lineHeight;
//比較最後一行與之前的最大寬度進行比較,去打的作為wrap_content的寬度
wrapContentWidth = Math.max(lineWidth,wrapContentWidth);
}

}

setMeasuredDimension(widthMeasureMode == MeasureSpec.EXACTLY ? mWidth:wrapContentWidth+getPaddingLeft()+getPaddingRight(),
heightMeasureMode == MeasureSpec.EXACTLY ? mHeight:wrapContentHeight+getPaddingTop() + getPaddingBottom());

}

List<List<View>> allchildViews =  new ArrayList<>();
List<Integer> lineHeights = new ArrayList<>();

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

allchildViews.clear();
lineHeights.clear();

int mwidth = getWidth();

//記錄每一行的寬度和高度
int lineWidth = 0;
int lineHeight = 0;

List<View> lineViews = new ArrayList<>();
int childCount = getChildCount();

for(int i = 0 ; i < childCount ; i++){

View child = getChildAt(i);

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

int childWidth = child.getMeasuredWidth()+ layoutParams.leftMargin + layoutParams.rightMargin;;

int childHeight = child.getMeasuredHeight()+ layoutParams.topMargin + layoutParams.bottomMargin;;

if(lineWidth + childWidth > mwidth -getPaddingLeft() - getPaddingRight()){

//换行
lineHeights.add(lineHeight);

lineWidth = 0;
lineHeight = childHeight;
allchildViews.add(lineViews);

lineViews = new ArrayList<>();

}

//不换行
lineWidth += childWidth;
lineHeight = Math.max(childHeight,lineHeight);
lineViews.add(child);

if(i == childCount -1){
//要將此次View所在的行高加上最后一行的行高
lineHeights.add(lineHeight);
//左后一行的view
allchildViews.add(lineViews);
}

}

int left = getPaddingLeft();
int top = getPaddingTop();

int lineNumbers = lineHeights.size();

for(int i = 0 ; i < lineNumbers ; i++){

lineViews = allchildViews.get(i);
lineHeight = lineHeights.get(i);

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

if(child.getVisibility() == View.GONE){
continue;
}

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

int childTopInparent = top + layoutParams.topMargin;

int childBottomInparent = top + layoutParams.topMargin +child.getMeasuredHeight();

int childLeftInparent = left + layoutParams.leftMargin;

int childRightInparent = left + layoutParams.leftMargin + child.getMeasuredWidth() ;

child.layout(childLeftInparent,childTopInparent,childRightInparent,childBottomInparent);

//下一个View的left其实点
left += layoutParams.leftMargin + child.getMeasuredWidth()+ layoutParams.rightMargin;
}

//每一行完毕后,left又回到最左边,二top则增加了一行
left = getPaddingLeft();
top += lineHeight;
}
}

/**
* 指定我們自己想要的LayoutParams,如果現有的LayoutParams不能滿足需求,我們科以自定義
*/
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(),attrs);
}
}


源码:http://pan.baidu.com/s/1jG1yrvo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: