照着“自定义控件其实很简单”博客来学自定义view(一)

2017-05-03  本文已影响0人  仁昌居士

在有了一定的自定义view的基础了后,我现在开始了再一次重新温故和学习自定义view的知识。
From AigeStudio(http://blog.csdn.net/aigestudio/article/details/41212583)Power by Aige
根据这篇文章起,开始重学一遍。
我要做的就是这个:圆圈是会动态变化半径的。

Paste_Image.png
首先的步骤是:
如图:
Paste_Image.png
1、写自定义控件,首先就是继承View或者子类ViewGroup甚至更子类,比如:TextView,Button或者其他的第三方自定义View。
2、继承了View后,就需要重写构造方法。
Paste_Image.png
构造方法有好几个。我们主要可以重写蓝色框的这两个。第二个是用于xml的。什么用呢?
先来看一下我在xml怎么调用这个AnimationCircleView自定义view。 Paste_Image.png
我们在xml文件引用我们的AnimationCircleView自定义view时为其指定了两个android自带的两个属性:layout_width和layout_height,当我们需要使用类似的属性(比如更多的什么id啊、padding啊、margin啊之类)时必须在自定义View的构造方法中添加一个AttributeSet类型的签名来解析这些属性。所以记住,要加重写方法哦!

然后,开始准备画画了。
要画画,首先当然是需要工具了。纸笔桌伺候嘛。
纸即Canvas,俗称画布。笔即Paint,俗称画笔。桌即为初始化准备。
纸是什么纸,白纸一张。所以不用初始化。笔呢,要求当然高了。要能画出花来,5毛钱的笔可不好画。要9.9的才行。所以需要初始化画笔。桌呢,没桌子不好画图耶。
那么开始:
先initView()准备好要画图需要的桌子。

Paste_Image.png
我需要Context 和屏幕的宽、高。
然后我要挑个好一点的笔,沾点墨水。
这么多选择可以挑。
Paste_Image.png
我们挑好了。
Paste_Image.png
开始画画喽,重写onDraw()方法
canvas有很多的画画模具哦,比如:
Paste_Image.png
我们画个圆环。drawCircle表示绘制的是圆形,但是由于我们的画笔样式设置为描边,其绘制出来的就是一个圆环!其中drawCircle的前两个参数表示圆心的XY坐标,这里我们用到了一个工具类获取屏幕尺寸以便将其圆心设置在屏幕中心位置,第三个参数是圆的半径,第四个参数则为我们的画笔!
注意:
在Android中设置数字类型的参数时如果没有特别的说明,参数的单位一般都为px像素。
Paste_Image.png

好了。画完了。现在要让他动起来,怎么动。一种方式就是通过线程去不断的重绘。
线程的话,我们通过自定义view来继承接口Runnable。重写run()方法。


Paste_Image.png

而重绘呢?这时就有2个方法了。invalidate()、postInvalidate()。
invalidate()、postInvalidate(): 调用invalidate()、postInvalidate()会 界面刷新,执行 draw 过程。区别就是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。 鉴于此,如果要使用invalidate的刷新,那我们就得配合handler的使用,使异步非ui线程转到ui线程中调用,如果要在非ui线程中直接使用就调用postInvalidate方法即可,这样就省去使用handler的烦恼了。

Paste_Image.png

然后建个activity去调用它,就能实现需要的效果了。

Paste_Image.png

总代码:
xml:

<?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:orientation="vertical">

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start"/>

    <rcjs.com.customviewdemo.widget.AnimationCircleView
        android:id="@+id/circle"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

自定义view:

package rcjs.com.customviewdemo.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import rcjs.com.customviewdemo.utils.UIHelper;

/**
 * Created by 仁昌居士 on 2017/5/3.
 * Description:
 */

public class AnimationCircleView extends View implements Runnable {
    private Paint mPaint;
    private Context mContext;
    private int mWidth;
    private int mHeight;
    private int radiu;// 圆环半径

    public AnimationCircleView(Context context) {
        this(context, null);

    }

    public AnimationCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        // 初始化
        initView(context);
    }

    private void initView(Context context) {
        mContext = context;
        mWidth = UIHelper.getWindowWidthHeight(mContext)[0];
        mHeight = UIHelper.getWindowWidthHeight(mContext)[1];
        // 初始化画笔
        initPaint();
    }


    /**
     * 初始化画笔
     */
    private void initPaint() {
        // 实例化画笔并打开抗锯齿
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    /*
     * 设置画笔样式为描边,圆环嘛……当然不能填充不然就么意思了
     *
     * 画笔样式分三种:
     * 1.Paint.Style.STROKE:描边
     * 2.Paint.Style.FILL_AND_STROKE:描边并填充
     * 3.Paint.Style.FILL:填充
     */
        mPaint.setStyle(Paint.Style.STROKE);

        // 设置画笔颜色为浅灰色
        mPaint.setColor(Color.LTGRAY);

    /*
     * 设置描边的粗细,单位:像素px
     * 注意:当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
     */
        mPaint.setStrokeWidth(10);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制圆环
        canvas.drawCircle(mWidth / 2, mHeight / 2, radiu, mPaint);
    }

    @Override
    public synchronized void run() {
         /*
         * 确保线程不断执行不断刷新界面
         */
        while (true) {
            try {
                /*
                 * 如果半径小于200则自加否则大于200后重置半径值以实现往复
                 */
                if (radiu <= 200) {
                    radiu += 10;

                    // 刷新View
                    postInvalidate();// invalidate();必须在子线程里去调用,postInvalidate();会另开线程调用

                } else {
                    radiu = 0;
                }

                // 每执行一次暂停40毫秒
                Thread.sleep(40);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Activity:

package rcjs.com.customviewdemo.ui.activity;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import rcjs.com.customviewdemo.R;
import rcjs.com.customviewdemo.widget.AnimationCircleView;

/**
 * Created by 仁昌居士 on 2017/5/3.
 * Description:
 */

public class AnimationCircleActivity extends AppCompatActivity {

    @BindView(R.id.circle)
    AnimationCircleView mAnimationCircleView;
    @BindView(R.id.start)
    Button start;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animationcircle);
        ButterKnife.bind(this);
    }

    @OnClick(R.id.start)
    public void onClick(View view) {
          /*
         * 开线程
         */
        new Thread(mAnimationCircleView).start();
    }

}

好了,接下来就是看第二篇去了。

上一篇下一篇

猜你喜欢

热点阅读