利用Android感應器開發水平儀

來源:互聯網
上載者:User

這裡介紹的水平儀,指的是比較傳統的氣泡水平儀,在一個透明圓盤內充滿液體,液體中留有一個氣泡,當一端翹起時,該氣泡就會浮向翹起的一端。 在上文中,利用方向感應器返回的第一個參數,實現了一個指南針小應用。接下來,我們利用返回的第二、三個參數實現該水平儀。因為第二個參數,反映底部(或頂部)翹起的角度,第三個參數可以反映右側(或左側)翹起的角度。根據這兩個角度就可以開發水平儀,實現手機哪端翹起,氣泡就浮向哪端,這也是水平儀的實現思想。代碼如下: Activity:  

package com.home.activity;    import android.app.Activity;  import android.hardware.Sensor;  import android.hardware.SensorEvent;  import android.hardware.SensorEventListener;  import android.hardware.SensorManager;  import android.os.Bundle;    import com.home.R;  import com.home.view.MyView;    public class MainActivity extends Activity implements SensorEventListener {      // 定義水平儀的儀錶盤       private MyView view;      // 定義水平儀能處理的最大傾斜角,超過該角度,氣泡將直接位於邊界       private final int MAX_ANGLE = 30;      // 定義真機的Sensor管理器       private SensorManager mSensorManager;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          // 擷取水平儀的組件           view = (MyView) findViewById(R.id.main_myview);          // 擷取真機的感應器管理服務           mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);      }        @Override      protected void onResume() {          super.onResume();          // 為系統的方向感應器註冊監聽器           mSensorManager.registerListener(this,                  mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),                  SensorManager.SENSOR_DELAY_GAME);      }        @Override      protected void onPause() {          // 取消註冊           mSensorManager.unregisterListener(this);          super.onPause();      }        @Override      public void onAccuracyChanged(Sensor sensor, int accuracy) {      }        @Override      public void onSensorChanged(SensorEvent event) {          float[] values = event.values;          // 真機上擷取觸發的感應器類型           int sensorType = event.sensor.getType();          switch (sensorType) {          case Sensor.TYPE_ORIENTATION:              // 擷取與Y軸的夾角               float yAngle = values[1];              // 擷取與Z軸的夾角               float zAngle = values[2];              // 氣泡位於中間時(水平儀完全水平),氣泡的X、Y座標               int x = (view.back.getWidth() - view.bubble.getWidth()) / 2;              int y = (view.back.getHeight() - view.bubble.getHeight()) / 2;              // 如果與z軸的傾斜角還在最大角度之內               if (Math.abs(zAngle) <= MAX_ANGLE) {                  // 根據與z軸的傾斜角計算x座標的變化值(傾斜角度越大,x座標變化越大)                   int deltaX = (int) ((view.back.getWidth() - view.bubble                          .getWidth()) / 2 * zAngle / MAX_ANGLE);                  x += deltaX;              }              // 如果與z軸的傾斜角已經大於MAX_ANGLE,氣泡應到最左邊               else if (zAngle > MAX_ANGLE) {                  x = 0;              }              // 如果與Z軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊               else {                  x = view.back.getWidth() - view.bubble.getWidth();              }              // 如果與Y軸的傾斜角還在最大角度之內               if (Math.abs(yAngle) <= MAX_ANGLE) {                  // 根據與Y軸的傾斜角計算Y座標的變化值(傾斜角度越大,Y座標變化越大)                   int deltaY = (int) ((view.back.getHeight() - view.bubble                          .getHeight()) / 2 * zAngle / MAX_ANGLE);                  y += deltaY;              }              // 如果與Y軸的傾斜角已經大於MAX_ANGLE,氣泡應到最下邊               else if (yAngle > MAX_ANGLE) {                  y = view.back.getHeight() - view.bubble.getHeight();              }              // 如果與Y軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊               else {                  y = 0;              }              // 如果計算出來的X、Y座標還位於水平儀的儀錶盤內,更新水平儀的氣泡座標               if (isContain(x, y)) {                  view.bubbleX = x;                  view.bubbleY = y;              }              // 通知系統重繪MyView組件               view.postInvalidate();              break;          }      }        // 計算X、Y點的氣泡是否處於水平儀的儀錶盤內       private boolean isContain(int x, int y) {          // 計算氣泡的圓心座標X、Y           int bubbleCx = x + view.bubble.getWidth() / 2;          int bubbleCy = y + view.bubble.getHeight() / 2;          // 計算水平儀儀錶盤的圓心座標X、Y           int backCx = view.back.getWidth() / 2;          int backCy = view.back.getHeight() / 2;          // 計算氣泡的圓心與水平儀儀錶盤的圓心之間的距離           double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)                  + (bubbleCy - backCy) * (bubbleCy - backCy));          // 若兩個圓心的距離小於它們的半徑差,即可認為處於該店的氣泡依然位於儀錶盤內           if (distance < (view.back.getWidth() - view.bubble.getWidth()) / 2) {              return true;          } else {              return false;          }      }  }  package com.home.activity;import android.app.Activity;import android.hardware.Sensor;import android.hardware.SensorEvent;import android.hardware.SensorEventListener;import android.hardware.SensorManager;import android.os.Bundle;import com.home.R;import com.home.view.MyView;public class MainActivity extends Activity implements SensorEventListener {// 定義水平儀的儀錶盤private MyView view;// 定義水平儀能處理的最大傾斜角,超過該角度,氣泡將直接位於邊界private final int MAX_ANGLE = 30;// 定義真機的Sensor管理器private SensorManager mSensorManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 擷取水平儀的組件view = (MyView) findViewById(R.id.main_myview);// 擷取真機的感應器管理服務mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);}@Overrideprotected void onResume() {super.onResume();// 為系統的方向感應器註冊監聽器mSensorManager.registerListener(this,mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),SensorManager.SENSOR_DELAY_GAME);}@Overrideprotected void onPause() {// 取消註冊mSensorManager.unregisterListener(this);super.onPause();}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {float[] values = event.values;// 真機上擷取觸發的感應器類型int sensorType = event.sensor.getType();switch (sensorType) {case Sensor.TYPE_ORIENTATION:// 擷取與Y軸的夾角float yAngle = values[1];// 擷取與Z軸的夾角float zAngle = values[2];// 氣泡位於中間時(水平儀完全水平),氣泡的X、Y座標int x = (view.back.getWidth() - view.bubble.getWidth()) / 2;int y = (view.back.getHeight() - view.bubble.getHeight()) / 2;// 如果與z軸的傾斜角還在最大角度之內if (Math.abs(zAngle) <= MAX_ANGLE) {// 根據與z軸的傾斜角計算x座標的變化值(傾斜角度越大,x座標變化越大)int deltaX = (int) ((view.back.getWidth() - view.bubble.getWidth()) / 2 * zAngle / MAX_ANGLE);x += deltaX;}// 如果與z軸的傾斜角已經大於MAX_ANGLE,氣泡應到最左邊else if (zAngle > MAX_ANGLE) {x = 0;}// 如果與Z軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊else {x = view.back.getWidth() - view.bubble.getWidth();}// 如果與Y軸的傾斜角還在最大角度之內if (Math.abs(yAngle) <= MAX_ANGLE) {// 根據與Y軸的傾斜角計算Y座標的變化值(傾斜角度越大,Y座標變化越大)int deltaY = (int) ((view.back.getHeight() - view.bubble.getHeight()) / 2 * zAngle / MAX_ANGLE);y += deltaY;}// 如果與Y軸的傾斜角已經大於MAX_ANGLE,氣泡應到最下邊else if (yAngle > MAX_ANGLE) {y = view.back.getHeight() - view.bubble.getHeight();}// 如果與Y軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊else {y = 0;}// 如果計算出來的X、Y座標還位於水平儀的儀錶盤內,更新水平儀的氣泡座標if (isContain(x, y)) {view.bubbleX = x;view.bubbleY = y;}// 通知系統重繪MyView組件view.postInvalidate();break;}}// 計算X、Y點的氣泡是否處於水平儀的儀錶盤內private boolean isContain(int x, int y) {// 計算氣泡的圓心座標X、Yint bubbleCx = x + view.bubble.getWidth() / 2;int bubbleCy = y + view.bubble.getHeight() / 2;// 計算水平儀儀錶盤的圓心座標X、Yint backCx = view.back.getWidth() / 2;int backCy = view.back.getHeight() / 2;// 計算氣泡的圓心與水平儀儀錶盤的圓心之間的距離double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)+ (bubbleCy - backCy) * (bubbleCy - backCy));// 若兩個圓心的距離小於它們的半徑差,即可認為處於該店的氣泡依然位於儀錶盤內if (distance < (view.back.getWidth() - view.bubble.getWidth()) / 2) {return true;} else {return false;}}}

 

自訂群組件類(MyView):  
package com.home.view;    import com.home.R;    import android.content.Context;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.graphics.Canvas;  import android.util.AttributeSet;  import android.view.View;    public class MyView extends View {      // 定義水平儀盤圖片       public Bitmap back;      // 定義水平儀中的泡泡圖標       public Bitmap bubble;      // 定義水平儀中氣泡的X、Y座標       public 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);          // 根據氣泡座標繪製氣泡           canvas.drawBitmap(bubble, bubbleX, bubbleY, null);      }  }  package com.home.view;import com.home.R;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.View;public class MyView extends View {// 定義水平儀盤圖片public Bitmap back;// 定義水平儀中的泡泡圖標public Bitmap bubble;// 定義水平儀中氣泡的X、Y座標public 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);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 繪製水平儀圖片canvas.drawBitmap(back, 0, 0, null);// 根據氣泡座標繪製氣泡canvas.drawBitmap(bubble, bubbleX, bubbleY, null);}}

 

布局XML: 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent" >        <com.home.view.MyView          android:id="@+id/main_myview"          android:layout_width="match_parent"          android:layout_height="match_parent" />    </LinearLayout>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <com.home.view.MyView        android:id="@+id/main_myview"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

 


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.