首页 > 移动开发 > Android – Compass(罗盘) 详解

Android – Compass(罗盘) 详解

Compass(罗盘)是一个定制的视图, 继承View类, 重写了视图的边界(onMeasure)内容(onDraw);

如图:

以下是Compass的具体设计:

 

1. 创建CompassView类, 罗盘视图

位置: java->package->CompassView

[java] view plaincopy在CODE上查看代码片派生到我的代码片

  1. package mzx.spike.compass.app;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.Resources;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Paint;  
  7. import android.util.AttributeSet;  
  8. import android.view.View;  
  9. import android.view.accessibility.AccessibilityEvent;  
  10.   
  11. /** 
  12.  * Created by C.L.Wang on 14-3-16. 
  13.  */  
  14. public class CompassView extends View {  
  15.   
  16.     private float bearing; //方位  
  17.   
  18.     public void setBearing(float _bearing) {  
  19.         bearing = _bearing;  
  20.         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);  
  21.     }  
  22.   
  23.     public float getBearing() {  
  24.         return bearing;  
  25.     }  
  26.   
  27.     private Paint markerPaint;  
  28.     private Paint textPaint;  
  29.     private Paint circlePaint;  
  30.     private String northString;  
  31.     private String eastString;  
  32.     private String southString;  
  33.     private String westString;  
  34.     private int textHeight;  
  35.   
  36.     public CompassView(Context context) {  
  37.         super(context);  
  38.         initCompassView();  
  39.     }  
  40.   
  41.     public CompassView(Context context, AttributeSet attrs) {  
  42.         super(context, attrs);  
  43.         initCompassView();  
  44.     }  
  45.   
  46.     public CompassView(Context context, AttributeSet attrs, int defaultStyle) {  
  47.         super(context, attrs, defaultStyle);  
  48.         initCompassView();  
  49.     }  
  50.   
  51.     private void initCompassView() {  
  52.         setFocusable(true);  
  53.   
  54.         Resources r = this.getResources();  
  55.   
  56.         circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  57.         circlePaint.setColor(r.getColor(R.color.background_color));  
  58.         circlePaint.setStrokeWidth(1); //笔画宽度  
  59.         circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);  
  60.   
  61.         northString = r.getString(R.string.cardinal_north);  
  62.         eastString = r.getString(R.string.cardinal_east);  
  63.         southString = r.getString(R.string.cardinal_south);  
  64.         westString = r.getString(R.string.cardinal_west);  
  65.   
  66.         textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  67.         textPaint.setColor(r.getColor(R.color.text_color));  
  68.   
  69.         textHeight = (int)textPaint.measureText("yY");  
  70.   
  71.         markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  72.         markerPaint.setColor(r.getColor(R.color.marker_color));  
  73.     }  
  74.   
  75.     @Override  
  76.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  77.         int measuredWidth = measure(widthMeasureSpec);  
  78.         int measuredHeight = measure(heightMeasureSpec);  
  79.   
  80.         int d = Math.min(measuredWidth, measuredHeight);  
  81.   
  82.         setMeasuredDimension(d, d);  
  83.     }  
  84.   
  85.     protected int measure(int measureSpec) {  
  86.         int result;  
  87.   
  88.         int specMode = MeasureSpec.getMode(measureSpec);  
  89.         int specSize = MeasureSpec.getSize(measureSpec);  
  90.   
  91.         if (specMode == MeasureSpec.UNSPECIFIED) {  
  92.             result = 200;  
  93.         } else {  
  94.             result = specSize;  
  95.         }  
  96.   
  97.         return result;  
  98.     }  
  99.   
  100.     @Override  
  101.     protected void onDraw(Canvas canvas) {  
  102.         int mMeasuredWidth = getMeasuredWidth();  
  103.         int mMeasuredHeight = getMeasuredHeight();  
  104.   
  105.         int px = mMeasuredWidth/2;  
  106.         int py = mMeasuredHeight/2;  
  107.   
  108.         int radius = Math.min(px, py);  
  109.   
  110.         canvas.drawCircle(px, py, radius, circlePaint);  
  111.   
  112.         canvas.save();  
  113.         canvas.rotate(-bearing, px, py); //相反方向旋转  
  114.   
  115.         int textWidth = (int)textPaint.measureText("W");  
  116.         int cardinalX = px-textWidth/2;  
  117.         int cardinalY = py-radius+textHeight;  
  118.   
  119.         for (int i=0; i<24; i++) {  
  120.             canvas.drawLine(px, py-radius, px, py-radius+10, markerPaint);  
  121.   
  122.             canvas.save();  
  123.             canvas.translate(0, textHeight);  
  124.   
  125.             if (i%6 == 0) {  
  126.                 String dirString = "";  
  127.                 switch (i) {  
  128.                     case (0) : {  
  129.                         dirString = northString;  
  130.                         int arrowY = 2*textHeight;  
  131.                         canvas.drawLine(px, arrowY, px-53*textHeight, markerPaint);  
  132.                         canvas.drawLine(px, arrowY, px+53*textHeight, markerPaint);  
  133.                         break;  
  134.                     }  
  135.   
  136.                     case (6) : dirString = eastString; break;  
  137.                     case (12) : dirString = southString; break;  
  138.                     case (18) : dirString = westString; break;  
  139.                 }  
  140.   
  141.                 canvas.drawText(dirString, cardinalX, cardinalY, textPaint);  
  142.             }  
  143.   
  144.             else if (i%3 == 0) {  
  145.                 String angle = String.valueOf(i*15);  
  146.                 float angleTextWidth = textPaint.measureText(angle);  
  147.   
  148.                 int angleTextX = (int)(px-angleTextWidth/2);  
  149.                 int angleTextY = py-radius+textHeight;  
  150.                 canvas.drawText(angle, angleTextX, angleTextY, textPaint);  
  151.             }  
  152.   
  153.             canvas.restore();  
  154.   
  155.             canvas.rotate(15, px, py);  
  156.         }  
  157.         canvas.restore();  
  158.     }  
  159.   
  160.     @Override  
  161.     public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) {  
  162.         super.dispatchPopulateAccessibilityEvent(event);  
  163.   
  164.         if (isShown()) {  
  165.             String bearingStr = String.valueOf(bearing);  
  166.   
  167.             event.getText().add(bearingStr);  
  168.   
  169.             return true;  
  170.         } else  
  171.             return false;  
  172.     }  
  173. }  



