簡單指南針的實現(xiàn):將方向傳感器的第一個參數(shù)(與正北方的夾角)傳遞給圖片,進行旋轉(zhuǎn)動畫反向相等的角度
public class MainActivity extends Activity implements SensorEventListener
{
// 定義顯示指南針的圖片
ImageView znzImage;
// 記錄指南針圖片轉(zhuǎn)過的角度
float currentDegree = 0f;
SensorManager mSensorManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 獲取界面中顯示指南針的圖片
znzImage = (ImageView) findViewById(R.id.znzImage);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
}
@Override
protected void onResume()
{
super.onResume();
// 為系統(tǒng)的方向傳感器注冊監(jiān)聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onStop()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onSensorChanged(SensorEvent event)
{
int sensorType = event.sensor.getType();
if(sensorType==Sensor.TYPE_ORIENTATION){
float degree = event.values[0];
// 創(chuàng)建旋轉(zhuǎn)動畫(反向轉(zhuǎn)過degree度)
RotateAnimation ra = new RotateAnimation(currentDegree,
-degree, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
// 設(shè)置動畫的持續(xù)時間
ra.setDuration(200);
// 運行動畫
znzImage.startAnimation(ra);
currentDegree = -degree;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
水平儀:將方向傳感器返回的底部谓晌、右側(cè)翹起角度傳給氣泡圖片茁影,控制其在屏幕上的位置
public class MyView extends View
{
// 定義水平儀儀表盤圖片
Bitmap back;
// 定義水平儀中的氣泡圖標
Bitmap bubble;
// 定義水平儀中氣泡 的X适刀、Y座標
int bubbleX, bubbleY;
public MyView(Context context, AttributeSet attrs)
{
super(context, attrs);
// 加載水平儀圖片和氣泡圖片
back = BitmapFactory.decodeResource(getResources()
, R.drawable.back);
bubble = BitmapFactory
.decodeResource(getResources(), R.drawable.bubble);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// 繪制水平儀表盤圖片
canvas.drawBitmap(back, 0, 0, null);
// 根據(jù)氣泡座標繪制氣泡
canvas.drawBitmap(bubble, bubbleX, bubbleY, null);
}
}
public class MainActivity extends Activity implements SensorEventListener
{
// 定義水平儀的儀表盤
MyView show;
// 定義水平儀能處理的最大傾斜角踱葛,超過該角度,氣泡將直接在位于邊界春寿。
int MAX_ANGLE = 30;
// // 定義真機的Sensor管理器
SensorManager mSensorManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 獲取水平儀的主組件
show = (MyView) findViewById(R.id.show);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
}
@Override
public void onResume()
{
super.onResume();
// 為系統(tǒng)的方向傳感器注冊監(jiān)聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onStop()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
// // 真機上獲取觸發(fā)event的傳感器類型
int sensorType = event.sensor.getType();
if(sensorType==Sensor.TYPE_ORIENTATION){
// 獲取與Y軸的夾角
float yAngle = values[1];
// 獲取與Z軸的夾角
float zAngle = values[2];
// 氣泡位于中間時(水平儀完全水平)朗涩,氣泡的X、Y座標
int x = (show.back.getWidth() - show.bubble.getWidth()) / 2;
int y = (show.back.getHeight() - show.bubble.getHeight()) / 2;
// 如果與Z軸的傾斜角還在最大角度之內(nèi)
if (Math.abs(zAngle) <= MAX_ANGLE)
{
// 根據(jù)與Z軸的傾斜角度計算X座標的變化值(傾斜角度越大绑改,X座標變化越大)
int deltaX = (int) ((show.back.getWidth() - show.bubble
.getWidth()) / 2 * zAngle / MAX_ANGLE);
x += deltaX;
}
// 如果與Z軸的傾斜角已經(jīng)大于MAX_ANGLE谢床,氣泡應(yīng)到最左邊
else if (zAngle > MAX_ANGLE)
{
x = 0;
}
// 如果與Z軸的傾斜角已經(jīng)小于負的MAX_ANGLE兄一,氣泡應(yīng)到最右邊
else
{
x = show.back.getWidth() - show.bubble.getWidth();
}
// 如果與Y軸的傾斜角還在最大角度之內(nèi)
if (Math.abs(yAngle) <= MAX_ANGLE)
{
// 根據(jù)與Y軸的傾斜角度計算Y座標的變化值(傾斜角度越大,Y座標變化越大)
int deltaY = (int) ((show.back.getHeight() - show.bubble
.getHeight()) / 2 * yAngle / MAX_ANGLE);
y += deltaY;
}
// 如果與Y軸的傾斜角已經(jīng)大于MAX_ANGLE萤悴,氣泡應(yīng)到最下邊
else if (yAngle > MAX_ANGLE)
{
y = show.back.getHeight() - show.bubble.getHeight();
}
// 如果與Y軸的傾斜角已經(jīng)小于負的MAX_ANGLE瘾腰,氣泡應(yīng)到最右邊
else
{
y = 0;
}
// 如果計算出來的X、Y座標還位于水平儀的儀表盤內(nèi)覆履,更新水平儀的氣泡座標
if (isContain(x, y))
{
show.bubbleX = x;
show.bubbleY = y;
}
// 通知系統(tǒng)重回MyView組件
show.postInvalidate();
}
}
// 計算x蹋盆、y點的氣泡是否處于水平儀的儀表盤內(nèi)
private boolean isContain(int x, int y)
{
// 計算氣泡的圓心座標X、Y
int bubbleCx = x + show.bubble.getWidth() / 2;
int bubbleCy = y + show.bubble.getWidth() / 2;
// 計算水平儀儀表盤的圓心座標X硝全、Y
int backCx = show.back.getWidth() / 2;
int backCy = show.back.getWidth() / 2;
// 計算氣泡的圓心與水平儀儀表盤的圓心之間的距離栖雾。
double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)
+ (bubbleCy - backCy) * (bubbleCy - backCy));
// 若兩個圓心的距離小于它們的半徑差,即可認為處于該點的氣泡依然位于儀表盤內(nèi)
if (distance < (show.back.getWidth() - show.bubble.getWidth()) / 2)
{
return true;
}
else
{
return false;
}
}
}