[自定义控件]android自定义view实战之太极图

android自定义view实战之太极图

尊重原创,转载请注明出处: http://blog.csdn.net/qq137722697

自定义view是Android工程师进阶不可避免要接触的,我的学习心得就是动手写,之后将推出系列自定view的文章,敬请期待,本篇将带来一个非常简单的自定义控件——>太极图。

先来看看最终的效果:

这里写图片描述

大部分自定义view无外乎包含三个方面的内容:

  • 图形展示
  • 用户交互
  • 动画效果

先来分析这个图应该怎么画,来看一个动态图:

这里写图片描述

  • 1、先画一个黑色的圆;

  • 2、画左边的白色半圆;

  • 3、画上边白色的中圆;

  • 4、画下边黑色的中圆;

  • 5、画上边黑色的小圆;

  • 6、画下面白色的小圆。

另外就是关于屏幕的坐标系,不是数学中的那种哦看下图你就明白了,Y轴的方向是向下的:

这里写图片描述

下面来看看代码如何实现:

一、图形展示

第一步,创建一个继承至View的类,重写三个构造方法

public class TJView extends View {

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

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

    public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);      
    }
   }

第二步、来看看画太极需要属性

    //画笔工具
    private Paint mPaint;
    //圆心坐标--屏幕的宽高来设置-->目的是默认居中显示
    private float currentX = 0;
    private float currentY = 0;
    //大圆半径
    private float radiusBig = 200;
    //中圆半径
    private float radiusCenter = radiusBig / 2;
    //小圆半径
    private float radiusSmall = radiusCenter / 3;
    //边距(主要作用是画黑色大圆的时候,为了达到有边框的效果,半径需要比原来的大一点)
    private int padding = 8;

第三步、初始化画笔(第三个构造方法中)

  public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);//去掉锯齿
    }

第四步、拿到屏幕中心点的坐标

这里需要重写onMeasure方法来拿到实际测量的值

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        currentX = MeasureSpec.getSize(widthMeasureSpec) / 2;//通过MeasureSpec拿到X轴
        currentY = MeasureSpec.getSize(heightMeasureSpec) / 2;//通过MeasureSpec拿到Y轴
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);//测绘
    }

准备工作就绪,开始画

第五步、画一个黑色的大圆(此时圆点坐标、半径已经准备就绪了)

同样的需要重写onDraw方法—具体的业务抽成方法便于理解

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBg(canvas);//画黑色大圆
        drawLeftHalfCirle(canvas);//画左边白色半圆
        drawTBCirle(canvas);//画上下的四个圆
    }
  /**
     * 画黑色的背景底板
     *
     * @param canvas
     */
    private void drawBg(Canvas canvas) {
        mPaint.setColor(Color.BLACK);//设置背景颜色为黑色
        canvas.drawCircle(currentX, currentY, radiusBig + padding, mPaint);//这里加padding才有边框效果
    }
  /**
     * 画左边半圆
     *
     * @param canvas
     */
    private void drawLeftHalfCirle(Canvas canvas) {
        mPaint.setColor(Color.WHITE);
        canvas.drawArc(new RectF(currentX - radiusBig, currentY - radiusBig, currentX + radiusBig, currentY + radiusBig), 90, 180, true, mPaint);//90度开始画  画180度
    }
    /**
     * 画上下两个圆--中圆和小圆
     *
     * @param canvas
     */
    private void drawTBCirle(Canvas canvas) {
        //画上面的白中圆
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusCenter, mPaint);
        //画上面的黑小圆
        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusSmall, mPaint);
        //画下面的黑中圆
        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusCenter, mPaint);
        //画下面的白小圆
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusSmall, mPaint);
    }

这样一个标准的太极图就画出来了,效果图就是一开始那个;

二、用户交互

下面加点交互效果,——>用户拖动的时候太极图会随手指的移动而移动;

这里写图片描述

这里需要重写onTouchEvent方法

上代码:

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        currentX = event.getX();//获取当前手指所在x轴
        currentY = event.getY();//获取当前手指所在y轴
        invalidate();//立刻重绘
        return true;//返回true表示不通知父控件处理,自己处理
    }

三、动画效果

关于动画,下面就来加点缩放动画吧,同样先看效果:

这里写图片描述

 /**
     * 设置缩放动画
     */
    private void setAnimation() {
        ScaleAnimation scaleAnimation2 = new ScaleAnimation(0.7f, 1.0f, 0.7f, 1.0f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f);
        scaleAnimation2.setDuration(500);// 设置持续时间
        scaleAnimation2.setRepeatCount(99999);// 设置重复次数
        scaleAnimation2.setFillAfter(true);// 保持动画结束时的状态
        startAnimation(scaleAnimation2);
    }

在第三个构造方法中调用:

public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
        //省略其余代码
        setAnimation();
    }

四、最后

最后贴出完整的代码:

调用处:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_tj"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--包名要对应-->
    <com.hdl.myhttputilssimple.TJView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

完整的TJView代码:

/**
 * 太极图
 * Created by HDL on 2016/12/27.
 */

public class TJView extends View {
    private static final String TAG = "TJView";
    private int padding = 8;
    //画笔工具
    private Paint mPaint;
    //圆心坐标
    private float currentX = 0;
    private float currentY = 0;
    //大圆半径
    private float radiusBig = 200;
    //中圆半径
    private float radiusCenter = radiusBig / 2;
    //小圆半径
    private float radiusSmall = radiusCenter / 3;

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

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

    public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        setAnimation();
    }

    /**
     * 设置缩放动画
     */
    private void setAnimation() {
        ScaleAnimation scaleAnimation2 = new ScaleAnimation(0.7f, 1.0f, 0.7f, 1.0f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f);
        scaleAnimation2.setDuration(500);// 设置持续时间
        scaleAnimation2.setRepeatCount(99999);// 设置重复次数
        scaleAnimation2.setFillAfter(true);// 保持动画结束时的状态
        startAnimation(scaleAnimation2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBg(canvas);
        drawLeftHalfCirle(canvas);
        drawTBCirle(canvas);
    }

    /**
     * 画上下两个圆--中圆和小圆
     *
     * @param canvas
     */
    private void drawTBCirle(Canvas canvas) {
        //画上面的白中圆
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusCenter, mPaint);
        //画上面的黑小圆
        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusSmall, mPaint);
        //画下面的黑中圆
        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusCenter, mPaint);
        //画下面的白小圆
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusSmall, mPaint);
    }

    /**
     * 画左边半圆
     *
     * @param canvas
     */
    private void drawLeftHalfCirle(Canvas canvas) {
        mPaint.setColor(Color.WHITE);
        canvas.drawArc(new RectF(currentX - radiusBig, currentY - radiusBig, currentX + radiusBig, currentY + radiusBig), 90, 180, true, mPaint);//90度开始画180度
    }

    /**
     * 画黑色的背景底板
     *
     * @param canvas
     */
    private void drawBg(Canvas canvas) {
        mPaint.setColor(Color.BLACK);
        canvas.drawCircle(currentX, currentY, radiusBig + padding, mPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        currentX = MeasureSpec.getSize(widthMeasureSpec) / 2;
        currentY = MeasureSpec.getSize(heightMeasureSpec) / 2;
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        currentX = event.getX();
        currentY = event.getY();
        invalidate();
        return true;
    }
}

尊重原创,转载请注明出处: http://blog.csdn.net/qq137722697

发布了60 篇原创文章 · 获赞 252 · 访问量 43万+

猜你喜欢

转载自blog.csdn.net/qq137722697/article/details/53914686