在Api Demo 裡面有一個指南針的例子,路徑為com.example.android.apis.graphics-》Compass.java。源碼使用的是SensorListener 做為動力感應為指南針傳遞角度。基於此原理不斷的去畫VIEW,目前能搜索出來的代碼大致也是根據此DEMO做出修改。代碼如下:
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.graphics;
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Config;
import android.util.Log;
import android.view.View;
public class Compass extends GraphicsActivity {
private static final String TAG = "Compass";
private SensorManager mSensorManager;
private SampleView mView;
private float[] mValues;
private final SensorListener mListener = new SensorListener() {
public void onSensorChanged(int sensor, float[] values) {
if (Config.LOGD) Log.d(TAG, "sensorChanged (" + values[0] + ", " + values[1] + ", " + values[2] + ")");
mValues = values;
if (mView != null) {
mView.invalidate();
}
}
public void onAccuracyChanged(int sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mView = new SampleView(this);
setContentView(mView);
}
@Override
protected void onResume()
{
if (Config.LOGD) Log.d(TAG, "onResume");
super.onResume();
mSensorManager.registerListener(mListener,
SensorManager.SENSOR_ORIENTATION,
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
if (Config.LOGD) Log.d(TAG, "onStop");
mSensorManager.unregisterListener(mListener);
super.onStop();
}
private class SampleView extends View {
private Paint mPaint = new Paint();
private Path mPath = new Path();
private boolean mAnimate;
private long mNextTime;
public SampleView(Context context) {
super(context);
// Construct a wedge-shaped path
mPath.moveTo(0, -50);
mPath.lineTo(-20, 60);
mPath.lineTo(0, 50);
mPath.lineTo(20, 60);
mPath.close();
}
@Override protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
canvas.drawColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
int w = canvas.getWidth();
int h = canvas.getHeight();
int cx = w / 2;
int cy = h / 2;
canvas.translate(cx, cy);
if (mValues != null) {
canvas.rotate(-mValues[0]);
}
canvas.drawPath(mPath, mPaint);
}
@Override
protected void onAttachedToWindow() {
mAnimate = true;
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
mAnimate = false;
super.onDetachedFromWindow();
}
}
}
運行結果:
根據Api Demo的例子,我們就可以方便的實現自己想要的指南針效果了。下面是根據Api Demo給出的實現思路自己完成的一個小小指南針,要實現的效果為如下所示:
首先,項目啟動時,設置屏幕為橫屏顯示:
在配置文件下對應的Activity 加入如下代碼:
android:screenOrientation="landscape"
接著畫View 將指南針的view 參照api Demo 畫出來,由於我個人喜歡View 保存相對的獨立性,所以都是將View 盡量的標准化,即可以以編程方式引用也可以在Layout 文件中使用XML引用。下面是我指南針View 代碼:
package com.yaomei.view;
import java.io.InputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.BitmapFactory.Options;
import android.util.AttributeSet;
import android.view.View;
import com.yaomei.compass.R;
public class CompassView extends View {
private Bitmap[] mBitmapArray = new Bitmap[4];
InputStream is;
private float[] mValues;
int[] mBitmapWidth = new int[4];
int[] mBitmapHeight = new int[4];
public CompassView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
public CompassView(Context context, AttributeSet attrs) {
super(context, attrs);
BitmapFactory.Options opts = new Options();
opts.inJustDecodeBounds = false;
setBitMapArray(context, 0, opts, R.drawable.panel);
setBitMapArray(context, 1, opts, R.drawable.compass_digree);
}
/**
* 設置bitmap數組個下標的值
*
* @param index
* @param opts
* @param resid
*/
private void setBitMapArray(Context context, int index,
BitmapFactory.Options opts, int resid) {
is = context.getResources().openRawResource(resid);
mBitmapArray[index] = BitmapFactory.decodeStream(is);
mBitmapWidth[index] = mBitmapArray[index].getWidth();
mBitmapHeight[index] = mBitmapArray[index].getHeight();
mBitmapArray[index + 2] = BitmapFactory.decodeStream(is, null, opts);
mBitmapHeight[index + 2] = mBitmapArray[index + 2].getHeight();
mBitmapWidth[index + 2] = mBitmapArray[index + 2].getWidth();
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
int w = canvas.getWidth();
int h = canvas.getHeight();
int cx = w / 2;
int cy = h / 2;
canvas.translate(cx, cy);
drawPictures(canvas, 0);
}
private void drawPictures(Canvas canvas, int idDelta) {
if (mValues != null) {
// Log.d(TAG, "mValues[0] = "+ mValues[0]);
canvas.rotate(-mValues[0]);
canvas.drawBitmap(mBitmapArray[0 + idDelta],
-mBitmapWidth[0 + idDelta] / 2,
-mBitmapHeight[0 + idDelta] / 2, null);
canvas.rotate(360 + mValues[0]);
canvas.drawBitmap(mBitmapArray[1 + idDelta],
-mBitmapWidth[1 + idDelta] / 2,
-mBitmapHeight[1 + idDelta] / 2, null);
} else {
canvas.drawBitmap(mBitmapArray[0 + idDelta],
-mBitmapWidth[0 + idDelta] / 2,
-mBitmapHeight[0 + idDelta] / 2, null);
canvas.drawBitmap(mBitmapArray[1 + idDelta],
-mBitmapWidth[1 + idDelta] / 2,
-mBitmapHeight[1 + idDelta] / 2, null);
}
}
//角度值
public void setValue(float[] value) {
this.mValues = value;
}
}
通過上面的繪制VIEW就可以在布局中使用:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:gravity="center">
<TextView android:id="@+id/title" android:textColor="@drawable/white"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content" android:layout_height="wrap_content">
</TextView>
<com.yaomei.view.CompassView android:id="@+id/compass"
android:layout_width="wrap_content" android:layout_height="wrap_content">
</com.yaomei.view.CompassView>
</LinearLayout>
對應Activity使用SensorListener為view 傳遞角度,當然如果是在車載上面可能不是用SensorListener而是使用GPS等另外其他傳過來的參數,這個是後話。
package com.yaomei.compass;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.WindowManager;
import android.widget.TextView;
import com.yaomei.view.CompassView;
@SuppressWarnings("deprecation")
public class CompassActivity extends Activity {
private SensorManager mSensorManager;
private CompassView mView;
private String text = "";
private Resources mRes;
private TextView tv;
public final SensorListener mListtenr = new SensorListener() {
@Override
public void onSensorChanged(int sensor, float[] values) {
// TODO Auto-generated method stub
synchronized (this) {
mView.setValue(values);
if (Math.abs(values[0] - 0.0f) < 1)
return;
switch ((int) values[0]) {
case 0:
text = mRes.getText(R.string.North).toString();
break;
case 90:
text = mRes.getText(R.string.West).toString();
break;
case 180:
text = mRes.getText(R.string.South).toString();
break;
case 270:
text = mRes.getText(R.string.East).toString();
break;
default:
int v = (int) values[0];
if (v > 0 && v < 90) {
text = mRes.getText(R.string.North_west).toString()
+ " " + v + " 度";
}
if (v > 90 && v < 180) {
text = mRes.getText(R.string.South_west).toString()
+ " " + (180 - v) + " 度";
}
if (v > 180 && v < 270) {
text = mRes.getText(R.string.South_east).toString()
+ " " + (v - 180) + " 度";
}
if (v > 270 && v < 360) {
text = mRes.getText(R.string.North_east).toString()
+ " " + (360 - v) + " 度";
}
break;
}
tv.setText(text);
if (mView != null) {
mView.invalidate();
}
}
}
@Override
public void onAccuracyChanged(int sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mRes = this.getResources();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
findView();
}
void findView() {
tv = (TextView) findViewById(R.id.title);
mView = (CompassView) findViewById(R.id.compass);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mSensorManager.registerListener(mListtenr,
SensorManager.SENSOR_ORIENTATION,
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
mSensorManager.unregisterListener(mListtenr);
super.onStop();
}
}
apk下載:
CarCompass.7z 改成apk,可能不能打開加密了。
轉自:http://www.cnblogs.com/TerryBlog/archive/2010/11/12/1875657.html