流式佈局控制元件的編寫
阿新 • • 發佈:2019-02-09
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;
}
}