Android 车载的小小指南针【源码】

2010-11-12 22:17

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(
-2060);
            mPath.lineTo(
050);
            mPath.lineTo(
2060);
            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] / 2null);
            canvas.rotate(
360 + mValues[0]);
            canvas.drawBitmap(mBitmapArray[
1 + idDelta],
                    
-mBitmapWidth[1 + idDelta] / 2,
                    
-mBitmapHeight[1 + idDelta] / 2null);

        } 
else {
            canvas.drawBitmap(mBitmapArray[
0 + idDelta],
                    
-mBitmapWidth[0 + idDelta] / 2,
                    
-mBitmapHeight[0 + idDelta] / 2null);

            canvas.drawBitmap(mBitmapArray[
1 + idDelta],
                    
-mBitmapWidth[1 + idDelta] / 2,
                    
-mBitmapHeight[1 + idDelta] / 2null);
        }
    }
  //角度值
    
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下载:

/Files/TerryBlog/CarCompass.7z  改成apk,可能不能打开加密了。

作者: Terry_龙 发表于 2010-11-12 14:17 原文链接

评论: 2 查看评论 发表评论


最新新闻:
· 开源播放器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)

编辑推荐:Sina App Engine架构:云计算时代的分布式Web服务解决方案

网站导航:博客园首页  我的园子  新闻  闪存  小组  博问  知识库