Android画一个太极图

转载地址:http://www.jianshu.com/p/2a9e5ddbeb26


今天练手一下,一起来画个太极图吧~

最终效果如下:


最终效果

一般都是先讲原理,我就反其道而行,先讲实现吧。

1.继承实现初始化方法

继承View,实现基本的构造函数:

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

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

public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    init();
}

在init()方法中,进行初始化操作,这里初始化一下画笔就好。

private Paint mPaint;

private void init() {
    initPaint();
}

/**
 * 初始化画笔
 */
private void initPaint() {
    mPaint = new Paint();               //创建画笔对象
    mPaint.setColor(Color.BLACK);       //设置画笔颜色
    mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充
    mPaint.setStrokeWidth(10f);         //设置画笔宽度为10px
    mPaint.setAntiAlias(true);          //设置抗锯齿
    mPaint.setAlpha(255);               //设置画笔透明度
}

在onSizeChanged()方法中获取高宽,便于之后绘制计算。

private int mWidth;
private int mHeight;    

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = w;
    mHeight = h;
}

创建两个路径,一下计算就在这两个路径中进行。

private Path path0 = new Path();
private Path path1 = new Path();

然后到最关键的onDraw()方法了,这里会分几步来演示。

1.移动布局到中间

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //移动布局到中间
    canvas.translate(mWidth / 2, mHeight / 2);
}

ps:为了简洁,之后的代码都是在onDraw()中逐层增加的,之后就不写onDraw()的外出括号了。

2.画背景黄色

    mPaint.setColor(0xffffff00);
    path0.addRect(-400, -400, 400, 400, Path.Direction.CW);
    canvas.drawPath(path0, mPaint);

第二步.png

3.画白色圆背景,即太极图的白鱼部分。

mPaint.setColor(0xffffffff);
path0.rewind();
path0.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path0, mPaint);

第三步.png

4.画黑色圆背景,即太极图的黑鱼部分,和白鱼一样大小位置,只是把白鱼盖住了,这里就需要用一些boolean运算进行绘制了。

//白鱼的背景
mPaint.setColor(0xffffffff);
path0.rewind();
path0.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path0, mPaint);

//黑鱼的背景
mPaint.setColor(0xff000000);
path1.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path0, mPaint);//这一段注意,之后要删除

第四步.png

5.对黑鱼(path1)进行boolean计算,把不需要的部分去掉。这里就是要把圆的右半边消除,这里就需要用到path.op()方法了。

mPaint.setColor(0xffffffff);
path0.rewind();
path0.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path0, mPaint);

mPaint.setColor(0xff000000);
path1.addCircle(0, 0, 200, Path.Direction.CW);

path0.rewind();
path0.addRect(0, -200, 200, 200, Path.Direction.CW);
path1.op(path0, Path.Op.DIFFERENCE);
canvas.drawPath(path0, mPaint);//这一段注意,之后要删除

第五步.png

6.这时候我们已经把不需要的另一半黑色去掉了,但是黑鱼应该有个圆的头,那么我们就拼接一个头给它。

mPaint.setColor(0xffffffff);
path0.rewind();
path0.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path0, mPaint);

mPaint.setColor(0xff000000);
path1.addCircle(0, 0, 200, Path.Direction.CW);

path0.rewind();
path0.addRect(0, -200, 200, 200, Path.Direction.CW);
path1.op(path0, Path.Op.DIFFERENCE);

path0.rewind();
path0.addCircle(0, -100, 100, Path.Direction.CW);
path1.op(path0, Path.Op.UNION);

canvas.drawPath(path1, mPaint);//这一段注意,之后要删除

第六步.png

7.到这里,我们看到,只需要在绘制一个白鱼的头就可以了,那么也和第五步一样,使用一个boolean运算把多余的黑色去掉即可。

mPaint.setColor(0xffffffff);
path0.rewind();
path0.addCircle(0, 0, 200, Path.Direction.CW);
canvas.drawPath(path0, mPaint);

mPaint.setColor(0xff000000);
path1.addCircle(0, 0, 200, Path.Direction.CW);

path0.rewind();
path0.addRect(0, -200, 200, 200, Path.Direction.CW);
path1.op(path0, Path.Op.DIFFERENCE);

path0.rewind();
path0.addCircle(0, -100, 100, Path.Direction.CW);
path1.op(path0, Path.Op.UNION);

path0.rewind();
path0.addCircle(0, 100, 100, Path.Direction.CW);
path1.op(path0, Path.Op.DIFFERENCE);
canvas.drawPath(path1, mPaint);

第七步.png

8.至此,已经绘制好了八卦图的背景了,只需要在绘制鱼的眼睛即可。

//画黑色小圆
path0.rewind();
path0.addCircle(0, 100, 50, Path.Direction.CW);
mPaint.setColor(0xff000000);
canvas.drawPath(path0, mPaint);

//画白色小圆
path0.rewind();
path0.addCircle(0, -100, 50, Path.Direction.CW);
mPaint.setColor(0xffffffff);
canvas.drawPath(path0, mPaint);

第八步.png

完成,最后上完整的代码。代码写得有点乱,不过也是练习而已,哈哈。至于其中的boolean运算什么的,之后在我的自定义View的笔记中在写吧。

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by Whitelaning on 2016/6/28.
 * Email: whitelaning@qq.com
 */
public class TestView extends View {

    private Paint mPaint;
    private int mWidth;
    private int mHeight;

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

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

    public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        initPaint();
    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();               //创建画笔对象
        mPaint.setColor(Color.BLACK);       //设置画笔颜色
        mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充
        mPaint.setStrokeWidth(10f);         //设置画笔宽度为10px
        mPaint.setAntiAlias(true);          //设置抗锯齿
        mPaint.setAlpha(255);               //设置画笔透明度
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    private Path path0 = new Path();
    private Path path1 = new Path();

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //移动布局到中间
        canvas.translate(mWidth / 2, mHeight / 2);

        //画大背景颜色
        mPaint.setColor(0xffffff00);
        path0.addRect(-400, -400, 400, 400, Path.Direction.CW);
        canvas.drawPath(path0, mPaint);

        mPaint.setColor(0xffffffff);
        path0.rewind();
        path0.addCircle(0, 0, 200, Path.Direction.CW);
        canvas.drawPath(path0, mPaint);

        mPaint.setColor(0xff000000);
        path1.addCircle(0, 0, 200, Path.Direction.CW);

        path0.rewind();
        path0.addRect(0, -200, 200, 200, Path.Direction.CW);
        path1.op(path0, Path.Op.DIFFERENCE);

        path0.rewind();
        path0.addCircle(0, -100, 100, Path.Direction.CW);
        path1.op(path0, Path.Op.UNION);

        path0.rewind();
        path0.addCircle(0, 100, 100, Path.Direction.CW);
        path1.op(path0, Path.Op.DIFFERENCE);
        canvas.drawPath(path1, mPaint);

        //画黑色小圆
        path0.rewind();
        path0.addCircle(0, 100, 50, Path.Direction.CW);
        mPaint.setColor(0xff000000);
        canvas.drawPath(path0, mPaint);

        //画白色小圆
        path0.rewind();
        path0.addCircle(0, -100, 50, Path.Direction.CW);
        mPaint.setColor(0xffffffff);
        canvas.drawPath(path0, mPaint);
    }
}

Whitelaning
It's very easy to be different but very difficult to be better


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值