模仿微信搖一搖(只模仿傳感器及震動)

參考鏈接:
主體內容參考:http://blog.csdn.net/catoop/article/details/8051835
看到http://104zz.iteye.com/blog/1694738對應的文章時,想着應該把此功能做一個封裝


以下爲正文(實際上就是代碼)

項目地址:https://github.com/itlonewolf/Practice
使用參照項目中ShakeActivity中的示例

封裝後的搖一搖控制器(方便使用與複用)


import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Vibrator;
import android.support.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;

/**
 * Created by xiaoyee on 16/7/28.
 * 搖一搖控制器
 * <p>
 *     代碼主體參考http://blog.csdn.net/catoop/article/details/8051835
 *     看到http://104zz.iteye.com/blog/1694738對應的文章時,想着應該把此功能做一個封裝
 * </p>
 *
 */
public class ShakeController implements SensorEventListener {

    public interface Amplitude{

        /**
         * 對於過山車而言,得很大的搖動纔算事兒吧
         */
        int ROLLER_COASTER = 100;
        int SUV            = 55;
        int BIKE           = 38;
        /**
         * 很小的搖動對於輪椅來講就是需要注意的了
         */
        int WHEELCHAIR     = 18;
    }

    /**
     * 搖一搖兩次之間的間隔至少爲500ms
     */
    private static final int SHAKE_TIME_SLOT = 500;
    //不重複震動
    private static final int DONT_REPEAT     = -1;
    //震動模式
    private static final long[] VIBRATOR_PATTERN = new long[]{
            //每兩個數值爲一個組合
            100, 300,//100爲等待(停止)時間,300爲震動時間
            200, 300 //200爲等待(停止)時間,300爲震動時間
    };
    private SensorManager mSensorManager;
    private Vibrator      mVibrator;
    //是否需要震動,默認開啓震動
    private boolean mNeedVibrate = true;
    //上一次震動的時間戳;單位納秒
    private long mLastTimeShake = 0;
    //設當絕對值大於多少時纔算一次搖動
    private int mShakeAmplitude = Amplitude.SUV;

    private OnShakedListener mOnShakedListener;

    /**
     * 設置搖動幅度爲多少時,纔算是搖動
     */
    public void setShakeAmplitude(@AmplitudeAnno int shakeAmplitude) {
        mShakeAmplitude = shakeAmplitude;
    }

    /**
     *
     * @param needVibrate 是否需要開啓震動
     */
    public ShakeController(Context context, boolean needVibrate) {
        mNeedVibrate = needVibrate;
        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    }

    /**
     * 默認開啓震動
     */
    public ShakeController(Context context) {
        this(context, true);
    }

    public void startWatchShake(){
        if (mSensorManager != null) {
            mSensorManager.registerListener(
                    this,
                    mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL
                                           );
        }
    }

    public void stopWatchShake(){
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(this);
        }
    }

    public void setOnShakedListener(OnShakedListener onShakedListener) {
        mOnShakedListener = onShakedListener;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        //驗證傳感器
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            float[] values = event.values;
            float   x      = values[0]; // x軸方向的重力加速度,向右爲正
            float   y      = values[1]; // y軸方向的重力加速度,向前爲正
            float   z      = values[2]; // z軸方向的重力加速度,向上爲正
            // 一般在這三個方向的重力加速度達到40就達到了搖晃手機的狀態。
            if (Math.abs(x) > mShakeAmplitude || Math.abs(y) > mShakeAmplitude || Math.abs(z) > mShakeAmplitude) {
                //使用此方法降低調用次數
                if (isTimeSlot(event.timestamp)) {
                    if (mNeedVibrate) {
                        mVibrator.vibrate(VIBRATOR_PATTERN, DONT_REPEAT);
                    }

                    if (mOnShakedListener != null) {
                        mOnShakedListener.onShake();
                    }
                }
            }
        }
    }

    /**
     * 間隔時間是否大於要求值;目前間隔時間爲 {@link #SHAKE_TIME_SLOT 500ms}
     * @param currentTime   本次時間;單位爲納秒
     */
    private boolean isTimeSlot(long currentTime) {
        if (TimeUnit.NANOSECONDS.toMillis(currentTime - mLastTimeShake) > SHAKE_TIME_SLOT) {
            mLastTimeShake = currentTime;
            return true;
        }
        return false;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        //暫時不關心此更改
    }

    /**
     * 搖一搖監聽器
     */
    public interface OnShakedListener{
        void onShake();
    }

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({Amplitude.WHEELCHAIR, Amplitude.BIKE, Amplitude.SUV, Amplitude.ROLLER_COASTER})
    private @interface AmplitudeAnno{}
}

使用示例:

public class ShakeActivity extends AppCompatActivity {

    private ShakeController mShakeController;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shake);

        mShakeController = new ShakeController(this);
        mShakeController.setOnShakedListener(new ShakeController.OnShakedListener() {
            @Override
            public void onShake() {
                Toast.makeText(ShakeActivity.this, "搖一搖", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        mShakeController.startWatchShake();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mShakeController.stopWatchShake();
    }

}

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