Android 自定义控件之画篮球

对于Android开发者来说,自定义控件听起来是一件高大上的事,但同时呢也让大多数开发者感到怯步,正所谓会者不难,难者不会,只要经过学习,练习,自定义控件也很简单。最近NBA正在打的火热,今天就简单地画个篮球,感受感受自定义控件这只纸老虎。

一、先上效果图:


二、分三步走:

1.自定义属性

2.自定义View

3.使用自定义View

三、第一步:自定义属性

res --> values 下新建attrs.xml文件(有则不用新建),代码如下:

<resources>

    <declare-styleable name="CustomProgressBar">
        <attr name="firstColor" format="color" />
        <attr name="secondColor" format="color" />
        <attr name="circleWidth" format="dimension" />
        <attr name="speed" format="integer" />
    </declare-styleable>

</resources>

解释一下上面:

1.name="CustomProgressBar":这个name值可以随便写,没有特定要求,不过一般写成自定义View的类名(后面介绍),便于标识。

2.<attr name="firstColor" format="color" />:每一个代表一个属性,在布局中会用到;name为属性名,format为该属性的类型定义,定义该属性是一个颜色类型,还是尺寸大小类型,还是一个图片,亦或是其他类型。

四、自定义View:

package com.dapeng.demo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by dapeng on 2017/6/13.
 */

public class CustomProgressBar extends View {
    //底色
    private int mFirstColor;
    //进度的颜色
    private int mSecondColor;
    //圈的宽度
    private int mCircleWidth;
    //画笔
    private Paint mPaint;
    //当前进度
    private int mProgress;
    //速度
    private int mSpeed;

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

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

    /**
     * 必要的初始化,获得一些自定义的值
     *
     * @param context
     * @param attrs
     * @param defStyle
     */
    public CustomProgressBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        //获取自定义属性的值
        TypedArray arrs = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar, defStyle, 0);
        mFirstColor = arrs.getColor(R.styleable.CustomProgressBar_firstColor, Color.GREEN);
        mSecondColor = arrs.getColor(R.styleable.CustomProgressBar_secondColor, Color.RED);
        mCircleWidth = arrs.getDimensionPixelSize(R.styleable.CustomProgressBar_circleWidth, 20);
        mSpeed = arrs.getInt(R.styleable.CustomProgressBar_speed, 100);
        arrs.recycle();

        mPaint = new Paint();
        mProgress = 0;

        startDraw();

    }

    /**
     * 利用定时器来画
     */
    private void startDraw() {
        final Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                if (mProgress == 360) {
                    timer.cancel();
                    return;
                }
                mProgress++;
                postInvalidate();
            }
        };
        timer.schedule(task, 0, mSpeed);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        float centreX = getWidth() / 2; // 圆心的x坐标
        float centreY = getHeight() / 2; // 圆心的y坐标
        float radius = centreX - 20;// 半径
        mPaint.setStrokeWidth(mCircleWidth); // 设置画笔的粗细宽度(即圆环的宽度)
        mPaint.setAntiAlias(false); // 消除锯齿
        mPaint.setStyle(Paint.Style.STROKE); // 设置空心
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置画笔线条两头为圆头

        mPaint.setColor(mFirstColor); // 设置底色
        canvas.drawCircle(centreX, centreY, radius, mPaint); // 画出圆环
        RectF oval2 = new RectF(centreX - radius, centreY - radius / 2, centreX + radius, centreY + radius / 2); // 用于定义圆弧的形状和大小的界限
        canvas.drawOval(oval2, mPaint);//画出椭圆
        canvas.drawLine(centreX - radius, centreY, centreX + radius, centreY, mPaint);//画直线

        mPaint.setColor(mSecondColor); // 设置进度的颜色
        RectF oval = new RectF(centreX - radius, centreY - radius, centreX + radius, centreY + radius); // 用于定义圆弧的形状和大小的界限
        canvas.drawArc(oval, 0, mProgress, false, mPaint); // 根据进度画圆弧
        canvas.drawArc(oval2, 0, mProgress, false, mPaint); // 根据进度画圆弧
        canvas.drawLine(centreX - radius, centreY, centreX - radius + (radius * 2) / 360 * mProgress, centreY, mPaint);//根据进度画直线
    }
}

代码中的注释已经很清楚了,我在这再简单说明一下:

xml布局文件中使用这个自定义View会调用拥有两个参数的构造函数,在这让其再调用三个参数的构造函数,在构造函数中获取自定义属性的值,然后利用定时器不断地去画篮球。要想把篮球画到手机界面,就得重写onDraw()方法,把画篮球的动作放在onDraw()中,而startDraw()方法中的postInvalidate();的作用就是不断地调用onDraw()方法进行重绘。

Ondraw()方法中的代码都很简单,不过有一个RectF类我得给大家介绍一下:


源码中的注释是这么解释的:RectF为一个矩形保存四个float坐标。矩形是由它的4条边(左,上,右下)的坐标表示的。可以直接访问这些字段。使用width()height()来检索矩形的宽度和高度。注意:大多数方法都不检查是否正确地排列了坐标(例如,左小于等于右和顶部小于等于底部)


如图所示:这个类是给准备要画的圆弧确定一个范围,传进去的四个参数left,top,right,bottom,确定一个矩形,然后在矩形的内部画正切椭圆

canvas.drawArc(oval, 0, mProgress, false, mPaint);这段代码就是用来画圆弧的,第一个参数就是RectF类型的,就是确定要画的圆弧的整体轨迹;第二个参数为起点,就是你想让这个圆弧从哪开始画(0代表起点在right处,-90代表起点在top处);第三个参数是这个圆弧两点之间的角度,确定圆弧的长度;第四个参数表示是否要画半径,false表示就只画一段圆弧,true会把两条半径也画出来,就是一个扇形;第五个参数就是画笔。

五、在布局中使用自定义View

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dapeng="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.dapeng.demo.CustomProgressBar
        android:id="@+id/CustomProgressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        dapeng:circleWidth="10dp"
        dapeng:firstColor="#FF000000"
        dapeng:secondColor="#FFA7433C"
        dapeng:speed="30" />
</RelativeLayout>

注意要加上这行代码:xmlns:dapeng="http://schemas.android.com/apk/res-auto",否则dapeng这个关键字不起作用。当然你也可以改为你想要的字段。


源码下载:http://download.csdn.net/detail/u012604745/9869190

猜你喜欢

转载自blog.csdn.net/u012604745/article/details/73174772
今日推荐