Android的传感器开发
1.1 开发传感器应用
开发传感器的步骤如下:
调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取SensorManager对象。
调用SensorManager的getDefaultSensor(int type)方法来获取指定类型的传感器。
一般在Activity的onResume()方法中调用SensorManager的registerListener()为指定传感器注册监听器即可。程序可以通过实现监听器即可获取传感器传回来的数据。
SersorManager提供的注册传感器的方法为registerListener(SensorListener listener, Sensor sensor, int rate)该方法中三个参数说明如下:
listener:监听传感器事件的监听器
sensor:传感器对象
rate:指定获取传感器数据的频率
rate可以获取传感器数据的频率,支持如下几个频率值:
SENSOR_DELAY_FASTEST:最快,延迟最小。
SENSOR_DELAY_GAME:适合游戏的频率。
SENSOR_DELAY_NORMAL:正常频率
SENSOR_DELAY_UI:适合普通用户界面的频率。
例:加速度传感器:
AccelerometerTest.java
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
|
public
class
AccelerometerTest
extends
Activity
implements
SensorEventListener
{
// 定义系统的Sensor管理器
SensorManager sensorManager;
EditText etTxt1;
@Override
public
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取程序界面上的文本框组件
etTxt1 = (EditText) findViewById(R.id.txt1);
// 获取系统的传感器管理服务
sensorManager = (SensorManager) getSystemService(
Context.SENSOR_SERVICE);
}
@Override
protected
void
onResume()
{
super
.onResume();
// 为系统的加速度传感器注册监听器
sensorManager.registerListener(
this
,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected
void
onStop()
{
// 取消注册
sensorManager.unregisterListener(
this
);
super
.onStop();
}
// 以下是实现SensorEventListener接口必须实现的方法
// 当传感器的值发生改变时回调该方法
@Override
public
void
onSensorChanged(SensorEvent event)
{
float
[] values = event.values;
StringBuilder sb =
new
StringBuilder();
sb.append(X方向上的加速度:);
sb.append(values[
0
]);
sb.append(
Y方向上的加速度:);
sb.append(values[
1
]);
sb.append(
Z方向上的加速度:);
sb.append(values[
2
]);
etTxt1.setText(sb.toString());
}
// 当传感器精度改变时回调该方法。
@Override
public
void
onAccuracyChanged(Sensor sensor,
int
accuracy)
{
}
}
|
需要指出的是,传感器的坐标系统与屏幕坐标系统不同,传感器坐标系统的X轴沿屏幕向右;Y轴则沿屏幕向上,Z轴在垂直屏幕向上。
当拿着手机横向左右移动时,可能产生X轴上的加速度;拿着手机前后移动时,可能产生Y轴上的加速度;当拿着手机竖向上下移动时,可能产生Z轴上的加速度。
1.2 下载和安装SensorSimulator
SensorSimulator是传感器的模拟工具,安装这个模拟工具之后,开发者就可以在Android模拟器上开发、调试传感器应用。
SensorSimulator,由PC端程序和手机端程序组成,当两端的程序运行并建立连接之后,用户可以通过PC端的程序来改变手机的传感数据。
下载和安装SensorSimulator步骤如下:
登录到http://code.google.com/p/openintents/wiki/SensorSimulator站点或FTP上,下载SensorSimulator的最新版本。
下载SensorSimulator工具后,下载完成后得到一个sensorsimulator-2.0-rc1.zip压缩包。解压该文件,得到如下文件结构。
安装SensorSimulator的手机端程序。通过命令窗口进入到上面文件的bin目录下,输入如下命令来安装SensorSimulatorSettings-2.0-rc1.apk文件。adb install SensorSimulatorSettings-2.0-rc1.apk
运行SensorSimulator的PC端程序,通过命令窗口进入到上面文件的bin目录下,并在窗口内执行如下命令:java –jar sensorsimulator-2.0-rc1.jar。运行该程序出现如下界面。
运行SensorSimulator的手机端程序。
在SensorSimulator的手机端程序中填写SensorSimulator的PC端程序的监听IP地址、监听端口。
切换到SensorSimulator的Testting Tab页,单击该Tab里的Connect按钮,SensorSimulator手机端和PC端连接。
1.3 利用SensorSimulator开发传感器应用
通过使用SensorSimulator,接下来就可以在Android模拟器中开发、调试传感器应用了。不过使用SensorSimulator开发传感器应用与开发真实的传感器应用略有区别。
Android应用必须通过引用外部JAR包的形式来引用SensorSimulator的lib目录下的sensorsimulator-2.0-rc1.jar包。
在应用项目上右键单击选择“Build Path” à “Add External Archives…”,找到sensorsimulator-2.0-rc1.jar所在位置,将其添加到项目中。
应用程序编程使用SensorManagerSimulator代替了原有的SensorManager。
应用程序获取SensorManagerSimulator之后,需要调用connectSimulator()方法连接模拟器。
应用程序编程时所用的Sensor、SensorEvent、 SensorEventListener等不再是Android提供的类,而是由SensorSimulator提供的类。
应用程序需要访问网络的权限。
例:利用传感模拟工具开发加速度传感器:
AccelSimulatorTest.java
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
|
import
org.openintents.sensorsimulator.hardware.SensorManagerSimulator;
import
org.openintents.sensorsimulator.hardware.Sensor;
import
org.openintents.sensorsimulator.hardware.SensorEvent;
import
org.openintents.sensorsimulator.hardware.SensorEventListener;
import
android.app.Activity;
import
android.hardware.SensorManager;
import
android.os.Bundle;
import
android.widget.EditText;
public
class
AccelSimulatorTest
extends
Activity
implements
SensorEventListener
{
// 定义模拟器的Sensor管理器
private
SensorManagerSimulator mSensorManager;
// 定义界面上的文本框组件
EditText etTxt1;
@Override
public
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取程序界面的文本框组件
etTxt1 = (EditText) findViewById(R.id.txt1);
// 获取传感器模拟器的传感器管理服务
mSensorManager = SensorManagerSimulator.getSystemService(
this
, SENSOR_SERVICE);
// 连接传感器模拟器
mSensorManager.connectSimulator();
}
@Override
protected
void
onResume()
{
super
.onResume();
// 为系统的加速度传感器注册监听器
mSensorManager.registerListener(
this
,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected
void
onStop()
{
// 取消注册
mSensorManager.unregisterListener(
this
);
super
.onStop();
}
// 以下是实现SensorEventListener接口必须实现的方法
// 当传感器的值发生改变时回调该方法
@Override
public
void
onSensorChanged(SensorEvent event)
{
float
[] values = event.values;
StringBuilder sb =
new
StringBuilder();
sb.append(X方向上的加速度:);
sb.append(values[
0
]);
sb.append(
Y方向上的加速度:);
sb.append(values[
1
]);
sb.append(
Z方向上的加速度:);
sb.append(values[
2
]);
etTxt1.setText(sb.toString());
}
@Override
// 当传感器精度改变时回调该方法。
public
void
onAccuracyChanged(Sensor sensor,
int
accuracy)
{
}
}
|
1
2
|
<!-- 通过模拟器调试需要访问网络 -->
<uses-permission android:name=
"android.permission.INTERNET/"
></uses-permission>
|
Android的常用传感器
2.1加速度传感器Accelerometer
加速度传感器主要感应手机的运动,在注册了传感器监听器后加速度传感器主要捕获3个参数values[0]、values[1]、values[2]。
values[0]:空间坐标系中x轴方向上的加速度减去重力加速度减去中立加速度在x轴上的分量。
values[1]:空间坐标系中x轴方向上的加速度减去重力加速度减去中立加速度在y轴上的分量。
values[2]:空间坐标系中x轴方向上的加速度减去重力加速度减去中立加速度在z轴上的分量。
上述3个数据的单位均为米每二次方秒。
距离说明:
当手机平放到桌面静止时,加速度为重力加速度g,通过0减去-g(重力加速度g方向为z轴反方向,故为负值)得到values[2]为g。
如果把手机水平方向右推,此时手机x方向上的加速度为正,即values[0]为正。
当把手机以a米每二次方秒的加速度竖值向上举时,values[2]的返回值为(a+g)米每二次方秒,通过a减去-g得到。
2.2 方向传感器Orientation
方向传感器主要感应手机方位的变化,其每次读取的都是静态的状态值,在注册了传感器监听器后方向传感器主要捕获3个参数values[0]、values[1]、values[2],关于三个角度的说明如下:
第一个角度:表示手机顶部朝向与正北方向的夹角。当手机绕着Z轴旋转时,该角度值发生改变。
第二个角度:表示手机顶部或尾部翘起的角度,当手机绕着X轴倾斜时,该角度值发生变化。
第三个角度:表示手机左侧或右侧翘起的角度。当手机绕着Y轴倾斜时,该角度值发生变化。
2.3磁场传感器Magnetic Field
磁场传感器主要用于感应周围的磁感应强度。即使周围没有任何直接的磁场,手机设备也始终会处于地球磁场中。随着手机状态设备摆放状态的改变,周围磁场在手机的X、Y、Z方向上的会发生改变。
磁场传感器传感器会返回三个数据,三个数据分别代表周围磁场分解到X、Y、Z三个方向上的磁场分量。磁场数据的单位是微特斯拉(uT)。
2.4光传感器Light
光传感器用于感应周围的光强,注册监听器后只捕获一个参数:values[0]。该参数代表周围的光照强度,单位为勒克斯(lux)。
2.5温度传感器Temperature
温度传感器用于获取手机设备所处环境的温度。温度传感器会返回一个数据,该数据代表手机设备周围的温度,单位是摄氏度。
2.6压力传感器 Pressure
压力传感器用于获取手机设备所处环境的压力的大小。压力传感器会返回一个数据,代表手机设备周围的压力大小。
例:传感器应用:
SensorSimulatorTest.java
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
|
public
class
SensorSimulatorTest
extends
Activity
implements
SensorEventListener
{
// // 定义真机的Sensor管理器
// private SensorManager mSensorManager;
// 定义模拟器的Sensor管理器
private
SensorManagerSimulator mSensorManager;
EditText etOrientation;
EditText etMagnetic;
EditText etTemerature;
EditText etLight;
EditText etPressure;
@Override
public
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取界面上的EditText组件
etOrientation = (EditText) findViewById(R.id.etOrientation);
etMagnetic = (EditText) findViewById(R.id.etMagnetic);
etTemerature = (EditText) findViewById(R.id.etTemerature);
etLight = (EditText) findViewById(R.id.etLight);
etPressure = (EditText) findViewById(R.id.etPressure);
// 获取真机的传感器管理服务
// mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// 获取传感器模拟器的传感器管理服务
mSensorManager = SensorManagerSimulator.getSystemService(
this
,
SENSOR_SERVICE);
// 连接传感器模拟器
mSensorManager.connectSimulator();
}
@Override
protected
void
onResume()
{
super
.onResume();
// 为系统的方向传感器注册监听器
mSensorManager.registerListener(
this
,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的磁场传感器注册监听器
mSensorManager.registerListener(
this
,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的温度传感器注册监听器
mSensorManager.registerListener(
this
,
mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的光传感器注册监听器
mSensorManager.registerListener(
this
,
mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的压力传感器注册监听器
mSensorManager.registerListener(
this
,
mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected
void
onStop()
{
// 程序退出时取消注册传感器监听器
mSensorManager.unregisterListener(
this
);
super
.onStop();
}
@Override
protected
void
onPause()
{
// 程序暂停时取消注册传感器监听器
mSensorManager.unregisterListener(
this
);
super
.onPause();
}
// 以下是实现SensorEventListener接口必须实现的方法
@Override
// 当传感器精度改变时回调该方法。
public
void
onAccuracyChanged(Sensor sensor,
int
accuracy)
{
}
@Override
public
void
onSensorChanged(SensorEvent event)
{
float
[] values = event.values;
// // 真机上获取触发event的传感器类型
// int sensorType = event.sensor.getType();
// 模拟器上获取触发event的传感器类型
int
sensorType = event.type;
StringBuilder sb =
null
;
// 判断是哪个传感器发生改变
switch
(sensorType)
{
// 方向传感器
case
Sensor.TYPE_ORIENTATION:
sb =
new
StringBuilder();
sb.append(绕Z轴转过的角度:);
sb.append(values[
0
]);
sb.append(
绕X轴转过的角度:);
sb.append(values[
1
]);
sb.append(
绕Y轴转过的角度:);
sb.append(values[
2
]);
etOrientation.setText(sb.toString());
break
;
// 磁场传感器
case
Sensor.TYPE_MAGNETIC_FIELD:
sb =
new
StringBuilder();
sb.append(X方向上的角度:);
sb.append(values[
0
]);
sb.append(
Y方向上的角度:);
sb.append(values[
1
]);
sb.append(
Z方向上的角度:);
sb.append(values[
2
]);
etMagnetic.setText(sb.toString());
break
;
// 温度传感器
case
Sensor.TYPE_TEMPERATURE:
sb =
new
StringBuilder();
sb.append(当前温度为:);
sb.append(values[
0
]);
etTemerature.setText(sb.toString());
break
;
// 光传感器
case
Sensor.TYPE_LIGHT:
sb =
new
StringBuilder();
sb.append(当前光的强度为:);
sb.append(values[
0
]);
etLight.setText(sb.toString());
break
;
// 压力传感器
case
Sensor.TYPE_PRESSURE:
sb =
new
StringBuilder();
sb.append(当前压力为:);
sb.append(values[
0
]);
etPressure.setText(sb.toString());
break
;
}
}
}
|
传感器应用案例
对传感器的支持是Android系统的特性之一,通过使用传感器可以开发出各种有趣的应用,我们通过方向传感器来开发指南针。
开发指南针的思路比较简单:程序先准备一张指南针图片,该图片上方向指针指向北方。接下来开发一个检测方向的传感器,程序检测到手机顶部绕Z轴转过多少度,让指南针图片反向转过多少度即可。
该应用中只要在界面中添加一张图片,并让图片总是反向转过方向传感器反回的第一个角度即可。
例:指南针:
Compass.java
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
|
public
class
Compass
extends
Activity
implements
SensorEventListener
{
// 定义显示指南针的图片
ImageView znzImage;
// 记录指南针图片转过的角度
float
currentDegree = 0f;
// 定义模拟器的Sensor管理器
// private SensorManagerSimulator mSensorManager;
// 定义真机的Sensor管理器
SensorManager mSensorManager;
@Override
public
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取界面中显示指南针的图片
znzImage = (ImageView) findViewById(R.id.znzImage);
// 获取真机的传感器管理服务
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// // 获取传感器模拟器的传感器管理服务
// mSensorManager = SensorManagerSimulator.getSystemService(this,
// SENSOR_SERVICE);
// // 连接传感器模拟器
// mSensorManager.connectSimulator();
}
@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
protected
void
onStop()
{
// 取消注册
mSensorManager.unregisterListener(
this
);
super
.onStop();
}
@Override
public
void
onSensorChanged(SensorEvent event)
{
// 真机上获取触发event的传感器类型
int
sensorType = event.sensor.getType();
// // 模拟器上获取触发event的传感器类型
// int sensorType = event.type;
switch
(sensorType)
{
case
Sensor.TYPE_ORIENTATION:
// 获取绕Z轴转过的角度。
float
degree = event.values[
0
];
// 创建旋转动画(反向转过degree度)
RotateAnimation ra =
new
RotateAnimation(currentDegree,
-degree, Animation.RELATIVE_TO_SELF,
0
.5f,
Animation.RELATIVE_TO_SELF,
0
.5f);
// 设置动画的持续时间
ra.setDuration(
200
);
// 运行动画
znzImage.startAnimation(ra);
currentDegree = -degree;
break
;
}
}
@Override
public
void
onAccuracyChanged(Sensor sensor,
int
accuracy)
{
}
}
|
main.xml
1
2
3
4
|
<!--?xml version=
1.0
encoding=utf-
8
?-->
<linearlayout android:background=
"#fff"
android:layout_height=
"fill_parent"
android:layout_width=
"fill_parent"
android:orientation=
"vertical"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<imageview android:id=
"@+id/znzImage"
android:layout_height=
"fill_parent"
android:layout_width=
"fill_parent"
android:scaletype=
"fitCenter"
android:src=
"@drawable/znz"
>
</imageview></linearlayout>
|
例:水平仪:
Gradienter.java
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
|
public
class
Gradienter
extends
Activity
implements
SensorEventListener
{
// 定义水平仪的仪表盘
MyView show;
// 定义水平仪能处理的最大倾斜角,超过该角度,气泡将直接在位于边界。
int
MAX_ANGLE =
30
;
// // 定义真机的Sensor管理器
// SensorManager mSensorManager;
// 定义模拟器的Sensor管理器
SensorManagerSimulator mSensorManager;
@Override
public
void
onCreate(Bundle savedInstanceState)
{
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取水平仪的主组件
show = (MyView) findViewById(R.id.show);
// 获取真机的传感器管理服务
// mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// 获取传感器模拟器的传感器管理服务
mSensorManager = SensorManagerSimulator.getSystemService(
this
,
SENSOR_SERVICE);
// 连接传感器模拟器
mSensorManager.connectSimulator();
}
@Override
public
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
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;
// // 真机上获取触发event的传感器类型
// int sensorType = event.sensor.getType();
// 模拟器上获取触发event的传感器类型
int
sensorType = event.type;
switch
(sensorType)
{
case
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轴的倾斜角还在最大角度之内
if
(Math.abs(zAngle) <= MAX_ANGLE)
{
// 根据与Z轴的倾斜角度计算X座标的变化值(倾斜角度越大,X座标变化越大)
int
deltaX = (
int
) ((show.back.getWidth() - show.bubble
.getWidth()) /
2
* zAngle / MAX_ANGLE);
x += deltaX;
}
// 如果与Z轴的倾斜角已经大于MAX_ANGLE,气泡应到最左边
else
if
(zAngle > MAX_ANGLE)
{
x =
0
;
}
// 如果与Z轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边
else
{
x = show.back.getWidth() - show.bubble.getWidth();
}
// 如果与Y轴的倾斜角还在最大角度之内
if
(Math.abs(yAngle) <= MAX_ANGLE)
{
// 根据与Y轴的倾斜角度计算Y座标的变化值(倾斜角度越大,Y座标变化越大)
int
deltaY = (
int
) ((show.back.getHeight() - show.bubble
.getHeight()) /
2
* yAngle / MAX_ANGLE);
y += deltaY;
}
// 如果与Y轴的倾斜角已经大于MAX_ANGLE,气泡应到最下边
else
if
(yAngle > MAX_ANGLE)
{
y = show.back.getHeight() - show.bubble.getHeight();
}
// 如果与Y轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边
else
{
y =
0
;
}
// 如果计算出来的X、Y座标还位于水平仪的仪表盘内,更新水平仪的气泡座标
if
(isContain(x, y))
{
show.bubbleX = x;
show.bubbleY = y;
}
// 通知系统重回MyView组件
show.postInvalidate();
break
;
}
}
// 计算x、y点的气泡是否处于水平仪的仪表盘内
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));
// 若两个圆心的距离小于它们的半径差,即可认为处于该点的气泡依然位于仪表盘内
if
(distance < (show.back.getWidth() - show.bubble.getWidth()) /
2
)
{
return
true
;
}
else
{
return
false
;
}
}
}
|
MyView.java
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
|
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
);
// 根据气泡座标绘制气泡
canvas.drawBitmap(bubble, bubbleX, bubbleY,
null
);
}
}
|
1
2
3
4
|
<!--?xml version=
1.0
encoding=utf-
8
?-->
<framelayout android:background=
"#fff"
android:layout_height=
"fill_parent"
android:layout_width=
"fill_parent"
android:orientation=
"vertical"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<com.boby.sensor.myview android:id=
"@+id/show"
android:layout_height=
"fill_parent"
android:layout_width=
"fill_parent"
>
</com.boby.sensor.myview></framelayout>
|