Android自定義View注意事項

Android自定義View系列

自定義View的分類

  • 繼承View重寫onDraw方法

主要用於實現不規則的效果,即這種效果不方便經過佈局的組合方式來實現。至關於就是得本身「畫」了。採用這種方式須要本身支持wrap_content,padding也須要本身處理canvas

  • 繼承ViewGroup派生特殊的Layout

主要用於實現自定義的佈局,看起來很像幾種View組合在一塊兒的時候,可使用這種方式。這種方式須要合適地處理ViewGroup的測量和佈局,並同時處理子元素的測量和佈局過程。好比自定義一個自動換行的LinerLayout等。微信

  • 繼承特定的View,好比TextView

這種方法主要是用於擴展某種已有的View,增長一些特定的功能。這種方法比較簡單,也不須要本身支持wrap_content和padding。ide

  • 繼承特定的ViewGroup,好比LinearLayout

這種方式也比較常見,和上面的第2種方法比較相似,第2種方法更佳接近View的底層。佈局

自定義View有多種方式,須要根據實際須要選擇一種簡單低成本的方式來實現post

自定義View須要注意的地方

  • 讓View支持wrap_content

直接繼承View和ViewGroup的控件須要在onMeasure方法中處理wrap_content的方法。處理方法是在wrap_content的狀況下設置一個固定的尺寸動畫

//處理wrap_content的套路
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    //處理WAP_CONTENT
    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
        setMeasuredDimension(200,200);
    }else if (widthSpecMode == MeasureSpec.AT_MOST) {
        setMeasuredDimension(200, heightSize);
    }else if (heightSpecMode == MeasureSpec.AT_MOST) {
        setMeasuredDimension(widthSize, 200);
    }
}
  • 讓View支持padding

直接繼承View的控件須要在onDraw方法中處理padding,不然用戶設置padding屬性就不會起做用。直接繼承ViewGroup的控件須要在onMeasure和onLayout中考慮padding和子元素的margin對其形成的影響,否則將致使padding和子元素的margin失效。spa

@Override
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //獲取padding,而後根據實際狀況處理就好
    mPaddingLeft = getPaddingLeft();
    mPaddingRight = getPaddingRight();
    mPaddingTop = getPaddingTop();
    mPaddingBottom = getPaddingBottom();
    mWidth = getWidth() - mPaddingLeft - mPaddingRight;
    mHeight = getHeight() - mPaddingTop - mPaddingBottom;
}
  • 儘可能不要在View中使用Handler

View中已經提供了post系列方法,徹底能夠替代Handler的做用。線程

@UiThread
public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
        
    ...
        
    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
    
        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }

    public boolean postDelayed(Runnable action, long delayMillis) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.postDelayed(action, delayMillis);
        }
    
        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().postDelayed(action, delayMillis);
        return true;
    } 
    
    ...
}
  • View中若是有線程或者動畫,須要及時中止

在View的onDetachedFromWindow方法能夠中止線程和動畫,由於當View被remove或是包含此View的Activity退出時,就會調用View的onDetachedFromWindow方法。若是不處理的話極可能會致使內存泄漏code

  • View帶有滑動嵌套時,須要處理好滑動衝突問題對象

  • 在View的onDraw方法中不要建立太多的臨時對象,也就是new出來的對象。由於onDraw方法會被頻繁調用,若是有大量的臨時對象,就會引發內存抖動,影響View的效果


今天你進步了嘛?歡迎關注個人微信公衆號,和我一塊兒天天進步一點點!
相關文章
相關標籤/搜索