1. 程式人生 > >流式佈局控制元件的編寫

流式佈局控制元件的編寫

這裡寫圖片描述


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

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

/**
 * 作者: willkong on 2017/11/15.
 * 作用:流式佈局
 */
public class FlowLayout extends ViewGroup{
    public FlowLayout(Context context) {
        this
(context,null); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs,0); } public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //能夠設定當前佈局的寬度和高度 @Override protected void
onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); //獲取設定的寬高的模式和具體的值 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int
heightSize = MeasureSpec.getSize(heightMeasureSpec); //如果使用者使用的至多模式,那麼使用如下的兩個變數計算真實的寬高值 int width = 0; int height= 0; //每一行的寬度和高度 int lineWidth = 0; int lineHeight = 0; //獲取子檢視 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); //只有呼叫瞭如下的方法,方可計運算元檢視的測量的寬高 measureChild(childView,widthMeasureSpec,heightMeasureSpec); //獲取子檢視的寬高 int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); //要想保證可以獲取子檢視的邊距引數物件,必須重寫generateLayoutParams() MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams(); if (lineWidth + childWidth + mp.leftMargin+mp.rightMargin<widthSize){//不換行 lineWidth += childWidth + mp.leftMargin+mp.rightMargin; lineHeight = Math.max(lineHeight,childHeight+mp.topMargin+mp.bottomMargin); }else {//換行 width = Math.max(width,lineWidth); height+=lineHeight; //重置更新一行的寬高 lineWidth = childWidth + mp.leftMargin+mp.rightMargin; lineHeight = childHeight+mp.topMargin+mp.bottomMargin; } //最後一個元素--如果最後一個不換行,寬高沒有計算,不準確,所以需要下面的程式碼執行計算 //不管有沒有換行,最後一行都要加上,不然,最後一行就沒有顯示了。 if (i==childCount-1){ width = Math.max(width,lineWidth); height+=lineHeight; } } //設定當前流式佈局的寬高 setMeasuredDimension(widthMode==MeasureSpec.EXACTLY?widthSize:width,heightMode==MeasureSpec.EXACTLY?heightSize:height); } //佈局:給每一個子檢視指定顯示的位置,childView.layout() private List<List<View>>allViews = new ArrayList<>();//每一行的子檢視的集合構成的集合 private List<Integer>allHeights = new ArrayList<>();//每一行的高度構成的集合。 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //一、給兩個集合新增元素 //每一行的寬度和高度 int lineWidth = 0; int lineHeight = 0; //提供一個集合,儲存一行childView List<View>lineList = new ArrayList<>(); //獲取佈局的寬度 int width = this.getMeasuredWidth(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); //獲取檢視的測量寬高、邊距 int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams(); if (lineWidth+childView.getMeasuredWidth()+mp.leftMargin+mp.rightMargin<=width){//不換行 lineList.add(childView); lineWidth+=childWidth+mp.leftMargin+mp.rightMargin; lineHeight = Math.max(lineHeight,childHeight+mp.topMargin+mp.bottomMargin); }else {//換行 allViews.add(lineList); allHeights.add(lineHeight); lineWidth = childWidth+mp.leftMargin+mp.rightMargin; lineHeight = childHeight+mp.topMargin+mp.bottomMargin; lineList = new ArrayList<>(); lineList.add(childView); } if (i == childCount-1){//如果是最後一個元素 allViews.add(lineList); allHeights.add(lineHeight); } } //二、給每一個子檢視指定顯示的位置 int x=0; int y=0; for (int i = 0; i < allViews.size(); i++) {//每遍歷一次,對應一行元素 List<View>lineViews = allViews.get(i);//取出當前行構成的集合 for (int j = 0; j < lineViews.size(); j++) { View childView = lineViews.get(j); int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams(); int left = x + mp.leftMargin; int top = y + mp.topMargin; int right = left + childView.getMeasuredWidth(); int bottom = top + childView.getMeasuredHeight(); childView.layout(left,top,right,bottom); x+= childWidth + mp.leftMargin + mp.rightMargin; } y += allHeights.get(i); x = 0; } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { MarginLayoutParams mp = new MarginLayoutParams(getContext(), attrs); return mp; } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.willkong.p2pclient.fragment.ProductListFragment">

    <com.willkong.p2pclient.ui.FlowLayout
        android:id="@+id/flow_hot"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_blue_light">
        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="你是我心內的一首歌"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="濤聲依舊"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="夜夜"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="月落烏啼霜滿天"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="哇塞"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="word天哪"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="你咋不上天呢"
        android:layout_margin="10dp"
        android:textSize="20sp" />


        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="你想怎樣"
        android:layout_margin="10dp"
        android:textSize="20sp" />

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="夜曲"
        android:layout_margin="10dp"
        android:textSize="20sp" />
    </com.willkong.p2pclient.ui.FlowLayout>
