简单的完全自定义视图(同心圆)

这篇博客探讨了在Android中如何创建自定义视图的子类,并着重讲解了测量(onMeasure()方法,包括AT_MOST, EXACTLY和UNSPECIFIED三种约束)和绘制过程。内容包括如何在无约束条件下实现视图大小的自定义,并展示了最终的同心圆绘制效果。" 115360673,10227230,深入理解Android Jetpack之Lifecycle,"['移动开发', 'Android开发', 'Jetpack', 'Lifecycle']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建 View 的子类之后,类与框架之间就有两个主要的交互需要关注:测量和绘制。

测量:

在显示视图的层次结构之前,需要调用 onMeasure() 并向该方法传递两个约束,视图应根据这两个约束来管理应具备的大小,每个约束都为 MeasureSpec 的整数封装:

AT_MOST : 视图布局参数是 wrap_content

EXACTLY : 视图布局参数是固定值;如:android:layout_width="100dp",或者指定为 match_parent。

UNSPECIFIED : 视图无约束时所需的大小,View 想多大就多大,通常在绘制自定义 View 时使用。

绘制:

对视图测量并放置在布局结构中之后,框架要为视图构造一个 Canvas 实例,调整其大小并放置在合适的位置。

效果图如下:



content_main.xml (AndroidStudio 1.5):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.crazy.customwidget.MainActivity"
    tools:showIn="@layout/activity_main">

    <com.crazy.customwidget.BullsView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

BullsView.java  (MainActivity.java 无需修改):

package com.crazy.customwidget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;

public class BullsView extends View {

    private Paint mPaint;

    private Point mCenter;
    private float mRadius;

    public BullsView(Context context) {
        this(context, null);
    }

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

    public BullsView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 创建画笔(支持锯齿)
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
        // 创建圆心
        mCenter = new Point();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int width, height;
        // 确定内容的理想大小,无约束
        int cWidth = 100;
        int mHeight = 100;

        width = getHowToGetWH(widthMeasureSpec, cWidth);
        height = getHowToGetWH(heightMeasureSpec, mHeight);

        // 使用测量必须调用该方法
        setMeasuredDimension(width, height);
    }

    /**
     * 测量宽度和高度的方法
     */
    private int getHowToGetWH(int measureSpec, int mSize) {

        int specSize = MeasureSpec.getSize(measureSpec);

        switch (MeasureSpec.getMode(measureSpec)){
            case MeasureSpec.AT_MOST:
                return Math.min(specSize, mSize);
            case MeasureSpec.UNSPECIFIED:
                return mSize;
            case MeasureSpec.EXACTLY:
                return specSize;
            default:
                return 0;
        }
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

        // 如果有变化,则复位参数
        if (w != oldw || h != oldh){
            mCenter.x = w/2;
            mCenter.y = h/2;
            mRadius = Math.min(mCenter.x, mCenter.y);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {

        // 绘制同心圆
        mPaint.setColor(Color.RED);
        canvas.drawCircle(mCenter.x, mCenter.y, mRadius, mPaint);

        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.8f, mPaint);

        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.6f, mPaint);

        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.4f, mPaint);

        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(mCenter.x, mCenter.y, mRadius * 0.1f, mPaint);
    }
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值