自定义View入门 --转载自武老师博客160303

原文地址:http://blog.csdn.net/risky78125/article/details/50609538


自定义View入门

long time no see,这次写一个灰常简单的一个自定义的view.当然,虽然说简单,但是麻雀虽小五脏俱全,自定义view的流程基本涵盖了.

从简单入手,然后大致了解一下view的绘制过程.这个view有多简单呢,实际上咱们就画一个圆,然后上个色.

下面开始:
public class CircleView extends View {

    private static final String TAG = "CircleView";    /**
     * 定义一个默认的圆形颜色
     */
    private static final int DEFAULT_COLOR = Color.GRAY;    /**
     * 圆形的颜色
     */
    private int color = DEFAULT_COLOR;    /**
     * 画笔
     */
    private Paint mPaint;    public CircleView(Context context) {        this(context, null);
    }    public CircleView(Context context, AttributeSet attrs) {        this(context, attrs, 0);
    }    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);
        initPaint();
    }    private void initPaint() {        // 设置画笔抗锯齿,可以让图形的边缘更平滑.如果需要画的图形四四方方的那就没必要设置了
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        // 设置画笔的颜色
        mPaint.setColor(color);
    }    @Override
    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        // 获取控件本身的宽和高,并选择较短的一边的一半作为圆的半径
        int width = getWidth();        int height = getHeight();        int radius = Math.min(width, height) / 2;        // 画圆,前两个参数确定圆心的位置,之后圆的半径,画笔
        canvas.drawCircle(width / 2, height / 2, radius, mPaint);
    }
}123456789101112131415161718192021222324252627282930313233343536373839404142434445

很简单吧,那么看一下布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:orientation="vertical">

    <com.lanou3g.drawview.widget.CircleView        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/></LinearLayout>12345678910111213

布局也非常简单对吧,那好,看一下预览,还算是正常的吧

这里写图片描述

那好,接下来,咱们自定义一下这个圆圈的颜色,也就是需要在布局中有一条属性,可以控制这个view的颜色.
创建自定义属性文件,在res/values下,创建一个资源文件,命名为attrs,如下图:

这里写图片描述

文件里面就可以创建自定义的属性,继续贴代码:
<?xml version="1.0" encoding="utf-8"?><resources>
    <!--一般来说,为某个控件自定义属性,name就跟控件名字一样-->
    <declare-styleable name="CircleView">
        <!--定义一条属性叫circleColor,规定参数填颜色值-->
        <attr name="circleColor" format="color"/>
    </declare-styleable></resources>12345678

属性定义好了,就可以到代码中把颜色值取出,然后设置给画笔就可以了,继续代码
public class CircleView extends View {
    /** 这部分代码与上文一样,省略... */
    public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        // 获取自定义属性
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleView);        // 取出对应的值设置给color,并提供一个默认值
        color = a.getColor(R.styleable.CircleView_circleColor, DEFAULT_COLOR);
        initPaint();
    }    private void initPaint() {        // 设置画笔抗锯齿,可以让图形的边缘更平滑.如果需要画的图形四四方方的那就没必要设置了
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        // 设置画笔的颜色
        mPaint.setColor(color);
    }    /** 画圆部分与上文一样,省略 */}12345678910111213141516171819

自定义的属性获取就写完了.然后在布局文件中,设置命名空间,目的为可以获取到自定义的属性,然后在CircleView中使用自定义的属性为圆上色.当然,命名空间的名字我写的是view,这个可以根据自己的爱好命名.
<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:orientation="vertical">

    <com.lanou3g.drawview.widget.CircleView        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        view:circleColor="#0088ff"/></LinearLayout>123456789101112131415

ok,看预览,可以看到颜色咱们可以自定义了

这里写图片描述

实 际上这个自定义的控件是灰常不专业的,不知道大家注意到没有.咱们在布局文件中给这个控件设置的宽高都为wrap_content,那显示成这么大肯定是 不正常的.实际上虽然给的是wrap_content,但是系统是按照match_parent来计算的.那为什么会出现这种情况呢?给10秒钟大家思考 一下
try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }12345

思考完了吧,那记住一句话就得了,对于直接继承自view的自定义组件,如果不在代码中对wrap_content进行处理,那么系统就会把它理解成match_parent,呵呵哒,气人不.
那接下来,咱们就处理一下吧.在自定义组件中,重写onMeasure()这个方法,处理的过程就在此方法中.思路就是,如果布局中的宽或高设置成了wrap_content,那么对应的宽高就给设置成188.
/** 其他部分的代码省略 */@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(188,188);
        }else if (widthMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(188,heightSize);
        }else if (heightMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSize,188);
        }
    }12345678910111213141516

接下来再看一下预览(PS:Android Studio真是个好东西)
<com.lanou3g.drawview.widget.CircleView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        view:circleColor="#0088ff"/>1234

这里写图片描述

接下来另一个问题,写到现在这个程度的时候,大家可以试一下给这个控件加上margin属性和padding属性,看一下效果,给大家半个小时尝试一下
    try {
            Thread.sleep(30 * 60 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }12345

擦擦擦

/** Application Not Responding !!!!! */1

实 际结果是,margin是生效的,而padding是不会生效的.因为margin属性是由父容器控制的,所以会生效.而padding是控件本身控制 的,咱们没有进行处理,所有是无效的.那么接下来,继续处理一下padding.处理的过程也非常简单,在绘制的过程中,考虑一下padding即可.那 么修改一下onDraw方法,如下:
@Override
    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        // 获取padding值
        int paddingLeft = getPaddingLeft();        int paddingRight = getPaddingRight();        int paddingTop = getPaddingTop();        int paddingBottom = getPaddingBottom();        // 获取控件本身的宽和高,并选择较短的一边的一半作为圆的半径.计算时将padding考虑进去
        int width = getWidth() - paddingLeft - paddingRight;        int height = getHeight() - paddingTop - paddingBottom;        int radius = Math.min(width, height) / 2;        // 画圆,前两个参数确定圆心的位置,之后圆的半径,画笔
        canvas.drawCircle(paddingLeft + width / 2, paddingTop + height / 2, radius, mPaint);
    }123456789101112131415

布局文件
<com.lanou3g.drawview.widget.CircleView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:paddingTop="5dp"
        android:paddingBottom="20dp"
        view:circleColor="#0088ff"/>1234567

预览

这里写图片描述


转载于:https://my.oschina.net/u/2531415/blog/639721

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值