自定義viewGroup

padding和margin

padding用于控制view內(nèi)容邊界與view邊界的距離對

  1. viewGroup用padding時,其作用于其子控件,控制子控件與該viewGroup的邊距
  2. view用padding時,控制view的內(nèi)容與view邊界的距離
    margin用于控制本控件子控件與父控件的邊距
  3. viewGroup用margin時,其控制本viewGroup與其他view的邊距
  4. view用margin時,其控制本view與其他view的邊距

小結(jié)

從上面的現(xiàn)象可以得出:viewGroup設置padding作用于其子view時,相當于子view設置了margin

自定義viewGroup(包含margin,padding)

public class SwipeItemLayout extends ViewGroup {

    public SwipeItemLayout(Context context) {
        super(context);
    }


    public SwipeItemLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /**
         *
         * 測量子view的大小,也可以用measureChild,需要遍歷子view
         * measureChildren內(nèi)部也是調(diào)用了measureChild方法
         * measureChildWithMargins也是同理
         */
//        measureChildWithMargins();
       // measureChild(child,widthMeasureSpec,heightMeasureSpec);
        measureChildren(widthMeasureSpec,heightMeasureSpec);

        /**
         * 得到父view的size和mode
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        /**
         * 在測量大小時,需要計算padding值,而margin值的計算是放在具體的測量中,getTotalWidth,getMaxHeight
         */
        int horPadding = getPaddingLeft() + getPaddingRight();
        int virPadding = getPaddingBottom() + getPaddingTop();

        setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? getTotalWidth()+horPadding: widthSize+horPadding,
                heightMode == MeasureSpec.AT_MOST ? getMaxHeight()+virPadding : heightSize+virPadding);
    }

    /**
     * 在計算總的寬度時,需要將子view的margin值計算進去
     * @return
     */
    private int getTotalWidth(){
        int totalWidth =0;
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
            int leftMargin = params.leftMargin;
            int rightMargin = params.rightMargin;
            int measuredWidth = view.getMeasuredWidth();
            totalWidth +=(measuredWidth + leftMargin + rightMargin);
        }
        return totalWidth;
    }


    /**
     * 計算高度時,也要將子view的margin值計算進去
     * @return
     */
    private int getMaxHeight(){
        int maxHeight =0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
            int topMargin = params.topMargin;
            int bottomMargin = params.bottomMargin;
            int actHeight = topMargin + bottomMargin +child.getMeasuredWidth();
            if (actHeight > maxHeight){
                maxHeight = actHeight;
            }
        }
        return maxHeight;
    }


    /**
     *在擺放view的過程中,主要計算view防止的l,t,r,b
     * margin和padding值其實都是空的,不屬于view
     * 
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left = getPaddingLeft();    //父view的padding值,空隙
        int right =0;
        int top = getPaddingTop();
        int bottom = getPaddingBottom();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            int height = child.getMeasuredHeight();
            int width = child.getMeasuredWidth();
            MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
            //子view的margin值
            int leftMargin = params.leftMargin;
            int rightMargin = params.rightMargin;
            int topMargin = params.topMargin;
            int bottomMargin = params.bottomMargin;
            //擺放的時候要將padding和margin加在一起的空隙都算出來,將view放在實際的位置即可
            child.layout(left+leftMargin,top+topMargin,left+leftMargin+width,top+topMargin+height);
            left +=(leftMargin+width+rightMargin);
        }
    }

   

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(),attrs);
    }

    public static class LayoutParams extends MarginLayoutParams{

        public LayoutParams(int width, int height) {
            super(width, height);
        }
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(ViewGroup.LayoutParams p) {
            super(p);
        }
    }
}

總結(jié)

  1. measure: view(這里指的是view類)自身已經(jīng)實現(xiàn)了measure方法,并且也有默認的onMeasure方法,所以我們在自定義view(這里不包括自定義viewgroup)的時候,可以重寫onMeasure方法。
    而viewGroup類是抽象類,其并沒有實現(xiàn)view類的measure方法,因此自定義viewGroup是直接使用view類的measure,其中的onMeasure方法需要我們自己去重寫,因為默認的onMeasure方法只是測量了自身的寬高并沒有去測量子view

  2. layout: 首先要明白layout方法能夠?qū)崿F(xiàn)將自身放置在正確的位置(已經(jīng)實現(xiàn)),而onlayout方法是將每個子view放置在正確的位置,在view類自身已經(jīng)實現(xiàn)了layout方法,只要傳入對應的參數(shù)就可以將自身放在對應的位置上,而在抽象類viewGroup中,將onLayout設置為抽象方法,所以在實現(xiàn)自定義viewGroup的時候就必須要實現(xiàn)對應的onlayout方法,將每個子view放置在對應的位置上(其實就是將子view的layout方法中傳入對應的參數(shù)去實現(xiàn))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容