1. 程式人生 > >android--------自定義控件 之 ViewGroup

android--------自定義控件 之 ViewGroup

lines resolv else 指定 並且 bsp view att param

前面幾篇講了自定義控件的組合控件,地址:http://www.cnblogs.com/zhangqie/p/8985612.html

今天這篇博文主要來說說 自定義控件的 ViewGroup。

什麽是ViewGroup?

ViewGroup是一種容器。它包含零個或以上的View及子View

ViewGroup有什麽作用?

ViewGroup內部可以用來存放多個View控件,並且根據自身的測量模式,來測量View子控件,並且決定View子控件的位置。這在下面會逐步講解它是怎麽測量及決定子控件大小和位置的。

自定義控件

public class FlowLayoutb extends ViewGroup {

    
private int horizontolSpacing; private int verticalSpacing; public FlowLayoutb(Context context) { super(context); init(context); } public FlowLayoutb(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); }
private Line currentline;// 當前的行 private int useWidth = 0;// 當前行使用的寬度 private List<Line> mLines = new ArrayList<Line>(); private int width; public FlowLayoutb(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { horizontolSpacing
= Util.dip2px(13, context); verticalSpacing = Util.dip2px(13, context); } // 測量 當前控件Flowlayout // 父類是有義務測量每個子View的 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mLines.clear(); currentline = null; useWidth = 0; /** * 獲得此ViewGroup上級容器為其推薦的寬和高,以及計算模式 */ int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); // 計算出所有的childView的寬和高 measureChildren(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingBottom() - getPaddingTop(); // 獲取到寬和高 int childeWidthMode; int childeHeightMode; // 為了測量每個子View 需要指定每個子View測量規則 childeWidthMode = widthMode == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : widthMode; childeHeightMode = heightMode == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : heightMode; int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childeWidthMode, width); int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childeHeightMode, height); currentline = new Line();// 創建了第一行 for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); // 測量每個子View child.measure(childWidthMeasureSpec, childHeightMeasureSpec); int measuredWidth = child.getMeasuredWidth(); useWidth += measuredWidth;// 讓當前行加上使用的長度 if (useWidth <= width) { currentline.addChild(child);//這時候證明當前的子View是可以放進當前的行裏,放進去 useWidth += horizontolSpacing; } else { //換行 newLine(child); } } if (!mLines.contains(currentline)) { mLines.add(currentline);// 添加最後一行 } int totalheight = 0; for (Line line : mLines) { totalheight += line.getHeight(); } totalheight += verticalSpacing * (mLines.size() - 1) + getPaddingTop() + getPaddingBottom(); System.out.println(totalheight); setMeasuredDimension(width + getPaddingLeft() + getPaddingRight(), resolveSize(totalheight, heightMeasureSpec)); } private void newLine(View child) { mLines.add(currentline);// 記錄之前的行 currentline = new Line();// 創建新的一行 currentline.addChild(child); useWidth = currentline.lineWidth; } private class Line { int height = 0; //當前行的高度 int lineWidth = 0; private List<View> children = new ArrayList<View>(); /** * 添加一個子View * * @param child */ public void addChild(View child) { children.add(child); if (child.getMeasuredHeight() > height) { height = child.getMeasuredHeight(); } lineWidth += child.getMeasuredWidth(); } public int getHeight() { return height; } /** * 返回子View的數量 * * @return */ public int getChildCount() { return children.size(); } public void layout(int l, int t) { lineWidth += horizontolSpacing * (children.size() - 1); int surplusChild = 0; int surplus = width - lineWidth; if (surplus > 0 && children.size() > 0) { surplusChild = surplus / children.size(); } for (int i = 0; i < children.size(); i++) { View child = children.get(i); child.layout(l, t, l + child.getMeasuredWidth() + surplusChild, t + child.getMeasuredHeight()); l += child.getMeasuredWidth() + surplusChild; l += horizontolSpacing; } } } // 分配每個子View的位置 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { l += getPaddingLeft(); t += getPaddingTop(); for (int i = 0; i < mLines.size(); i++) { Line line = mLines.get(i); line.layout(l, t); //交給每一行去分配 t += line.getHeight() + verticalSpacing; } } }

自定義ViewGroup的步驟:

  1. 繼承ViewGroup,覆蓋構造方法
  2. 重寫onMeasure方法測量子控件和自身寬高
  3. 實現onLayout方法擺放子控件

效果圖:

技術分享圖片 技術分享圖片

源碼地址:https://github.com/DickyQie/android-custom-control

參考資料:

https://blog.csdn.net/shineflowers/article/details/48055879

https://blog.csdn.net/zxt0601/article/details/50533658

https://blog.csdn.net/shakespeare001/article/details/51089453

android--------自定義控件 之 ViewGroup