Android 傳感器實現水平儀效果

這兩天公司項目需要效果是實現水平儀效果,從網上查了查,也找了一些儲備,雖然達到了要求,但是有點不足,和我需求不符合,就是當小球轉到邊緣的時候,小球會在邊緣不動,於是就改了改,完美達到了我的要求,不管你手機怎麼轉,小球始終在大圓裏面,超過邊緣的時候,也是在邊緣滾動哦,特在此記錄,有需要的可供參考,廢話不多說,下面直接上代碼了:

還是要聲明下,這是本人第一篇博客,寫的不好,勿怪

呃,自己要提前準備兩張圖片哦,一張是小球的,一張是小球的背景畫布

實現的效果如下


1、首先定義傳感器變量

  private Sensor gyroSensor = null;
2、在onCreat裏面初始化傳感器
//初始化方向傳感器
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

3、在onResume裏面註冊傳感器

  @Override
    protected void onResume() {
        super.onResume();
        if (null != sensorManager || null != gyroSensor) {
            sensorManager.registerListener(this, gyroSensor, SensorManager.SENSOR_DELAY_GAME); //爲傳感器註冊監聽器
        }
    }
4、onPause裏面要暫停傳感器
@Override
    protected void onPause() {
        // 取消方向傳感器的監聽
        if (null != sensorManager) {
            sensorManager.unregisterListener(this);
        }
        super.onPause();
    }

5、編寫PlaneView,這個就是水平儀的控件,這個是從網上摘抄的,不懂可以直接搜android 水平儀實現,一定有的

public class PlaneView extends View {
    // 定義水平儀儀表盤圖片
    public Bitmap back;
    // 定義水平儀中的氣泡圖標
    public Bitmap bubble;
    // 定義水平儀中氣泡 的X、Y座標
    public float bubbleX, bubbleY;

    public PlaneView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 加載水平儀圖片和氣泡圖片
        back = BitmapFactory.decodeResource(getResources(), R.mipmap.plane);
        bubble = BitmapFactory.decodeResource(getResources(), R.mipmap.bubble);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 繪製水平儀表盤圖片
        canvas.drawBitmap(back, 0, 0, null);
        // 根據氣泡座標繪製氣泡
        canvas.drawBitmap(bubble, bubbleX, bubbleY, null);
    }
}

6、下面就是將控件放到你的Activity佈局中去,我的是MainActivity,佈局android_main.xml

        <!-寬高在這裏設定,具體根據你個人項目需求->         
        <RelativeLayout
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="25dp">

            <cn.leadpcom.com.underparking.common.PlaneView
                android:id="@+id/pv_bubble"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </RelativeLayout>

7、下面就是具體在傳感器接收到數據之後的操作了,裏面的pv_bubble是我的控件名,大家應該懂得,轉換成你個人設定的就行,呃,實在不懂,我也沒有辦法啊,就是這裏面的邏輯和網上不同,希望大家注意哦,大家是不是在想MAX_ANGLE在哪裏,是什麼,哈哈,這個是定義的變量,就是角度,越小,小球就越靈敏

private int MAX_ANGLE = 10;//具體多大,自己嘗試下就行了
 @Override
    public void onSensorChanged(SensorEvent event) {
        float[] values = event.values;
        // 獲取觸發event的傳感器類型就
        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 = (pv_bubble.back.getWidth() - pv_bubble.bubble.getWidth()) / 2;
                int y = (pv_bubble.back.getHeight() - pv_bubble.bubble.getHeight()) / 2;
                // 根據與Z軸的傾斜角度計算X座標的變化值(傾斜角度越大,X座標變化越大)
                int deltaX = (int) ((pv_bubble.back.getWidth() - pv_bubble.bubble.getWidth()) / 2 * zAngle / MAX_ANGLE);
                x += deltaX;
                // 根據與Y軸的傾斜角度計算Y座標的變化值(傾斜角度越大,Y座標變化越大)
                int deltaY = (int) ((pv_bubble.back.getHeight() - pv_bubble.bubble.getHeight()) / 2 * yAngle / MAX_ANGLE);
                y += deltaY;
                // 如果計算出來的X、Y座標還位於水平儀的儀表盤內,更新水平儀的氣泡座標
                float aa = (float) Math.sqrt((x - (pv_bubble.back.getHeight() / 2 - pv_bubble.bubble.getHeight() / 2)) * (x - (pv_bubble.back.getHeight() / 2 - pv_bubble.bubble.getHeight() / 2)) + (y - (pv_bubble.back.getHeight() / 2 - pv_bubble.bubble.getHeight() / 2)) * (y - (pv_bubble.back.getHeight() / 2 - pv_bubble.bubble.getHeight() / 2)));
                if (aa < pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)) {
                    pv_bubble.bubbleX = x;
                    pv_bubble.bubbleY = y;
                } else {
                    float newx = (float) ((pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)) * (x - (pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)))) / aa + ((pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)));
                    float newy = (float) ((pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)) * (y - (pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)))) / aa + ((pv_bubble.back.getHeight() / 2 - (pv_bubble.bubble.getHeight() / 2)));
                    pv_bubble.bubbleX = newx;
                    pv_bubble.bubbleY = newy;
                }
                // 通知系統重回MyView組件
                pv_bubble.postInvalidate();
                break;
        }
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

8、好了,只要按照上面的說的,應該就能完美實現了,小球一直在畫布裏面的哦!~!~!~!~!有需要的,參考下,大神還請給出點評,我會繼續更新改正,上面部分是摘抄,別的部分是原創,如有雷同,純屬巧合!~!~!~!~!~!








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章