建立自定義檢視

如果你需要完全自定義的檢視,則需要子類 View(所有 Android 檢視的超類)並提供自定義大小(onMeasure(...))和繪圖(onDraw(...))方法:

  1. 建立自定義檢視框架: 對於每個自定義檢視,這基本相同。在這裡,我們為自定義檢視建立骨架,可以繪製一個名為 SmileyView 的笑臉:

    public class SmileyView extends View {
        private Paint mCirclePaint;
        private Paint mEyeAndMouthPaint;
    
        private float mCenterX;
        private float mCenterY;
        private float mRadius;
        private RectF mArcBounds = new RectF();
    
        public SmileyView(Context context) {
            this(context, null, 0);
        }
    
        public SmileyView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SmileyView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initPaints();
        }
    
        private void initPaints() {/* ... */}
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {/* ... */}
    
        @Override
        protected void onDraw(Canvas canvas) {/* ... */}
    }
    
  2. 初始化你的顏料: Paint 物件是虛擬畫布的畫筆,用於定義幾何物件的渲染方式(例如顏色,填充和描邊樣式等)。在這裡,我們建立了兩個 Paints,一個用於圓圈的黃色填充繪圖和一個用於眼睛和嘴巴的黑色筆觸繪圖:

    private void initPaints() {
        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setColor(Color.YELLOW);
        mEyeAndMouthPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mEyeAndMouthPaint.setStyle(Paint.Style.STROKE);
        mEyeAndMouthPaint.setStrokeWidth(16 * getResources().getDisplayMetrics().density);
        mEyeAndMouthPaint.setStrokeCap(Paint.Cap.ROUND);
        mEyeAndMouthPaint.setColor(Color.BLACK);
    }
    
  3. 實現你自己的 onMeasure(...) 方法: 這是必需的,以便父佈局(例如 FrameLayout)可以正確對齊你的自定義檢視。它提供了一組 measureSpecs,你可以使用它來確定檢視的高度和寬度。在這裡,我們通過確保高度和寬度相同來建立一個正方形:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int w = MeasureSpec.getSize(widthMeasureSpec);
        int h = MeasureSpec.getSize(heightMeasureSpec);
    
        int size = Math.min(w, h);
        setMeasuredDimension(size, size);
    }
    

    請注意,onMeasure(...) 必須至少包含一次對 setMeasuredDimension(..) 的呼叫,否則你的自定義檢視將與 IllegalStateException 一起崩潰。

  4. 實現你自己的 onSizeChanged(...) 方法: 這允許你捕獲自定義檢視的當前高度和寬度,以正確調整渲染程式碼。這裡我們只計算我們的中心和半徑:

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        mRadius = Math.min(w, h) / 2f;
    }
    
  5. 實現自己的 onDraw(...) 方法: 這是實現檢視的實際渲染的地方。它提供了一個可以繪製的 Canvas 物件( 有關所有可用的繪圖方法,請參閱官方 Canvas 文件)。

    @Override
    protected void onDraw(Canvas canvas) {
        // draw face
        canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
        // draw eyes
        float eyeRadius = mRadius / 5f;
        float eyeOffsetX = mRadius / 3f;
        float eyeOffsetY = mRadius / 3f;
        canvas.drawCircle(mCenterX - eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius, mEyeAndMouthPaint);
        canvas.drawCircle(mCenterX + eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius, mEyeAndMouthPaint);
        // draw mouth
        float mouthInset = mRadius /3f;
        mArcBounds.set(mouthInset, mouthInset, mRadius * 2 - mouthInset, mRadius * 2 - mouthInset);
        canvas.drawArc(mArcBounds, 45f, 90f, false, mEyeAndMouthPaint);
    }
    
  6. 將自定義檢視新增到佈局: 自定義檢視現在可以包含在你擁有的任何佈局檔案中。在這裡,我們將其包裝在 FrameLayout 中:

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.example.app.SmileyView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    

請注意,建議在檢視程式碼完成後構建專案。如果不構建它,你將無法在 Android Studio 的預覽螢幕上看到該檢視。

將所有內容放在一起後,在啟動包含上述佈局的活動後,你將看到以下螢幕:

https://i.stack.imgur.com/0yhjv.jpg