Android 自定義流式佈局(快速實現)
阿新 • • 發佈:2018-12-17
首先先寫一個自定義的類繼承viewgroup,程式碼如下
package com.demo.com.jd_zhang.ui.customview; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2018/9/25. */ public class FlowGroupView extends ViewGroup { /** * 儲存所有的view 按行記錄 */ private List<List<View>> mAllViews = new ArrayList<List<View>>(); /** * 記錄每一行的高度 */ private List<Integer> mLineHeight = new ArrayList<Integer>(); private String TAG = "TAG"; public FlowGroupView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public FlowGroupView(Context context, AttributeSet attrs) { super(context, attrs); } public FlowGroupView(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mAllViews.clear(); mLineHeight.clear(); //得到上級容器為其推薦的寬高和計算模式 int specWidthMode = MeasureSpec.getMode(widthMeasureSpec); int specHeighMode = MeasureSpec.getMode(heightMeasureSpec); int specWidthSize = MeasureSpec.getSize(widthMeasureSpec); int specHeighSize = MeasureSpec.getSize(heightMeasureSpec); int width = 0; int height = 0; // 得到子view的個數 int cCount = getChildCount(); /** * 記錄每一行的寬度,width不斷取最大寬度 */ int lineWidth = 0; /** * 每一行的高度,累加至height */ int lineHeight = 0; // 儲存每一行所有的childView List<View> lineViews = new ArrayList<View>(); for (int i = 0; i < cCount; i++) { // 得到每個子View View child = getChildAt(i); // 測量每個子View的寬高 measureChild(child, widthMeasureSpec, heightMeasureSpec); // 當前子view的lp MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); // 子view的寬和高 int cWidth = 0; int cheight = 0; cWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; cheight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; lineHeight = cheight; if (lineWidth + cWidth > specWidthSize) { width = Math.max(lineWidth, cWidth); lineWidth = cWidth; mAllViews.add(lineViews); mLineHeight.add(cheight); lineViews = new ArrayList<>(); lineViews.add(child); height += cheight; Log.e("需要換行", "hight--" + height); Log.e("onMeasure", "AllViews.size() -- > " + mAllViews.size()); } else { lineWidth += cWidth; Log.e("不需要換行", "hight--" + height); lineViews.add(child); } if (i == cCount - 1) { // 如果是最後一個view width = Math.max(lineWidth, cWidth); height += cheight; Log.e("最後一個view", "hight--" + height); } } mLineHeight.add(lineHeight); mAllViews.add(lineViews); setMeasuredDimension( specWidthMode == MeasureSpec.EXACTLY ? specWidthSize : width, specHeighMode == MeasureSpec.EXACTLY ? specHeighSize : height ); Log.e("onMeasure", "mAllViews.size() -- > " + mAllViews.size() + " mLineHeight.size() -- > " + mLineHeight.size() + "Height -- > " + height); } /** * 所有childView的位置的佈局 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int lineHeight = 0; List<View> lineViews = new ArrayList<View>(); int left = 0; int top = 0; int lineNums = mAllViews.size(); for (int i = 0; i < lineNums; i++) { lineViews = mAllViews.get(i); lineHeight = mLineHeight.get(i); Log.e("onLayout", "第" + i + "行 :" + lineViews.size() + "-------lineHeight" + lineHeight); // 遍歷當前行所有的View for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); //計算childView的left,top,right,bottom int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin; } left = 0; top += lineHeight; } Log.v("onLayout", "onLayout mAllViews.size() -- > " + mAllViews.size() + " mLineHeight.size() -- > " + mLineHeight.size()); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
然後在activity裡引用
private ArrayList<String> names; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search); ButterKnife.bind(this); setTwoFlowLayout(); } private void setTwoFlowLayout() { //新增資料 names = new ArrayList<String>(); names.add("筆記本"); names.add("空氣進化器"); names.add("空調"); names.add("電腦"); names.add("華為"); names.add("小米"); names.add("機械誡命"); names.add("vivo"); //為佈局新增內容 for (int i = 0; i < names.size(); i++) { addTextView(names.get(i)); } } /** * 動態添加布局 * * @param str */ private void addTextView(String str) { TextView child = new TextView(this); ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT, ViewGroup.MarginLayoutParams.WRAP_CONTENT); params.setMargins(5, 5, 5, 5); child.setLayoutParams(params); child.setBackgroundResource(R.drawable.flag); child.setText(str); child.setTextColor(Color.WHITE); initEvents(child);//監聽 myFlowLayout.addView(child); } // /** // * 為每個view 新增點選事件 // */ private void initEvents(final TextView tv) { tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(SearchActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show(); Intent intent2 = new Intent(SearchActivity.this, ProductDetailsActivity.class); intent2.putExtra("name", tv.getText().toString()); startActivity(intent2); } }); }