Android 创建自定义视图

示例

如果需要完全自定义的视图,则需要子类View(所有Android视图的超类),并提供自定义的sizing(onMeasure(...))和drawing(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) {
       // 画脸
       canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
       // 吸引眼球
       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);
       // 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的预览屏幕上查看视图。

将所有内容放在一起后,启动包含上述布局的活动后,应该会出现以下屏幕: