1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Android自定義實(shí)現(xiàn)繪制時(shí)鐘表盤(pán)

        共 11688字,需瀏覽 24分鐘

         ·

        2022-06-30 19:34

        首先看下效果圖:



        實(shí)現(xiàn)步驟:


        • 繪制表盤(pán)[刻度,數(shù)字]

        • 繪制指針

        • 讓指針走起來(lái)~


        具體如下:


        繪制表盤(pán):


        首先需要計(jì)算出刻度的起點(diǎn)和終點(diǎn)坐標(biāo)值,這里我們通過(guò)構(gòu)建兩個(gè)半徑不同的同心圓,大圓半徑減小圓半徑,就可以得到一條刻度,只用改變角度,就可以獲取所有刻度:



            /**     * 通過(guò)改變角度值,獲取不同角度方向的外圓一點(diǎn)到圓心連線過(guò)內(nèi)圓一點(diǎn)的路徑坐標(biāo)集合     * @param x0 圓心x     * @param y0 圓心y     * @param outRadius 外圓半徑     * @param innerRadius 內(nèi)圓半徑     * @param angle 角度     * @return 返回     */    private float[] getDialPaths(int x0,int y0,int outRadius,int innerRadius,int angle){        float[] paths = new float[4];        paths[0]  = (float) (x0 + outRadius * Math.cos(angle * Math.PI / 180));        paths[1]  = (float) (y0 + outRadius * Math.sin(angle * Math.PI / 180));        paths[2]  = (float) (x0 + innerRadius * Math.cos(angle * Math.PI / 180));        paths[3]  = (float) (y0 + innerRadius * Math.sin(angle * Math.PI / 180));        return paths;    }


        秒針刻度間隔360/60 = 6 度,循環(huán)繪制60次,每一次角度加6,就可以了,繪制代碼如下:

        for (int i = 0; i < 60 ; i++) {            if (i % 5 == 0){                //獲取刻度路徑                float[] dialKdPaths = getDialPaths(halfMinLength, halfMinLength, halfMinLength - 8, halfMinLength * 5 / 6, -i * 6);                canvas.drawLines(dialKdPaths,paintKd30);                float[] dialPathsStr = getDialPaths(halfMinLength, halfMinLength, halfMinLength - 8, halfMinLength * 3 / 4, -i * 6);                canvas.drawText(strKedu[i/5],dialPathsStr[2] - 16,dialPathsStr[3] + 14,paintKd30Text);                continue;            }            float[] dialKdPaths = getDialPaths(halfMinLength, halfMinLength, halfMinLength - 8, halfMinLength * 7 / 8, -i * 6);            canvas.drawLines(dialKdPaths,paintKdSecond);        }


        繪制指針和旋轉(zhuǎn)指針


        這里的重點(diǎn)在于對(duì)指針旋轉(zhuǎn)的理解:



        通過(guò)上圖可以看到,我們通過(guò)旋轉(zhuǎn)畫(huà)布,然后繪制指針,最后恢復(fù)畫(huà)布,從而改變了指針的指向,具體操作過(guò)程是:


        1. 保存已經(jīng)繪制畫(huà)面

        2. 以一定角度旋轉(zhuǎn)畫(huà)布

        3. 繪制指針

        4. 恢復(fù)畫(huà)布角度


        代碼如下:以時(shí)針繪制為例

                //時(shí)針繪制        canvas.save(); //保存之前內(nèi)容        canvas.rotate(angleHour,halfMinLength,halfMinLength); //旋轉(zhuǎn)的是畫(huà)布,從而得到指針旋轉(zhuǎn)的效果        canvas.drawLine(halfMinLength,halfMinLength,halfMinLength,halfMinLength*3/4,paintHour);        canvas.restore(); //恢復(fù)


        讓時(shí)間走起來(lái)

        通過(guò)實(shí)時(shí)的計(jì)算時(shí)針,分針,秒針的角度,然后通知重新繪制畫(huà)面,我們就看到時(shí)間在走動(dòng)。

        /**     * 更新時(shí)分秒針的角度,開(kāi)始繪制     */    public void startRun(){        new Thread(new Runnable() {            @Override            public void run() {                while (drawable){                    try {                        Thread.sleep(1000); // 睡1s                        updataAngleSecond(); //更新秒針角度                        updataAngleMinute(); //更新分針角度                        updataAngleHour(); //更新時(shí)針角度                        postInvalidate(); //重新繪制                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }

        完整代碼如下:

        public class DialView extends View {
        private boolean drawable = true; //是否可以繪制 private int halfMinLength; //最小寬/高的一半長(zhǎng)度 private Paint paintKd30; //時(shí)針刻度線畫(huà)筆 private Paint paintKd30Text; // 時(shí)針數(shù)字畫(huà)筆 private Paint paintKdSecond; //秒針刻度線畫(huà)筆 private Paint paintHour; //時(shí)針畫(huà)筆 private Paint paintCircleBar;//指針圓心畫(huà)筆 private Paint paintMinute; //分針畫(huà)筆 private Paint paintSecond; //秒針畫(huà)筆 private float angleHour; //時(shí)針旋轉(zhuǎn)角度 private float angleMinute; //分針旋轉(zhuǎn)角度 private float angleSecond; //秒針旋轉(zhuǎn)角度 private int cuurSecond; //當(dāng)前秒 private int cuurMinute; //當(dāng)前分 private int cuurHour; //當(dāng)前時(shí) private Calendar mCalendar; private boolean isMorning = true; //上午/下午 private String[] strKedu = {"3","2","1","12","11","10","9","8","7","6","5","4"};

        public DialView(Context context) { this(context,null); }
        public DialView(Context context, AttributeSet attrs) { this(context, attrs,-1); }
        public DialView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr);
        initPaint(); //初始化畫(huà)筆 initTime(); //初始化時(shí)間
        }
        @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); halfMinLength = Math.min(width,height) / 2; System.out.println(halfMinLength); }
        @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //表盤(pán)刻度繪制 for (int i = 0; i < 60 ; i++) { if (i % 5 == 0){ //獲取刻度路徑 float[] dialKdPaths = getDialPaths(halfMinLength, halfMinLength, halfMinLength - 8, halfMinLength * 5 / 6, -i * 6); canvas.drawLines(dialKdPaths,paintKd30); float[] dialPathsStr = getDialPaths(halfMinLength, halfMinLength, halfMinLength - 8, halfMinLength * 3 / 4, -i * 6); canvas.drawText(strKedu[i/5],dialPathsStr[2] - 16,dialPathsStr[3] + 14,paintKd30Text); continue; } float[] dialKdPaths = getDialPaths(halfMinLength, halfMinLength, halfMinLength - 8, halfMinLength * 7 / 8, -i * 6); canvas.drawLines(dialKdPaths,paintKdSecond); } //指針繪制 //時(shí)針繪制 canvas.save(); //保存之前內(nèi)容 canvas.rotate(angleHour,halfMinLength,halfMinLength); //旋轉(zhuǎn)的是畫(huà)布,從而得到指針旋轉(zhuǎn)的效果 canvas.drawLine(halfMinLength,halfMinLength,halfMinLength,halfMinLength*3/4,paintHour); canvas.restore(); //恢復(fù) //繪制分針 canvas.save(); canvas.rotate(angleMinute,halfMinLength,halfMinLength); //旋轉(zhuǎn)的是畫(huà)布,從而得到指針旋轉(zhuǎn)的效果 canvas.drawLine(halfMinLength,halfMinLength,halfMinLength,halfMinLength/2,paintMinute); paintCircleBar.setColor(Color.rgb(75,75,75)); paintCircleBar.setShadowLayer(4,4,8,Color.argb(70,40,40,40)); canvas.drawCircle(halfMinLength,halfMinLength,24,paintCircleBar); canvas.restore(); //繪制秒針 canvas.save(); canvas.rotate(angleSecond,halfMinLength,halfMinLength); //旋轉(zhuǎn)的是畫(huà)布,從而得到指針旋轉(zhuǎn)的效果 canvas.drawLine(halfMinLength,halfMinLength + 40,halfMinLength,halfMinLength / 4 - 20,paintSecond); paintCircleBar.setColor(Color.rgb(178,34,34)); paintCircleBar.setShadowLayer(4,4,8,Color.argb(50,80,0,0)); canvas.drawCircle(halfMinLength,halfMinLength,12,paintCircleBar); canvas.restore(); }
        /** * 初始化時(shí),分,秒 */ private void initTime() { mCalendar = Calendar.getInstance(); cuurHour = mCalendar.get(Calendar.HOUR_OF_DAY); cuurMinute = mCalendar.get(Calendar.MINUTE); cuurSecond = mCalendar.get(Calendar.SECOND); if (cuurHour >= 12){ cuurHour = cuurHour - 12; isMorning = false; }else{ isMorning = true; } angleSecond = cuurSecond * 6f; angleMinute = cuurMinute * 6f; angleHour = cuurHour * 6f * 5f; }
        /** * 更新時(shí)分秒針的角度,開(kāi)始繪制 */ public void startRun(){ new Thread(new Runnable() { @Override public void run() { while (drawable){ try { Thread.sleep(1000); // 睡1s updataAngleSecond(); //更新秒針角度 updataAngleMinute(); //更新分針角度 updataAngleHour(); //更新時(shí)針角度 postInvalidate(); //重新繪制 } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); }
        private void updataAngleHour() { //更新時(shí)針角度 angleHour = angleHour + (30f/3600); if (angleHour >= 360){ angleHour = 0; cuurHour = 0; } }
        private void updataAngleMinute() { //更新分針角度 angleMinute = angleMinute + 0.1f; if (angleMinute >= 360){ angleMinute = 0; cuurMinute = 0; cuurHour += 1; } }
        private void updataAngleSecond() { //更新秒針角度 angleSecond = angleSecond + 6; cuurSecond += 1; if (angleSecond >= 360){ angleSecond = 0; cuurSecond = 0; cuurMinute += 1; //一分鐘同步一次本地時(shí)間 mCalendar = Calendar.getInstance(); cuurHour = mCalendar.get(Calendar.HOUR_OF_DAY); cuurMinute = mCalendar.get(Calendar.MINUTE); cuurSecond = mCalendar.get(Calendar.SECOND); if (cuurHour >= 12){ cuurHour = cuurHour - 12; isMorning = false; }else{ isMorning = true; } angleSecond = cuurSecond * 6f; angleMinute = cuurMinute * 6f; angleHour = cuurHour * 6f * 5f; } } /** * 停止繪制 */ public void stopDrawing(){ drawable = false; }
        /** * 通過(guò)改變角度值,獲取不同角度方向的外圓一點(diǎn)到圓心連線過(guò)內(nèi)圓一點(diǎn)的路徑坐標(biāo)集合 * @param x0 圓心x * @param y0 圓心y * @param outRadius 外圓半徑 * @param innerRadius 內(nèi)圓半徑 * @param angle 角度 * @return 返回 */ private float[] getDialPaths(int x0,int y0,int outRadius,int innerRadius,int angle){ float[] paths = new float[4]; paths[0] = (float) (x0 + outRadius * Math.cos(angle * Math.PI / 180)); paths[1] = (float) (y0 + outRadius * Math.sin(angle * Math.PI / 180)); paths[2] = (float) (x0 + innerRadius * Math.cos(angle * Math.PI / 180)); paths[3] = (float) (y0 + innerRadius * Math.sin(angle * Math.PI / 180)); return paths; }
        /** * 初始化畫(huà)筆參數(shù) */ private void initPaint() { paintKd30 = new Paint(); paintKd30.setStrokeWidth(8); paintKd30.setColor(Color.rgb(75,75,75)); paintKd30.setAntiAlias(true); paintKd30.setDither(true); paintKd30.setStrokeCap(Paint.Cap.ROUND);
        paintKd30Text = new Paint(); paintKd30Text.setTextAlign(Paint.Align.LEFT); //左對(duì)齊 paintKd30Text.setStrokeWidth(6); //設(shè)置寬度 paintKd30Text.setTextSize(40); //文字大小 paintKd30Text.setTypeface(Typeface.DEFAULT_BOLD); //加粗 paintKd30Text.setColor(Color.rgb(75,75,75)); //畫(huà)筆顏色 paintKd30Text.setAntiAlias(true); //抗鋸齒 paintKd30Text.setDither(true); //抖動(dòng) paintKd30Text.setStrokeCap(Paint.Cap.ROUND); //筆尖圓角 paintKd30Text.setShadowLayer(4,2,4,Color.argb(60,90,90,90)); //陰影
        paintKdSecond = new Paint(); paintKdSecond.setStrokeWidth(6); paintKdSecond.setColor(Color.rgb(75,75,75)); paintKdSecond.setAntiAlias(true); paintKdSecond.setDither(true); paintKdSecond.setStrokeCap(Paint.Cap.ROUND); paintKdSecond.setShadowLayer(4,5,10,Color.argb(50,80,80,80));
        paintHour = new Paint(); paintHour.setStrokeWidth(30); paintHour.setColor(Color.rgb(75,75,75)); paintHour.setAntiAlias(true); paintHour.setDither(true); paintHour.setStrokeCap(Paint.Cap.ROUND); paintHour.setShadowLayer(4,5,10,Color.argb(50,80,80,80));
        paintCircleBar = new Paint(); paintCircleBar.setStrokeWidth(6);// paintCircleBar.setColor(Color.rgb(178,34,34)); paintCircleBar.setAntiAlias(true); paintCircleBar.setDither(true); paintCircleBar.setStrokeCap(Paint.Cap.ROUND);// paintCircleBar.setShadowLayer(4,5,10,Color.argb(100,80,80,80));
        paintMinute = new Paint(); paintMinute.setStrokeWidth(30); paintMinute.setColor(Color.rgb(75,75,75)); paintMinute.setAntiAlias(true); paintMinute.setDither(true); paintMinute.setStrokeCap(Paint.Cap.ROUND); paintMinute.setShadowLayer(4,5,10,Color.rgb(80,80,80));
        paintSecond = new Paint(); paintSecond.setStrokeWidth(6); paintSecond.setColor(Color.rgb(180,30,30)); paintSecond.setAntiAlias(true); paintSecond.setDither(true); paintSecond.setStrokeCap(Paint.Cap.ROUND); paintSecond.setShadowLayer(4,2,10,Color.argb(100,90,90,90));
        }}


        代碼中有比較詳細(xì)的注釋。

        瀏覽 74
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            尹人大香蕉在线 | 色在线播放 | 人人做人人操 | 综合久久综合 | 黄片无码免费看 | 午夜寂寞自拍 | 国产91蝌蚪视频 | 新疆女人A片在线观看 | 午夜欧美性爱视频 | 欧美啪啪一区 |