使用Android原生canvas绘制炫酷的太极八卦图

内部的太极以及外部的八卦环都可以调节不同的速度和方向,实现效果:

 原代码:

EightDiagrams:
package com.hjq.myapplication;


import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;


public class EightDiagrams extends View {

    private final Paint mPaint;

    private final Paint whitePaint;   //白色画笔
    private final Paint blackPaint;
    private final Paint outlinePaint;   //轮廓画笔
    float mWidth;                 //控件宽
    float mHeight;                //控件高
    float mOutlineR1;
    float mOutlineR2;
    float mOutlineR3;
    float mOutlineR4;
    float mOutlineR5;
    private final String[][] listR1;
    private final String[] listR2;
    private final String[] listR3;
    private final String[] listR4;
    private final String[] listR5;
    private float degrees_tai = 0;          //旋转角度


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

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

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

        //路径
        whitePaint = new Paint();
        whitePaint.setAntiAlias(true);
        whitePaint.setColor(Color.WHITE);

        blackPaint = new Paint();
        blackPaint.setAntiAlias(true);
        blackPaint.setColor(Color.BLACK);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);

        outlinePaint = new Paint();
        outlinePaint.setAntiAlias(true);
        outlinePaint.setStyle(Paint.Style.STROKE);
        outlinePaint.setColor(Color.parseColor("#000000"));

        listR1 = new String[][]{{"|","|","|",""},{"¦","¦","¦",""},{"|","¦","¦",""},
                                {"¦","|","¦",""},{"¦","|","|",""},{"¦","¦","|",""},
                                {"|","¦","|",""},{"|","|","¦",""},{"","","",""}, {"☰","☷","☳","☵","☴","☶","☲","☱",""}};

        listR2 = new String[]{"申", "庚", "酉", "辛", "戌", "乾", "亥", "壬", "子", "癸", "丑", "艮",
                "寅", "甲", "卯", "乙", "辰", "巽", "巳", "丙", "午", "丁", "未", "坤", ""};
        listR3 = new String[]{"天厨","天市","天梧","天苑","天命","天宫","天","太乙","天屏","太徽","天广","南极"
                             ,"天常","天境","天开","天汉","少徽","天乙","天魁","天廊","天皇","天铺","天叠","阴光",""};
        listR4 = new String[]{"夬", "乾", "姤", "大过", "鼎", "恒", "巽", "井", "蛊", "升", "诉", "困",
                            "未济", "解", "涣", "坎", "蒙", "师", "遯", "咸", "旅", "小过", "渐", "蹇", "艮",
                            "谦","否","萃","晋","豫","观","比","剥","坤","蕧","颐","屯",
                            "益","震","嘘咳","随","无安","明夷","贵","既济","家人","丰","难","革",
                            "同人","临","损","节","中孚","归妹","睽","兑","履","泰","大畜","需",
                            "小畜","大壮","否","萃","晋","豫","观","比","剥","坤","大有","离",""};
        listR5 = new String[]{"水","木","水","木","土","金","火","土","水","木","土","金",
                              "火","水","木","土","金","火","金","木","水","火","火","土",
                              "火","水","木","土","金","火","金","木","水","火","火","土",
                              "水","木","土","金","火","金","木","水","火","火","土","火",
                              "土","水","木","土","金","火","金","木","水","火","土","火",""};

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);
        setMeasuredDimension(width, height);
        mWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
        mHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
    }

    private int measureHeight(int measureSpec) {
        int mode = MeasureSpec.getMode(measureSpec);
        int val = MeasureSpec.getSize(measureSpec);
        int result = 0;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                result = val;
                break;
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                break;
        }
        result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
        return result + getPaddingTop() + getPaddingBottom();
    }

    private int measureWidth(int measureSpec) {
        int mode = MeasureSpec.getMode(measureSpec);
        int val = MeasureSpec.getSize(measureSpec);
        int result = 0;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                result = val;
                break;
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                break;
        }
        result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
        return result + getPaddingLeft() + getPaddingRight();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        mOutlineR1 = mWidth * 0.17f;
        mOutlineR2 = mWidth * 0.24f;
        mOutlineR3 = mWidth * 0.307f;
        mOutlineR4 = mWidth * 0.371f;
        mOutlineR5 = mWidth * 0.432f;
    }

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

        if (canvas == null)
            return;
        canvas.drawColor(Color.parseColor("#fff7f9fa"));//填充背景
        canvas.save();
        canvas.translate(mWidth / 2, mHeight / 2);//原点移动到中心

        //绘制各元件,后文会涉及到
        drawCenterInfo(canvas);
        drawOutline(canvas);

    }

    @SuppressLint("SuspiciousIndentation")
    private void drawOutline(Canvas canvas) {
        outlinePaint.setStrokeWidth(mWidth/350);

        mPaint.setColor(Color.WHITE);
        mPaint.setAlpha(255);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(mWidth * 0.06f);
        mPaint.setColor(Color.parseColor("#000000"));

        //第一层
        canvas.save();
        canvas.rotate(-degrees_tai/4);
        canvas.drawCircle(0, 0, mOutlineR1, outlinePaint);
        for (int i = 0; i <= 8; i++) {
            double angle = 2 * Math.PI / 8 * i+Math.PI / 8 ;
            canvas.drawLine((float) StrictMath.cos(angle) * mWidth / 10, (float) StrictMath.sin(angle) * mWidth / 10,
                    (float) StrictMath.cos(angle) * mOutlineR1, (float) StrictMath.sin(angle) * mOutlineR1, outlinePaint);
            canvas.save();
            float iDeg1 = 360 / 8f * i;
            canvas.rotate(iDeg1,0,0);
            mPaint.setTextAlign(Paint.Align.RIGHT);
            for (int j=0;j<=2;j++)
            canvas.drawText(listR1[i][j],  mOutlineR1*(0.9f-j*0.1f), getCenteredY()+mOutlineR1*0.28f, mPaint);
            canvas.restore();
        }
        canvas.restore();

        //第二层
        mPaint.setTextSize(mWidth * 0.03f);
        canvas.save();
        canvas.rotate(degrees_tai/6);
        canvas.drawCircle(0, 0, mOutlineR2, outlinePaint);
        for (int i = 0; i <= 24; i++) {
            double angle = 2 * Math.PI / 24f * i+5;
            canvas.drawLine((float) StrictMath.cos(angle) * mOutlineR1, (float) StrictMath.sin(angle) * mOutlineR1,
                    (float) StrictMath.cos(angle) * mOutlineR2, (float) StrictMath.sin(angle) * mOutlineR2, outlinePaint);
            canvas.save();
            float iDeg1 = 360 / 24f * i;
            canvas.rotate(iDeg1);
            mPaint.setTextAlign(Paint.Align.RIGHT);
            canvas.drawText(listR2[i],  mOutlineR2*0.9f, getCenteredY(), mPaint);
            canvas.restore();
        }
        canvas.restore();

        //第三层
        mPaint.setTextSize(mWidth * 0.028f);
        canvas.save();
        canvas.rotate(-degrees_tai/6);
        canvas.drawCircle(0, 0, mOutlineR3, outlinePaint);
        for (int i = 0; i <= 24; i++) {
            double angle = 2 * Math.PI / 24f * i+5;
            canvas.drawLine((float) StrictMath.cos(angle) * mOutlineR2, (float) StrictMath.sin(angle) * mOutlineR2,
                    (float) StrictMath.cos(angle) * mOutlineR3, (float) StrictMath.sin(angle) * mOutlineR3, outlinePaint);
            canvas.save();
            float iDeg1 = 360 / 24f * i;
            canvas.rotate(iDeg1);
            mPaint.setTextAlign(Paint.Align.RIGHT);
            canvas.drawText(listR3[i],  mOutlineR3*0.965f, getCenteredY(), mPaint);
            canvas.restore();
        }
        canvas.restore();


        //第四层
        mPaint.setTextSize(mWidth * 0.02f);
        canvas.save();
        canvas.rotate(degrees_tai/18);
        canvas.drawCircle(0, 0, mOutlineR4, outlinePaint);
        for (int i = 0; i <= 72; i++) {
            double angle = 2 * Math.PI / 72f * i+2;
            canvas.drawLine((float) StrictMath.cos(angle) * mOutlineR3, (float) StrictMath.sin(angle) * mOutlineR3,
                    (float) StrictMath.cos(angle) * mOutlineR4, (float) StrictMath.sin(angle) * mOutlineR4, outlinePaint);

            canvas.save();
            float iDeg1 = 360 / 72f * i;
            canvas.rotate(iDeg1);
            mPaint.setTextAlign(Paint.Align.RIGHT);
            canvas.drawText(listR4[i],  mOutlineR4*0.95f, getCenteredY(), mPaint);
            canvas.restore();
        }
        canvas.restore();

        //第五层
        mPaint.setTextSize(mWidth * 0.025f);
        canvas.save();
        canvas.rotate(-degrees_tai/15);
        canvas.drawCircle(0, 0, mOutlineR5, outlinePaint);
        for (int i = 0; i <= 60; i++) {
            double angle = 2 * Math.PI / 60f * i+2;
            canvas.drawLine((float) StrictMath.cos(angle) * mOutlineR4, (float) StrictMath.sin(angle) * mOutlineR4,
                    (float) StrictMath.cos(angle) * mOutlineR5, (float) StrictMath.sin(angle) * mOutlineR5, outlinePaint);

            canvas.save();
            float iDeg1 = 360 / 60f * i;
            canvas.rotate(iDeg1);
            mPaint.setTextAlign(Paint.Align.RIGHT);
            canvas.drawText(listR5[i],  mOutlineR5*0.95f, getCenteredY(), mPaint);
            canvas.restore();
        }
        canvas.restore();

    }

    //绘制太极
    private void drawCenterInfo(Canvas canvas) {
        canvas.save();
        canvas.rotate(degrees_tai);
        //绘制两个半圆
        int radius = (int) (Math.min(mWidth, mHeight) / 10);             //太极半径
        RectF rect = new RectF(-radius, -radius, radius, radius);   //绘制区域
        canvas.drawArc(rect, 90, 180, true, blackPaint);            //绘制黑色半圆
        canvas.drawArc(rect, -90, 180, true, whitePaint);           //绘制白色半圆
        //绘制两个小圆
        int smallRadius;   //小圆半径为大圆的一般
        smallRadius = radius / 2;
        canvas.drawCircle(0, -smallRadius, smallRadius, blackPaint);
        canvas.drawCircle(0, smallRadius, smallRadius, whitePaint);
        //绘制鱼眼(两个更小的圆)
        canvas.drawCircle(0, -smallRadius, smallRadius >> 2, whitePaint);
        canvas.drawCircle(0, smallRadius, smallRadius >> 2, blackPaint);
        canvas.restore();
    }


    public void setRotate(float degrees_tai) {
        this.degrees_tai = degrees_tai;
        invalidate();                   //重绘界面
    }

    /**
     * 中间对齐
     *
     */
    private float getCenteredY() {
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        return mPaint.getFontSpacing() / 2 - 4*fontMetrics.bottom;
    }


}



EightDiagramsActivity:

package com.hjq.myapplication;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class EightDiagramsActivity extends Activity {

    private EightDiagrams eightDiagrams;

    private final Handler handler = new Handler(Looper.getMainLooper()) {
        private float degrees = 0;

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            eightDiagrams.setRotate(degrees += msg.what);
            this.sendEmptyMessageDelayed(msg.what, 50);
        }
    };

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_eight_diagrams);
        eightDiagrams = findViewById(R.id.eight_diagrams_id);

        eightDiagrams.setOnClickListener(v -> {
            handler.removeCallbacksAndMessages(null);
            handler.removeMessages(2);
            handler.sendEmptyMessageDelayed(30, 30);
            handler.postDelayed(() -> {
                handler.removeCallbacksAndMessages(null);
                handler.removeMessages(30);
                handler.sendEmptyMessageDelayed(2, 30);
            }, 1000);
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);
        finish();
    }

}

 activity_eight_diagrams.xml:





    

你可能感兴趣的:(android,java,android,studio)