这个类代码较多, 详解:

1. 私有变量bearing, 罗盘的方位, 包含set()和get()方法, 唯一可以操作的参数;

2. 资源的私有变量, 表示图画, 字符串, 高度, 从资源(xml)中获得;

3. 重载构造函数, 添加初始化资源程序initCompassView();

4. 在初始化程序initCompassView()中, 使用资源表的引用(getResources),初始化资源变量;

5. 重写onMeasure()方法, 创建边界, 使用setMeasuredDimension确定边界;

6. 在方法measure中, 具体的边界实现;

7. 重写onDraw()方法, 绘制图像;

8. onDraw(), 绘制: 圆形(drawCircle), 旋转(rotate), 24个线, 4个字母, 4个度数, 小箭头;

9. 注意set()方法中的sendAccessibilityEvent广播访问事件, 重写dispatchPopulateAccessibilityEvent方法, 接受广播事件, 改变应用程序的状态;

10. set方法可以定制旋转的角度;

 

2. 修改资源文件, 颜色(colors.xml)和字符串(strings.xml)

位置: res->values->colors&strings

[html] view plaincopy在CODE上查看代码片派生到我的代码片

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <color name="background_color">#F555</color>  
  4.     <color name="marker_color">#AFFF</color>  
  5.     <color name="text_color">#AFFF</color>  
  6. </resources>  

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <string name="app_name">Compass</string>  
  5.     <string name="action_settings">Settings</string>  
  6.     <string name="cardinal_north">N</string>  
  7.     <string name="cardinal_east">E</string>  
  8.     <string name="cardinal_south">S</string>  
  9.     <string name="cardinal_west">W</string>  
  10.   
  11. </resources>  



3. 修改主布局文件(activity_main.xml)

位置: res->layout->activity_main.xml

[html] view plaincopy在CODE上查看代码片派生到我的代码片

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  6.     android:paddingRight="@dimen/activity_horizontal_margin"  
  7.     android:paddingTop="@dimen/activity_vertical_margin"  
  8.     android:paddingBottom="@dimen/activity_vertical_margin"  
  9.     tools:context="mzx.spike.compass.app.MainActivity">  
  10.   
  11.     <mzx.spike.compass.app.CompassView  
  12.         android:id="@+id/compassView"  
  13.         android:layout_width="match_parent"  
  14.         android:layout_height="match_parent"  
  15.     />  
  16.   
  17. </RelativeLayout>  


实现文件(app.CompassView), 注册在布局文件中, 指定ID(compassView);

 

 

4. 修改主Activity的实现(MainActivity.java)

位置: java->package->MainActivity.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片

  1. ......  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         CompassView cv = (CompassView)this.findViewById(R.id.compassView);  
  7.         cv.setBearing(45);  
  8.     }  
  9. ......  


填充视图, 获得资源文件的引用(findViewById),设置角度(setBearing);

 

5. 执行程序:

 

下载位置:


本文固定链接: http://www.devba.com/index.php/archives/5270.html | 开发吧

报歉!评论已关闭.