Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android自定義刻度盤 表盤 速度表

android自定義刻度盤 表盤 速度表

編輯:關於Android編程

效果圖
這裡寫圖片描述
這裡寫圖片描述
直接在xml文件中添加即可,在代碼中調用setProgress(int) 即可。代碼注釋寫的很清楚,有興趣的隨便改改。

InstrumentView.java

package com.xk.testdemo.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.xk.testdemo.config.ConfigColor;

import static android.R.attr.angle;
import static android.R.attr.baseline;
import static android.R.attr.dial;
import static android.R.attr.end;
import static android.R.attr.path;
import static android.R.attr.radius;
import static android.R.attr.width;
import static android.R.attr.x;
import static android.R.attr.y;

/**
 * Created by xuekai on 2016/10/26.
 */

public class InstrumentView extends View {
    private String color_outcircle = "#DEDEDE";
    private String color_bg_outcircle = "#2690F8";
    private String color_bg_incircle = "#58ADE4";
    private String color_progress = "#87CEEB";
    private String color_smart_circle = "#C2B9B0";
    private String color_indicator_left = "#E1DCD6";
    private String color_indicator_right = "#F4EFE9";

    /**
     * 當前進度
     */
    private int progress = 50;
    /**
     * 要畫的內容的實際寬度
     */
    private int contentWidth;
    /**
     * view的實際寬度
     */
    private int viewWidth;
    /**
     * view的實際高度
     */
    private int viewHeight;
    /**
     * 外環線的寬度
     */
    private int outCircleWidth = 1;
    /**
     * 外環的半徑
     */
    private int outCircleRadius = 0;
    /**
     * 內環的半徑
     */
    private int inCircleRedius = 0;
    /**
     * 內環與外環的距離
     */
    private int outAndInDistance = 0;
    /**
     * 內環的寬度
     */
    private int inCircleWidth = 0;
    /**
     * 刻度盤距離它外面的圓的距離
     */
    private int dialOutCircleDistance = 0;
    /**
     * 內容中心的坐標
     */
    private int[] centerPoint = new int[2];


    /**
     * 刻度線的數量
     */
    private int dialCount = 0;
    /**
     * 每隔幾次出現一個長線
     */
    private int dialPer = 0;
    /**
     * 長線的長度
     */
    private int dialLongLength = 0;
    /**
     * 短線的長度
     */
    private int dialShortLength = 0;
    /**
     * 刻度線距離圓心最遠的距離
     */
    private int dialRadius = 0;


    /**
     * 圓弧開始的角度
     */
    private int startAngle = 0;
    /**
     * 圓弧劃過的角度
     */
    private int allAngle = 0;

    private Paint mPaint;
    /**
     * 刻度盤上數字的數量
     */
    private int figureCount = 6;


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

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

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