</LinearLayout>

需要注意的是,要想保證可以獲取子檢視的邊距引數物件,必須重寫generateLayoutParams()方法。

動態載入資料:


import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.loopj.android.http.RequestParams;
import com.willkong.p2pclient.R;
import com.willkong.p2pclient.common.BaseFragment;
import com.willkong.p2pclient.ui.FlowLayout;
import com.willkong.p2pclient.util.DrawUtils;
import com.willkong.p2pclient.util.UIUtils;

import java.util.Random;

import butterknife.Bind;

public class ProductHotFragment extends BaseFragment {
    @Bind(R.id.flow_hot)
    FlowLayout flowHot;
    private String[] datas = new String[]{"新手福利計劃", "財神道90天計劃", "矽谷計劃", "30天理財計劃", "180天理財計劃", "月月升", "中情局投資商業經營", "大學老師購買車輛", "屌絲下海經商計劃", "美人魚影視拍攝投資", "Android培訓老師自己週轉", "養豬場擴大經營",
            "旅遊公司擴大規模", "摩托羅拉洗錢計劃", "鐵路局回款計劃", "屌絲迎娶白富美計劃"
    };

    @Override
    protected RequestParams getParams() {
        return null;
    }

    @Override
    protected String getUrl() {
        return null;
    }

    @Override
    protected void initData(String content) {
        for (int i = 0; i < datas.length; i++) {
            final TextView tv = new TextView(getContext());
            tv.setText(datas[i]);
            ViewGroup.MarginLayoutParams mp = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            mp.leftMargin = UIUtils.dp2px(10);
            mp.topMargin = UIUtils.dp2px(10);
            mp.rightMargin = UIUtils.dp2px(10);
            mp.bottomMargin = UIUtils.dp2px(10);
            tv.setLayoutParams(mp);//設定邊距
            int padding = UIUtils.dp2px(5);
            tv.setPadding(padding,padding,padding,padding);//設定內邊距
            tv.setTextSize(UIUtils.dp2px(5));

            Random random = new Random();
            int red = random.nextInt(211);
            int green = random.nextInt(211);
            int blue = random.nextInt(211);
            //設定背景
//            tv.setBackground(DrawUtils.getDrawable(Color.rgb(red,green,blue),UIUtils.dp2px(5)));
            //設定具有選擇器的背景
            tv.setBackground(DrawUtils.getSelector(DrawUtils.getDrawable(Color.rgb(red,green,blue),UIUtils.dp2px(5)),DrawUtils.getDrawable(Color.WHITE,UIUtils.dp2px(5))));
            //設定textView是可點選的
//            tv.setClickable(true);
            tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    UIUtils.toast(tv.getText().toString().trim(),false);
                }
            });

            flowHot.addView(tv);
        }
    }

    @Override
    protected void initTitle() {

    }

    @Override
    public int getLayoutId() {
        return R.layout.fragment_product_hot;
    }
}

DrawUtils.class


import android.annotation.SuppressLint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
public class DrawUtils {
    @SuppressLint("WrongConstant")
    public static Drawable getDrawable(int rgb, int radius){
        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setColor(rgb);
        gradientDrawable.setGradientType(GradientDrawable.RECTANGLE);//矩形
        gradientDrawable.setCornerRadius(radius);//四周圓角半徑
        gradientDrawable.setStroke(UIUtils.dp2px(1),rgb);//邊框厚度與顏色
        return gradientDrawable;
    }

    public static StateListDrawable getSelector(Drawable normalDrawable,Drawable pressDrawable){
        StateListDrawable stateListDrawable = new StateListDrawable();
        //給當前的顏色選擇器新增選中圖片選中指向狀態,未選中圖片指向狀態
        stateListDrawable.addState(new int[]{android.R.attr.state_enabled,android.R.attr.state_pressed},pressDrawable);
        stateListDrawable.addState(new int[]{android.R.attr.state_enabled},normalDrawable);
        //設定預設狀態
        stateListDrawable.addState(new int[]{},normalDrawable);
        return stateListDrawable;
    }
}