android學習8#--自定義View之view類簡單分析

前面幾節做了這麼多鋪墊,終於要掀開自定義view的廬山真面目了。

View繪製過程

android學習5#–自定義View之座標系統中我就提到過View的顯示必須經歷Measure(測量)、Layout(佈局)和Draw(繪製)過程。具體可以參考官方:How Android Draws Views

  • Measure
    繪製前通過measure()方法先做一次測量,算出自己view的width和high,官網是這麼描述measure()的:The actual measurement work of a view is performed in onMeasure(int, int), called by this method. Therefore, only onMeasure(int, int) can and must be overridden by subclasses. 意思是measure()實際上是通過調用onMeasure()方法來測量。而且子類如果想自己實現測量,只能通過重寫onMeasure()方法來實現自定義view的測量。
  • Layout
    經過測量後,確定再有layout()方法確定在屏幕的位置。
    官網如此說:This is the second phase of the layout mechanism. (The first is measuring). In this phase, each parent calls layout on all of its children to position them. This is typically done using the child measurements that were stored in the measure pass().
    Derived classes should not override this method. Derived classes with children should override onLayout. In that method, they should call layout on each of their children.
    主要意思是layout()方法是view繪製的第二步(第一步是測量),同時也提供了onLayout()方法給子類重寫。
  • Draw
    必須經過前面的測量、佈局,才能進入繪製。官網如是說:
    Manually render this view (and all of its children) to the given Canvas. The view must have already done a full layout before this function is called. When implementing a view, implement onDraw(android.graphics.Canvas) instead of overriding this method. If you do need to override this method, call the superclass version.
    意思是說draw()方法會在佈局完成後調用,另外需要注意的是自定義view時,可以通過重寫onDraw()方法來實現繪製,但是重寫onDraw()方法時記得調用父類方法。

View類學習

瞭解了view的繪製過程後,我們再回到起點,既然我們自定義的view類必須繼承view,有必要了解view類的構造函數,掌握了它才知道如何設計自己的view類,

  • view():查看源碼如此註釋說:Non-public constructor for use in testing。用於測試中的非公共構造函數。
  • view(Context context):源碼如此註釋說:Simple constructor to use when creating a view from code.意思是從code上創建時會調用此函數。
  • view(Context context, AttributeSet attrs):源碼如此註釋說:Constructor that is called when inflating a view from XML。意思是view組件是從xml上加載佈局繪製時,調用此回調。
  • View(Context context, AttributeSet attrs, int defStyleAttr):跟第3種一樣,只是增加了style屬性設置。通過查看源碼可以看出第3中構造函數最後調用的是此構造函數。因此這個接口不會在創建view時自動創建,而是認爲手動加載新的style時纔會調用。
  • View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) :與第4種一樣,查看源碼發現第3種構造函數實際調用的是此函數。一時不知道如何講這個函數,後續碰到有用到此構造函數再說吧。

自定義view創建

到此,相信應該或多或少有了一定的概念了,先來看看本例的源碼:

public class CustomText extends View {
    private Paint mPaint;
    private Rect mBound;

    private int mTextColor;
    private float mTextSize;
    private String mTextTitle;
    private Bitmap mBg;

    private static final String TAG = CustomText.class.getSimpleName();

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

    public CustomText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomText(Context context, AttributeSet attrs, int defSytleAttr) {
        super(context, attrs, defSytleAttr);

        TypedArray typeArry = context.obtainStyledAttributes(attrs, R.styleable.CustomText);

        Log.d(TAG, "CustomText_texttitle: " + R.styleable.CustomText_texttitle);
        Log.d(TAG, "CustomText_textcolor: " + R.styleable.CustomText_textcolor);
        Log.d(TAG, "CustomText_textsize: " + R.styleable.CustomText_textsize);

        mTextTitle = typeArry.getString(R.styleable.CustomText_texttitle);
        mTextColor = typeArry.getColor(R.styleable.CustomText_textcolor, 0xff00ff00);
        mTextSize = typeArry.getDimension(R.styleable.CustomText_textsize, 36);
        int resourceId = typeArry.getResourceId(R.styleable.CustomText_textbackground, 0);
        mBg = BitmapFactory.decodeResource(getResources(), resourceId);
        typeArry.recycle();

        mPaint = new Paint();
        mPaint.setTextSize(mTextSize);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(10);

        mBound = new Rect();
        mPaint.getTextBounds(mTextTitle, 0, mTextTitle.length(), mBound);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
       // mBg = Bitmap.createScaledBitmap(mBg, getMeasuredWidth(), getMeasuredHeight(), false);
      //  canvas.drawBitmap(mBg,0, 0, null);

        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(110,150,60,mPaint);

        mPaint.setColor(Color.YELLOW);
        canvas.drawCircle((float)175.5, 210, 60, mPaint);

        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(245, 150, 60, mPaint);

        mPaint.setColor(Color.GREEN);
        canvas.drawCircle(311, 210, 60, mPaint);

        mPaint.setColor(Color.RED);
        canvas.drawCircle(380, 150, 60, mPaint);

        mPaint.setColor(mTextColor);
        canvas.drawText(mTextTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);

    }
}

上面的三個構造函數相信不用再講解了吧。本節就到這裏吧,下節再講講如何真正繪製view。

參考:

http://www.jianshu.com/p/84cee705b0d3#
http://blog.csdn.net/u011733020/article/details/50849475
http://blog.chinaunix.net/uid-26885609-id-3479671.html
http://www.cnblogs.com/angeldevil/p/3479431.html#two
http://blog.csdn.net/yuzhouxiang/article/details/6958017

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章