android之旋轉的刻度盤


      這是在學習android的Canvas繪圖技巧時做的一個實例。主要用的核心方法就是canvas.save,canvas.rotate,

canvas.translate以及canvas.restore。通過這個小例子的練習,可以更好的掌握這些方法的使用。

     先貼一張最終的效果圖吧,如下:

 

    來一步一步的來寫代碼吧。新建一個項目,然后新建類MyView繼承自View,下面我們來首先將外盤畫出來。即最外面的那個

圓。代碼如下:

  1 package com.example.testcanvas;
  2 
  3 import android.content.Context;
  4 import android.graphics.Canvas;
  5 import android.graphics.Paint;
  6 import android.util.AttributeSet;
  7 import android.view.DragEvent;
  8 import android.view.View;
  9 /**
 10  * 畫一個儀表盤出來,哈哈
 11  * @author fuly1314
 12  *
 13  */
 14 public class MyView extends View{
 15     
 16     private int width;//view寬度
 17     private int height;//view的高度
 18     private int radius;//外層圓的半徑

 22     public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
 23         super(context, attrs, defStyleAttr);
 24     }
 25 
 26     public MyView(Context context, AttributeSet attrs) {
 27         super(context, attrs);
 28     }
 29 
 30     public MyView(Context context) {
 31         super(context);
 32     }
 33     
 34     
 35     protected void onDraw(Canvas canvas) {
 36         
 37         width = getWidth();
 38         height = getHeight();
 39         radius = width/2;//外部圓盤的半徑
 40         
 41         Paint paintCircle = new Paint();
 42         paintCircle.setStyle(Paint.Style.STROKE);
 43         paintCircle.setStrokeWidth(5);
 44         paintCircle.setAntiAlias(true);
 45         //畫出外層的圓盤
 46         canvas.drawCircle(width/2, height/2, radius, paintCircle);

118     }
119 
120 }

 

     代碼很簡單,相信這一步大家都不陌生。我們將圓形置在了屏幕的中心位置,並讓半徑為寬度的一半。其他的就不多說了。

    接下來我們來畫刻度值。

    首先刻度值有兩種,一種是大的刻度值,這類刻度值都是可以被6整除的,另外一類則不可以。這個在畫的時候很容易解決。

不容易解決的是要按照一定的弧度來把刻度值給畫上。如果在這個時候,不利用canvcas.rotate方法的話,簡直是要愁死人了。

還好有這么一個方法可以很方便的解決這個問題。我們先看代碼,然后再來詳細解釋。增加的代碼如下:

package com.example.testcanvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.View;
/**
 * 畫一個儀表盤出來,哈哈
 * @author fuly1314
 *
 */
public class MyView extends View{
    
    private int width;//view寬度
    private int height;//view的高度
    private int radius;//外層圓的半徑
 public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context) {
        super(context);
    }
    
    
    protected void onDraw(Canvas canvas) {
        
        width = getWidth();
        height = getHeight();
        radius = width/2;//外部圓盤的半徑
        
        Paint paintCircle = new Paint();
        paintCircle.setStyle(Paint.Style.STROKE);
        paintCircle.setStrokeWidth(5);
        paintCircle.setAntiAlias(true);
        //畫出外層的圓盤
        canvas.drawCircle(width/2, height/2, radius, paintCircle);
        
        /**
         * 下面的代碼要畫出刻度值
         */
        
        for(int i =0;i<24;i++)
        {
            
            Paint paintDegree = new Paint();
            
            if(i%6 == 0)//畫的是大的刻度值
            {
                
                paintDegree.setStrokeWidth(5);
                paintDegree.setTextSize(30);
                
                canvas.drawLine(width/2, height/2-radius, width/2,
                        height/2-radius+60, paintDegree);
                canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2, 
                        height/2-radius+90, paintDegree);
            }else//畫的是小刻度
            {
                paintDegree.setStrokeWidth(3);
                paintDegree.setTextSize(25);
                
                canvas.drawLine(width/2, height/2-radius, width/2,
                        height/2-radius+30, paintDegree);
                canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2, 
                        height/2-radius+60, paintDegree);

            }
            
            //將坐標系繞點(width/2,height/2)旋轉15度
         canvas.rotate(360/24, width/2, height/2); 
        }
        

    }

}

 

 

    紅色部分就是增加的畫刻度線的代碼。代碼最核心的地方就是上面被黃色背景標注的地方。我們知道在畫刻度的時候,刻度0是最好畫的,如果

每一個刻度都能像畫0刻度這么容易的話,豈不是太過癮了!Android可謂在此時深深的了解你的願望啊,於是Canvas.rotate方法就過來拯救你了!

你把一個圓分成了24份,每一份是15度,那么從畫0刻度開始每次畫一個刻度就把坐標系旋轉15度,再來畫下一個刻度,是不是就一直跟畫0刻度的

方法是一樣的了呢?顯然是的!之所以應用rotate方法讓坐標系圍繞圓心旋轉15度,可不就是為了這個嘛!因此你會發現在循環畫刻度時,都是按照