    private void init() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        initValues();
    }

    /**
     * 初始化尺寸
     */
    private void initValues() {
        viewWidth = getMeasuredWidth();
        viewHeight = getMeasuredHeight();
        contentWidth = viewWidth > viewHeight ? viewHeight : viewWidth;
        outCircleRadius = contentWidth / 2 - outCircleWidth;
        outAndInDistance = (int) (contentWidth / 26.5);
        inCircleWidth = (int) (contentWidth / 18.7);
        centerPoint[0] = viewWidth / 2;
        centerPoint[1] = viewHeight / 2;
        inCircleRedius = outCircleRadius - outAndInDistance - inCircleWidth / 2;
        startAngle = 150;
        allAngle = 240;
        dialOutCircleDistance = inCircleWidth;

        dialCount = 50;
        dialPer = 5;
        dialLongLength = (int) (dialOutCircleDistance / 1.2);
        dialShortLength = (int) (dialLongLength / 1.8);
        dialRadius = inCircleRedius - dialOutCircleDistance;

    }

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

    }

    /**
     * 繪制靜態的部分
     *
     * @param canvas
     */
    private void drawStatic(Canvas canvas) {
        drawOutCircle(canvas);
        drawCircleWithRound(startAngle, allAngle, inCircleWidth, inCircleRedius, color_outcircle, canvas);
        drawDial(startAngle, allAngle, dialCount, dialPer, dialLongLength, dialShortLength, dialRadius, canvas);
        drawBackGround(canvas);
        drawFigure(canvas, figureCount);
    }

    private void drawFigure(Canvas canvas, int count) {
        int figure = 0;
        int angle;
        for (int i = 0; i < count; i++) {
            figure = (int) (100 / (1f * count-1) * i);
            angle = (int) ((allAngle) / ((count-1) * 1f) * i) + startAngle;
            int[] pointFromAngleAndRadius = getPointFromAngleAndRadius(angle, dialRadius - dialLongLength * 2 );
            mPaint.setTextSize(15);
            mPaint.setTextAlign(Paint.Align.CENTER);
            canvas.save();
            canvas.rotate(angle+90,pointFromAngleAndRadius[0],pointFromAngleAndRadius[1]);
            canvas.drawText(figure+"%",pointFromAngleAndRadius[0],pointFromAngleAndRadius[1],mPaint);
            canvas.restore();
        }
    }

    /**
     * 畫內層背景
     *
     * @param canvas
     */
    private void drawBackGround(Canvas canvas) {
        mPaint.setColor(Color.parseColor(color_bg_outcircle));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(outCircleRadius / 3 / 2);
        canvas.drawCircle(centerPoint[0], centerPoint[1], outCircleRadius / 3, mPaint);
        mPaint.setColor(Color.parseColor(color_bg_incircle));
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(centerPoint[0], centerPoint[1], (outCircleRadius / 3f / 2), mPaint);
    }

    /**
     * 畫刻度盤
     *
     * @param startAngle  開始畫的角度
     * @param allAngle    總共劃過的角度
     * @param dialCount   總共的線的數量
     * @param per         每隔幾個出現一次長線
     * @param longLength  長仙女的長度
     * @param shortLength 短線的長度
     * @param radius      距離圓心最遠的地方的半徑
     */
    private void drawDial(int startAngle, int allAngle, int dialCount, int per, int longLength, int shortLength, int radius, Canvas canvas) {
        int length;
        int angle;
        for (int i = 0; i <= dialCount; i++) {
            angle = (int) ((allAngle) / (dialCount * 1f) * i) + startAngle;

            if (i % 5 == 0) {
                length = longLength;
            } else {
                length = shortLength;
            }
            drawSingleDial(angle, length, radius, canvas);
        }
    }

    /**
     * 畫刻度中的一條線
     *
     * @param angle  所處的角度
     * @param length 線的長度
     * @param radius 距離圓心最遠的地方的半徑
     */
    private void drawSingleDial(int angle, int length, int radius, Canvas canvas) {
        int[] startP = getPointFromAngleAndRadius(angle, radius);
        int[] endP = getPointFromAngleAndRadius(angle, radius - length);
        canvas.drawLine(startP[0], startP[1], endP[0], endP[1], mPaint);
    }

    /**
     * 畫最外層的圓
     *
     * @param canvas
     */
    private void drawOutCircle(Canvas canvas) {
        mPaint.setStrokeWidth(outCircleWidth);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.parseColor(color_outcircle));
        canvas.drawCircle(centerPoint[0], centerPoint[1], outCircleRadius, mPaint);
    }

    /**
     * 繪制動態的部分
     *
     * @param canvas
     */
    private void drawDynamic(Canvas canvas) {

        drawProgress(progress, canvas);
        drawIndicator(progress, canvas);
        drawCurrentProgressTv(progress, canvas);
    }

    /**
     * 繪制當前進度是文字
     *
     * @param progress
     * @param canvas
     */
    private void drawCurrentProgressTv(int progress, Canvas canvas) {
//        canvas.drawText("當前進度:"+progress+"%",);
        mPaint.setTextSize(25);
        mPaint.setTextAlign(Paint.Align.CENTER);
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        float baseLine1 = centerPoint[1] + (outCircleRadius / 20f * 11 - fontMetrics.top - fontMetrics.bottom);
        canvas.drawText("當前進度", centerPoint[0], baseLine1, mPaint);


        float baseLine2 = outCircleRadius / 20f * 11 - 3 * (fontMetrics.bottom + fontMetrics.top) + centerPoint[1];
        canvas.drawText(progress + "%", centerPoint[0], baseLine2, mPaint);


    }

    /**
     * 畫指針以及他的背景
     *
     * @param progress
     * @param canvas
     */
    private void drawIndicator(int progress, Canvas canvas) {
        drawPointer(canvas);
        drawIndicatorBg(canvas);
    }

    /**
     * 指針的最遠處的半徑和刻度線的一樣
     */
    private void drawPointer(Canvas canvas) {
        RectF rectF = new RectF(centerPoint[0] - (int) (outCircleRadius / 3f / 2 / 2),
                centerPoint[1] - (int) (outCircleRadius / 3f / 2 / 2), centerPoint[0] + (int) (outCircleRadius / 3f / 2 / 2), centerPoint[1] + (int) (outCircleRadius / 3f / 2 / 2));
        int angle = (int) ((allAngle) / (100 * 1f) * progress) + startAngle;
        //指針的定點坐標
        int[] peakPoint = getPointFromAngleAndRadius(angle, dialRadius);
        //頂點朝上,左側的底部點的坐標
        int[] bottomLeft = getPointFromAngleAndRadius(angle - 90, (int) (outCircleRadius / 3f / 2 / 2));
        //頂點朝上,右側的底部點的坐標
        int[] bottomRight = getPointFromAngleAndRadius(angle + 90, (int) (outCircleRadius / 3f / 2 / 2));
        Path path = new Path();
        mPaint.setColor(Color.parseColor(color_indicator_left));
        path.moveTo(centerPoint[0], centerPoint[1]);
        path.lineTo(peakPoint[0], peakPoint[1]);
        path.lineTo(bottomLeft[0], bottomLeft[1]);
        path.close();
        canvas.drawPath(path, mPaint);
        canvas.drawArc(rectF, angle - 180, 100, true, mPaint);
        Log.e("InstrumentView", "drawPointer" + angle);


        mPaint.setColor(Color.parseColor(color_indicator_right));
        path.reset();
        path.moveTo(centerPoint[0], centerPoint[1]);
        path.lineTo(peakPoint[0], peakPoint[1]);
        path.lineTo(bottomRight[0], bottomRight[1]);
        path.close();
        canvas.drawPath(path, mPaint);

        canvas.drawArc(rectF, angle + 80, 100, true, mPaint);


    }

    private void drawIndicatorBg(Canvas canvas) {
        mPaint.setColor(Color.parseColor(color_smart_circle));
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(centerPoint[0], centerPoint[1], (outCircleRadius / 3f / 2 / 4), mPaint);
    }

    /**
     * 根據進度畫進度條
     *
     * @param progress 最大進度為100.最小為0
     */
    private void drawProgress(int progress, Canvas canvas) {
        float ratio = progress / 100f;
        int angle = (int) (allAngle * ratio);
        drawCircleWithRound(startAngle, angle, inCircleWidth, inCircleRedius, color_progress, canvas);

    }

    public int getProgress() {
        return progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
        invalidate();
    }

    /**
     * 畫一個兩端為圓弧的圓形曲線
     *
     * @param startAngle 曲線開始的角度
     * @param allAngle   曲線走過的角度
     * @param radius     曲線的半徑
     * @param width      曲線的厚度
     */
    private void drawCircleWithRound(int startAngle, int allAngle, int width, int radius, String color, Canvas canvas) {
        mPaint.setStrokeWidth(width);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.parseColor(color));
        RectF rectF = new RectF(centerPoint[0] - radius, centerPoint[1] - radius, centerPoint[0] + radius, centerPoint[1] + radius);
        canvas.drawArc(rectF, startAngle, allAngle, false, mPaint);
        drawArcRoune(radius, startAngle, width, canvas);
        drawArcRoune(radius, startAngle + allAngle, width, canvas);
    }

    /**
     * 繪制圓弧兩端的圓
     *
     * @param radius 圓弧的半徑
     * @param angle  所處於圓弧的多少度的位置
     * @param width  圓弧的寬度
     */
    private void drawArcRoune(int radius, int angle, int width, Canvas canvas) {
        int[] point = getPointFromAngleAndRadius(angle, radius);
        mPaint.setStrokeWidth(0);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(point[0], point[1], width / 2, mPaint);
    }

    /**
     * 根據角度和半徑,求一個點的坐標
     *
     * @param angle
     * @param radius
     * @return
     */
    private int[] getPointFromAngleAndRadius(int angle, int radius) {
        double x = radius * Math.cos(angle * Math.PI / 180) + centerPoint[0];
        double y = radius * Math.sin(angle * Math.PI / 180) + centerPoint[1];
        return new int[]{(int) x, (int) y};
    }

}

activity_main.xml




    




MainActivity.java

package com.xk.testdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.SeekBar;

import com.xk.testdemo.view.IndicatorContainer;
import com.xk.testdemo.view.InstrumentView;

public class MainActivity extends AppCompatActivity {
    private IndicatorContainer myView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final InstrumentView viewById = (InstrumentView) findViewById(R.id.instrumentView);
        SeekBar viewById1 = (SeekBar) findViewById(R.id.sb);

        viewById1.setMax(100);
        viewById1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                viewById.setProgress(progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved