Android 自定义ViewGroup(一) 基础

来源:互联网 发布:浏览器打不开淘宝网页 编辑:程序博客网 时间:2024/04/30 17:27

转载请标注来源:KingJA码家的博客

前言


自定义ViewGroup相比较自定义View而言少了些绘制,设计者更多地是把精力放在布局上。KJ为大家初步介绍下自定义ViewGroup的设计过程。

API


  • void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

    同View一样,一般只有ViewGroup设wrap_content才重写该方法。重写时一般通过遍历调用每个子View的measure()来测量每个子View的尺寸,然后根据子View的尺寸来决定自己的尺寸。
  • void onLayout(boolean changed, int l, int t, int r, int b)

    遍历每个子View的layout()方法来设置每个字View的位置。
  • void measureChildren(int widthMeasureSpec, int heightMeasureSpec)

    遍历每个子View,让它们自己测量。
  • void setMeasuredDimension(int measuredWidth, int measuredHeight)

    设置自身的大小。
  • void layout(int l, int t, int r, int b)

    设置子View的位置

代码


下面我们通过一个自定义ViewGroup的Demo来理解下概念,Demo的功能是做一个让子View垂直排列的ViewGroup,类似LinearLayout。先上效果图:
这里写图片描述
左边是加Padding的,右边是没加Padding的。

代码较少,直接贴上来。

package kingja.com.kingja_customviewdemo;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;/** * Created by Shinelon on 2016/1/5. */public class CustomViewGroup extends ViewGroup {    private MarginLayoutParams layoutParams;    private int childCount;    public CustomViewGroup(Context context) {        this(context,null);    }    public CustomViewGroup(Context context, AttributeSet attrs) {        this(context, attrs,0);    }    public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //设置ViewGroup背景色        setBackgroundColor(0xFFEB7488);    }    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        //遍历每个子View,让它们自己测量        measureChildren(widthMeasureSpec, heightMeasureSpec);        childCount = getChildCount();        int width = 0;        int height = 0;        for (int i = 0; i < childCount; i++) {            View child = getChildAt(i);            int childWidth = child.getMeasuredWidth();            int childHeight = child.getMeasuredHeight();            layoutParams = (MarginLayoutParams) child.getLayoutParams();            height += childHeight + layoutParams.bottomMargin + layoutParams.topMargin;            //遍历每个子View,取最大的width为wrap_content下的父控件width。            width = Math.max(childWidth, width);        }        /**         * 设置ViewGroup的尺寸,最终的尺寸要要加上padding         */        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width+getPaddingLeft()+getPaddingRight(), heightMode == MeasureSpec.EXACTLY ? heightSize : height+getPaddingTop()+getPaddingBottom());    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        /**         * 第一个子View的left和top要加上Padding且要考虑每个子View的Margin         */        int initTop=getPaddingTop();        for (int i = 0; i < childCount; i++) {            View child = getChildAt(i);            int childWidth = child.getMeasuredWidth();            int childHeight = child.getMeasuredHeight();            layoutParams = (MarginLayoutParams) child.getLayoutParams();            int left = layoutParams.leftMargin+getPaddingLeft();            int top = layoutParams.topMargin+initTop;            int right = left + childWidth;            int bottom = top + childHeight;            //放置子View            child.layout(left, top, right, bottom);            initTop+=childHeight;        }    }}

后记


如果这篇文章对你有帮助,我会感到欣慰。因为我把接力棒传了下去。

0 0