GcsSloop

Just do IT later.

嗨,我是 GcsSloop,一名来自2.5次元的魔法师,Android自定义View系列文章作者,非著名程序员。


欢迎来到我的魔法世界!

二十多行代码画太极

一个然并卵的自定义View实例,觉得很有趣就做了一个试试,效果看起来貌似还是挺不错的,代码也非常简单。

如果想系统的学习自定义View,可以参考: 安卓自定义View教程目录

完成效果图

太极

技术基础

这一篇内容主要设计到安卓中的2D绘图部分,主要用到的是Canvas,使用到的主要技术可以参考下面两篇文章:

绘制太极

1.定义画笔

由于太极图像由黑白两色构成,为了方便就定义了两个画笔,分别绘制黑色和白色。

private Paint whitePaint;   //白色画笔
private Paint blackPaing;   //黑色画笔
//初始化画笔函数
private void initPaints() {
    whitePaint = new Paint();
    whitePaint.setAntiAlias(true);
    whitePaint.setColor(Color.WHITE);

    blackPaing = new Paint(whitePaint);
    blackPaing.setColor(Color.BLACK);
}

2.在构造函数中初始化画笔

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

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

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

3.在onDraw中使用Canvas绘制内容

3.1 确定画布大小

int width = canvas.getWidth();                          //画布宽度
int height = canvas.getHeight();                        //画布高度

3.2 将Canvas坐标原点移动到画布中心

canvas.translate(centerPoint.x, centerPoint.y);         //将画布移动到中心

3.3 绘制背景色

canvas.drawColor(Color.GRAY);                           //绘制背景色

3.4 确定太极的半径大小并绘制两个半圆

//绘制两个半圆
int radius = Math.min(width, height) / 2 - 100;             //太极半径
RectF rect = new RectF(-radius, -radius, radius, radius);   //绘制区域
canvas.drawArc(rect, 90, 180, true, blackPaing);            //绘制黑色半圆
canvas.drawArc(rect, -90, 180, true, whitePaint);           //绘制白色半圆

在这里简单解释一下drawArc绘制圆弧方法几个参数的意义。

参数 作用
RectF oval 绘制的区域(是一个矩形)
float startAngle 开始角度
float sweepAngle 扫过角度
boolean useCenter 是否使用中心
Paint paint 画笔

另外,由于移动设备屏幕的坐标系和我们在数学中常用的坐标系稍微有点区别,需要注意一下。 在移动设备中一般定义左上角为坐标零点,x轴坐标向右增大,y轴坐标向下增大。而在数学坐标系中一般定义y轴坐标向上为增大方向,所以两者y轴刚好是反向的。

更多可参考:

3.5 绘制两个小圆

//绘制两个小圆
int smallRadius = radius / 2;	//小圆半径为大圆的一般
canvas.drawCircle(0, -smallRadius, smallRadius, blackPaing);
canvas.drawCircle(0, smallRadius, smallRadius, whitePaint);

3.6 绘制鱼眼

//绘制鱼眼(两个更小的圆)
canvas.drawCircle(0, -smallRadius, smallRadius / 4, whitePaint);
canvas.drawCircle(0, smallRadius, smallRadius / 4, blackPaing);

4.让太极旋转起来

4.1 设置旋转角度变量,并提供外部访问接口

private float degrees = 0;          //旋转角度
public void setRotate(float degrees) {
	this.degrees = degrees;
	invalidate();                   //重绘界面
}

4.2 在实际绘制之前调用旋转函数

//在绘制完背景色后调用即可
canvas.rotate(degrees);

4.3 不断改变旋转角度

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
    final TaiJi taiJi = new TaiJi(this);
    setContentView(taiJi);
    final Handler handler = new Handler() {
        private float degrees = 0;
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            taiJi.setRotate(degrees += 5);
            this.sendEmptyMessageDelayed(0, 80);
        }
    };

    handler.sendEmptyMessageDelayed(0, 20);
}

太极

5.完整代码

public class TaiJi extends View {
    private Paint whitePaint;   //白色画笔
    private Paint blackPaing;   //黑色画笔

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

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

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

        initPaints();
    }

    //初始化画笔函数
    private void initPaints() {
        whitePaint = new Paint();
        whitePaint.setAntiAlias(true);
        whitePaint.setColor(Color.WHITE);

        blackPaing = new Paint(whitePaint);
        blackPaing.setColor(Color.BLACK);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        int width = canvas.getWidth();          //画布宽度
        int height = canvas.getHeight();        //画布高度

        canvas.translate(width/2, height/2);    // 移动坐标原点到画布中心

        canvas.drawColor(Color.GRAY);           //绘制背景色
        canvas.rotate(degrees);                 //旋转画布

        //绘制两个半圆
        int radius = Math.min(width, height) / 2 - 100;        		//太极半径
        RectF rect = new RectF(-radius, -radius, radius, radius);   //绘制区域
        canvas.drawArc(rect, 90, 180, true, blackPaing);            //绘制黑色半圆
        canvas.drawArc(rect, -90, 180, true, whitePaint);           //绘制白色半圆

        //绘制两个小圆
        int smallRadius = radius / 2;	                            //小圆半径为大圆的一半
        canvas.drawCircle(0, -smallRadius, smallRadius, blackPaing);
        canvas.drawCircle(0, smallRadius, smallRadius, whitePaint);

        //绘制鱼眼(两个更小的圆)
        canvas.drawCircle(0, -smallRadius, smallRadius / 4, whitePaint);
        canvas.drawCircle(0, smallRadius, smallRadius / 4, blackPaing);

    }

    private float degrees = 0;                  //旋转角度
    public void setRotate(float degrees) {
        this.degrees = degrees;
        invalidate();                           //重绘界面
    }
}

结语

虽然写了这么长,但核心代码不过二十几行,其实还是挺简单的,一个没什么用但很中国特色的自定义View。


如果你觉得我的文章对你有帮助的话,捐赠一些晶石,鼓励我继续研究!

¥ 捐赠晶石
最近的文章

安卓自定义View基础-坐标系

一.屏幕坐标系和数学坐标系的区别由于移动设备一般定义屏幕左上角为坐标原点,向右为x轴增大方向,向下为y轴增大方向,所以在手机屏幕上的坐标系与数学中常见的坐标系是稍微有点差别的,详情如下:(PS:...…

CustomView

继续阅读
更早的文章

在AndroidStudio中使用PlantUML(for Win)

点击下面切换平台:| Mac | Win| Unified Modeling Language (UML)又称统一建模语言或标准建模语言,用来描述 类(对象的)、对象、关联、职责、行为、接口、用...…

Course

继续阅读