利用Android传感器开发水平仪

http://www.2cto.com/kf/201307/229224.html
这里介绍的水平仪,指的是比较传统的气泡水平仪,在一个透明圆盘内充满液体,液体中留有一个气泡,当一端翘起时,该气泡就会浮向翘起的一端。

在上文中,利用方向传感器返回的第一个参数,实现了一个指南针小应用。接下来,我们利用返回的第二、三个参数实现该水平仪。因为第二个参数,反映底部(或顶部)翘起的角度,第三个参数可以反映右侧(或左侧)翘起的角度。根据这两个角度就可以开发水平仪,实现手机哪端翘起,气泡就浮向哪端,这也是水平仪的实现思想。代码如下:

Activity:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

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;

@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;
}
}
}

自定义组件类(MyView):

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

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);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制水平仪图片
canvas.drawBitmap(back, 0, 0, null);
// 根据气泡坐标绘制气泡
canvas.drawBitmap(bubble, bubbleX, bubbleY, null);
}
}

布局XML:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

你可能感兴趣的:(利用Android传感器开发水平仪)