畫刻度0的畫法來畫的!!怎么樣,神奇吧!至此,所有的刻度我們算是畫好了。

 

    最后我們來畫兩根指針。

   再次修改代碼如下:

  1 package com.example.testcanvas;
  2 
  3 import android.content.Context;
  4 import android.graphics.Canvas;
  5 import android.graphics.Paint;
  6 import android.util.AttributeSet;
  7 import android.view.DragEvent;
  8 import android.view.View;
  9 /**
 10  * 畫一個儀表盤出來,哈哈
 11  * @author fuly1314
 12  *
 13  */
 14 public class MyView extends View{
 15     
 16     private int width;//view寬度
 17     private int height;//view的高度
 18     private int radius;//外層圓的半徑
 19     private int hcount = 0;
 20     private int mcount = 0;
 21 
 22     public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
 23         super(context, attrs, defStyleAttr);
 24     }
 25 
 26     public MyView(Context context, AttributeSet attrs) {
 27         super(context, attrs);
 28     }
 29 
 30     public MyView(Context context) {
 31         super(context);
 32     }
 33     
 34     
 35     protected void onDraw(Canvas canvas) {
 36         
 37         width = getWidth();
 38         height = getHeight();
 39         radius = width/2;//外部圓盤的半徑
 40         
 41         Paint paintCircle = new Paint();
 42         paintCircle.setStyle(Paint.Style.STROKE);
 43         paintCircle.setStrokeWidth(5);
 44         paintCircle.setAntiAlias(true);
 45         //畫出外層的圓盤
 46         canvas.drawCircle(width/2, height/2, radius, paintCircle);
 47         
 48         /**
 49          * 下面的代碼要畫出刻度值
 50          */
 51         
 52         for(int i =0;i<24;i++)
 53         {
 54             
 55             Paint paintDegree = new Paint();
 56             
 57             if(i%6 == 0)//畫的是大的刻度值
 58             {
 59                 
 60                 paintDegree.setStrokeWidth(5);
 61                 paintDegree.setTextSize(30);
 62                 
 63                 canvas.drawLine(width/2, height/2-radius, width/2,
 64                         height/2-radius+60, paintDegree);
 65                 canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2, 
 66                         height/2-radius+90, paintDegree);
 67             }else//畫的是小刻度
 68             {
 69                 paintDegree.setStrokeWidth(3);
 70                 paintDegree.setTextSize(25);
 71                 
 72                 canvas.drawLine(width/2, height/2-radius, width/2,
 73                         height/2-radius+30, paintDegree);
 74                 canvas.drawText(String.valueOf(i), width/2-paintDegree.measureText(String.valueOf(i))/2, 
 75                         height/2-radius+60, paintDegree);
 76 
 77             }
 78             
 79             //將坐標系繞點(width/2,height/2)旋轉15度
 80             canvas.rotate(360/24, width/2, height/2);
 81             
 82         }
 83         
 84         
 85         canvas.save();//先保存下,因為下面要用到坐標的平移
 86         
 87        //將坐標系的平移至原點為(wdith/2,height/2)的地方 88 canvas.translate(width/2, height/2);
 89         
 90         int hourRadius = radius*2/4;
 91         int minuteRaidus = radius*3/4;
 92         int hx = (int) (hourRadius*Math.cos(hcount));
 93         int hy = (int) (hourRadius*Math.sin(hcount));
 94         int mx = (int) (minuteRaidus*Math.cos(mcount));
 95         int my = (int) (minuteRaidus*Math.sin(mcount));
 96         
 97         Paint paintHour = new Paint();
 98         paintHour.setStrokeWidth(7);
 99         
100         canvas.drawLine(0, 0,hx , hy, paintHour);
101         
102         Paint paintMinute = new Paint();
103         paintMinute.setStrokeWidth(3);
104         
105         canvas.drawLine(0, 0, mx, my, paintMinute);
106         
107         canvas.restore();
108         
109         
110         mcount++;
111         
112         if(mcount%10 == 0){
113             hcount++;
114         }
115         
116         postInvalidateDelayed(500);
117         
118     }
119 
120 }

 

        核心代碼就是黃色背景標注的代碼!因為在畫指針的時候,我們發現還是不爽,還有從屏幕左上角來計算坐標。所以就使用canvas.translate方法

直接將坐標系給平移了。直接平移到圓心,因為我們的出發點就在圓形。接下來是不是畫那些指針就十分容易了!在這里,我們使用了兩個變量來控制

指針的轉動分別是hcount和mcount。在轉動的過程中怎么確定指針的坐標呢?畫個圖來說明吧。如下:

     代碼中的求指針的坐標的時候就是按照這個思路來求的。相信上面的代碼應該沒有什么問題了吧。當然了,代碼寫的亂,有很多可以優化的時候。

這里只是為了練習下canvas的方法,不去深究了。最后別忘記調用postInvalidateDelayed方法來進行刷新。

 

 

     至此,這個能動的儀表盤就做好了。下面把它放進布局中吧。修改activity_main.xml代碼如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
  >

    <com.example.testcanvas.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>

 

 

 

      直接運行程序吧!效果跟上面的貼圖一樣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM