Android - Compass(罗盘) 详解

Compass(罗盘) 详解


本文地址: http://blog.csdn.net/caroline_wendy/article/details/21379067


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

如图:

Android - Compass(罗盘) 详解_第1张图片


以下是Compass的具体设计:


1. 创建CompassView类, 罗盘视图

位置: java->package->CompassView


package mzx.spike.compass.app;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;

/**
 * Created by C.L.Wang on 14-3-16.
 */
public class CompassView extends View {

    private float bearing; //方位

    public void setBearing(float _bearing) {
        bearing = _bearing;
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
    }

    public float getBearing() {
        return bearing;
    }

    private Paint markerPaint;
    private Paint textPaint;
    private Paint circlePaint;
    private String northString;
    private String eastString;
    private String southString;
    private String westString;
    private int textHeight;

    public CompassView(Context context) {
        super(context);
        initCompassView();
    }

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

    public CompassView(Context context, AttributeSet attrs, int defaultStyle) {
        super(context, attrs, defaultStyle);
        initCompassView();
    }

    private void initCompassView() {
        setFocusable(true);

        Resources r = this.getResources();

        circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        circlePaint.setColor(r.getColor(R.color.background_color));
        circlePaint.setStrokeWidth(1); //笔画宽度
        circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);

        northString = r.getString(R.string.cardinal_north);
        eastString = r.getString(R.string.cardinal_east);
        southString = r.getString(R.string.cardinal_south);
        westString = r.getString(R.string.cardinal_west);

        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setColor(r.getColor(R.color.text_color));

        textHeight = (int)textPaint.measureText("yY");

        markerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        markerPaint.setColor(r.getColor(R.color.marker_color));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredWidth = measure(widthMeasureSpec);
        int measuredHeight = measure(heightMeasureSpec);

        int d = Math.min(measuredWidth, measuredHeight);

        setMeasuredDimension(d, d);
    }

    protected int measure(int measureSpec) {
        int result;

        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.UNSPECIFIED) {
            result = 200;
        } else {
            result = specSize;
        }

        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int mMeasuredWidth = getMeasuredWidth();
        int mMeasuredHeight = getMeasuredHeight();

        int px = mMeasuredWidth/2;
        int py = mMeasuredHeight/2;

        int radius = Math.min(px, py);

        canvas.drawCircle(px, py, radius, circlePaint);

        canvas.save();
        canvas.rotate(-bearing, px, py); //相反方向旋转

        int textWidth = (int)textPaint.measureText("W");
        int cardinalX = px-textWidth/2;
        int cardinalY = py-radius+textHeight;

        for (int i=0; i<24; i++) {
            canvas.drawLine(px, py-radius, px, py-radius+10, markerPaint);

            canvas.save();
            canvas.translate(0, textHeight);

            if (i%6 == 0) {
                String dirString = "";
                switch (i) {
                    case (0) : {
                        dirString = northString;
                        int arrowY = 2*textHeight;
                        canvas.drawLine(px, arrowY, px-5, 3*textHeight, markerPaint);
                        canvas.drawLine(px, arrowY, px+5, 3*textHeight, markerPaint);
                        break;
                    }

                    case (6) : dirString = eastString; break;
                    case (12) : dirString = southString; break;
                    case (18) : dirString = westString; break;
                }

                canvas.drawText(dirString, cardinalX, cardinalY, textPaint);
            }

            else if (i%3 == 0) {
                String angle = String.valueOf(i*15);
                float angleTextWidth = textPaint.measureText(angle);

                int angleTextX = (int)(px-angleTextWidth/2);
                int angleTextY = py-radius+textHeight;
                canvas.drawText(angle, angleTextX, angleTextY, textPaint);
            }

            canvas.restore();

            canvas.rotate(15, px, py);
        }
        canvas.restore();
    }

    @Override
    public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) {
        super.dispatchPopulateAccessibilityEvent(event);

        if (isShown()) {
            String bearingStr = String.valueOf(bearing);

            event.getText().add(bearingStr);

            return true;
        } else
            return false;
    }
}


这个类代码较多, 详解:

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


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="background_color">#F555</color>
    <color name="marker_color">#AFFF</color>
    <color name="text_color">#AFFF</color>
</resources>

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Compass</string>
    <string name="action_settings">Settings</string>
    <string name="cardinal_north">N</string>
    <string name="cardinal_east">E</string>
    <string name="cardinal_south">S</string>
    <string name="cardinal_west">W</string>

</resources>


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

位置: res->layout->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"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="mzx.spike.compass.app.MainActivity">

    <mzx.spike.compass.app.CompassView
        android:id="@+id/compassView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />

</RelativeLayout>

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



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

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


......
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CompassView cv = (CompassView)this.findViewById(R.id.compassView);
        cv.setBearing(45);
    }
......

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


5. 执行程序:


下载位置: http://download.csdn.net/detail/u012515223/7052999


Android - Compass(罗盘) 详解_第2张图片

你可能感兴趣的:(android,onDraw,compass,onmeasure,Mystra)