很多时候我们的应用需要使用传感器,使手机应用更加方便和可玩性更高, Google为我们提供了十一种传感器
#define SENSOR_TYPE_ACCELEROMETER 1 //加速度
#define SENSOR_TYPE_MAGNETIC_FIELD 2 //磁力
#define SENSOR_TYPE_ORIENTATION 3 //方向
#define SENSOR_TYPE_GYROSCOPE 4 //陀螺仪
#define SENSOR_TYPE_LIGHT 5 //光线感应
#define SENSOR_TYPE_PRESSURE 6 //压力
#define SENSOR_TYPE_TEMPERATURE 7 //温度
#define SENSOR_TYPE_PROXIMITY 8 //接近
#define SENSOR_TYPE_GRAVITY 9 //重力
#define SENSOR_TYPE_LINEAR_ACCELERATION 10//线性加速度
#define SENSOR_TYPE_ROTATION_VECTOR 11//旋转矢量
今天我们就实现微信中的摇一摇功能,分析一波,首先是直观的感受是,摇一摇的时候,手机振动了,其次是有动画效果,当然也少不了声音的效果。
xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1f1f1f">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/flower" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/up" />
<ImageView
android:id="@+id/down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/down" />
</LinearLayout>
</RelativeLayout>
因为我们需要摇一摇的时候有音效,所以需要在在res中新建一个raw文件夹,然后把音频文件放进文件夹中, 我的音频文件名为awe
逻辑的处理
public class MainActivity extends AppCompatActivity{
//记录上一次晃动手机的时间
private long lastTime;
private ImageView upIv;
private ImageView downIv;
private int sound1;
private SoundPool soundPool;
private Vibrator vibrator;
private SensorManager sensorManager;
@Override
protected void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//振动器
vibrator = ((Vibrator) getSystemService(VIBRATOR_SERVICE));
//传感器
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
upIv = ((ImageView) findViewById(R.id.up));
downIv = ((ImageView) findViewById(R.id.down));
initSoundPool();
}
@Override
protected void onResume (){
super.onResume();
if(sensorManager != null){
// 注册监听器
// 第一个参数是Listener,第二个参数是所得传感器类型,第三个参数值获取传感器信息的频率
sensorManager.registerListener(sensorEventListener, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
}
//记得在不用的时候关掉传感器,因为手机黑屏是不会自动关掉传感器的,当然如果你觉得电量一直都很足,那算我多嘴咯。
@Override
protected void onStop (){
super.onStop();
if(sensorManager != null){// 取消监听器
sensorManager.unregisterListener(sensorEventListener);
}
}
private SensorEventListener sensorEventListener = new SensorEventListener() {
//当加速度发生改变时调用
//当加速度放生变化时就会调用该方法,所以在一次晃动中该方法实际会调用多次
@Override
public void onSensorChanged(SensorEvent event) {
//获取手机在不同方向上加速度的大小
float valueX = Math.abs(event.values[0]);
float valueY = Math.abs(event.values[1]);
float valueZ = Math.abs(event.values[2]);
//当手机在任意一个方向上加速度的大小超过17时,认为晃动手机了
if (valueX > 17 || valueY > 17 || valueZ > 17) {
//获取当前毫秒数
long currentTimeMillis = System.currentTimeMillis();
//如果两次连续晃动的时间小于1秒
if (currentTimeMillis - lastTime < 1000) {
return;
}
lastTime = currentTimeMillis;
//1.执行动画
playAnimation();
//2.播放音效
playSound();
//3.手机震动
//1.震动节奏,off/on/off/on,
// new long[]{100, 200, 100, 200, 100, 200}这个数组表示
// 停止震动100ms/震动200ms/停止震动100ms/......
//2.是否循环,-1表示不循环
vibrator.vibrate(new long[]{100, 200, 100, 200, 100, 200}, -1);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
//执行动画
private void playAnimation() {
AnimationSet up = new AnimationSet(false);
TranslateAnimation upUp = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,
0, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, -1);
upUp.setDuration(1000);
TranslateAnimation upDown = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,
0, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, 1);
upDown.setDuration(1000);
//延迟1秒执行
upDown.setStartOffset(1000);
up.addAnimation(upUp);
up.addAnimation(upDown);
upIv.startAnimation(up);
AnimationSet down = new AnimationSet(false);
TranslateAnimation downDown = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,
0, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, 1);
downDown.setDuration(1000);
TranslateAnimation downUp = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,
0, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, -1);
downUp.setDuration(1000);
//延迟1秒执行
downUp.setStartOffset(1000);
down.addAnimation(downDown);
down.addAnimation(downUp);
downIv.startAnimation(down);
}
private void playSound() {
//1.音频文件id
//2.3 表示左右声道的音量
//4.优先级
//5.循环次数,-1表示无限循环
//6.播放速率,取值为0.5~2之间,1表示正常速率播放
soundPool.play(sound1, 1, 1, 1, 0, 1);
}
private void initSoundPool() {
if (Build.VERSION.SDK_INT > 20) {
SoundPool.Builder builder = new SoundPool.Builder();
//设置最大并发流
builder.setMaxStreams(3);
AudioAttributes.Builder attributes = new AudioAttributes.Builder();
attributes.setLegacyStreamType(AudioManager.STREAM_MUSIC);
//设置音频流
builder.setAudioAttributes(attributes.build());
soundPool = builder.build();
} else {
//1.最大并发流
//2.音频流
//3.音频质量
soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
}
//读取音频文件,返回值为音频文件id
//第三个参数表示音频优先级
sound1 = soundPool.load(this, R.raw.awe, 1);
}
}
当然,需要申明权限,申明手机振动的权限。
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>