Android 车载的小小指南针【源码】
by Terry_龙
at 2010-11-12 14:17:00
original http://www.cnblogs.com/TerryBlog/archive/2010/11/12/1875657.html
在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 代码:
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就可以在布局中使用:
<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等另外其他传过来的参数,这个是后话。
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下载:
/Files/TerryBlog/CarCompass.7z 改成apk,可能不能打开加密了。
作者: Terry_龙 发表于 2010-11-12 14:17 原文链接
最新新闻:
· 开源播放器MPlayer十周年(2010-11-12 23:45)
· IBM与北工大建成中国首个科教云 基于刀片集群(2010-11-12 23:39)
· 新应用按地理位置展示全球Twitter消息(2010-11-12 22:55)
· 苹果甲骨文联合发布Mac版OpenJDK项目(2010-11-12 22:50)
· 10款相似图片搜索引擎(2010-11-12 22:30)