android - 不使用库的加速度计视差

标签 android parallax

我想要一个根据加速度计移动并创建视差效果的自定义 View 。

现在我有了自定义 View 来监听加速度计值,但是我如何使用这些值来正确移动 View ?

代码:

public class ParallaxView extends AppCompatImageView
        implements SensorEventListener {

    private static final int SENSOR_DELAY = SensorManager.SENSOR_DELAY_FASTEST;

    //...

    public ParallaxView(Context context) {
        super(context);
    }

    public ParallaxView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ParallaxView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void init() {
        WindowManager windowManager = (WindowManager) getContext().getSystemService(WINDOW_SERVICE);
        mDisplay = windowManager.getDefaultDisplay();
        mSensorManager = (SensorManager) getContext().getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }

    public void setNewPosition(
            @Nullable Float sensorX,
            @Nullable Float sensorY) {
        // ???
    }

    //...

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
            setNewPosition(event.values[0], event.values[1]);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

    public void registerSensorListener() {
        mSensorManager.registerListener(this, mAccelerometer, SENSOR_DELAY);
    }

    public void unregisterSensorListener() {
        mSensorManager.unregisterListener(this);
    }
}

在 Activity 中使用这个 View :

@Override
protected void onCreate(Bundle savedInstanceState) {
    //...
    mParallaxView.init();
}

@Override
protected void onResume() {
    mParallaxView.registerSensorListener();
    super.onResume();
}

@Override
protected void onPause() {
    mParallaxView.unregisterSensorListener();
    super.onPause();
}

提前致谢

最佳答案

最后,我创建了自定义 View 以获得我想要的内容。

这里是存储库:https://github.com/GVMarc/ParallaxView

这里是代码:

public class ParallaxView extends AppCompatImageView implements SensorEventListener {

    private static final int DEFAULT_SENSOR_DELAY = SensorManager.SENSOR_DELAY_FASTEST;
    public static final int DEFAULT_MOVEMENT_MULTIPLIER = 3;
    public static final int DEFAULT_MIN_MOVED_PIXELS = 1;
    private static final float DEFAULT_MIN_SENSIBILITY = 0;

    private float mMovementMultiplier = DEFAULT_MOVEMENT_MULTIPLIER;
    private int mSensorDelay = DEFAULT_SENSOR_DELAY;
    private int mMinMovedPixelsToUpdate = DEFAULT_MIN_MOVED_PIXELS;
    private float mMinSensibility = DEFAULT_MIN_SENSIBILITY;

    private float mSensorX;
    private float mSensorY;
    private Float mFirstSensorX;
    private Float mFirstSensorY;
    private Float mPreviousSensorX;
    private Float mPreviousSensorY;

    private float mTranslationX = 0;
    private float mTranslationY = 0;

    private SensorManager mSensorManager;
    private Sensor mAccelerometer;

    public enum SensorDelay {
        FASTEST,
        GAME,
        UI,
        NORMAL
    }

    public ParallaxView(Context context) {
        super(context);
    }

    public ParallaxView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ParallaxView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void init() {
        mSensorManager = (SensorManager) getContext().getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }

    private void setNewPosition() {
        int destinyX = (int) ((mFirstSensorX - mSensorX) * mMovementMultiplier);
        int destinyY = (int) ((mFirstSensorY - mSensorY) * mMovementMultiplier);

        calculateTranslationX(destinyX);
        calculateTranslationY(destinyY);
    }

    private void calculateTranslationX(int destinyX) {
        if (mTranslationX + mMinMovedPixelsToUpdate < destinyX)
            mTranslationX++;
        else if (mTranslationX - mMinMovedPixelsToUpdate > destinyX)
            mTranslationX--;
    }

    private void calculateTranslationY(int destinyY) {
        if (mTranslationY + mMinMovedPixelsToUpdate < destinyY)
            mTranslationY++;
        else if (mTranslationY - mMinMovedPixelsToUpdate > destinyY)
            mTranslationY--;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        setTranslationX(mTranslationX);
        setTranslationY(mTranslationY);
        invalidate();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            mSensorX = event.values[0];
            mSensorY = -event.values[1];

            manageSensorValues();
        }
    }

    private void manageSensorValues() {
        if (mFirstSensorX == null)
            setFirstSensorValues();

        if (mPreviousSensorX == null || isSensorValuesMovedEnough()) {
            setNewPosition();
            setPreviousSensorValues();
        }
    }

    private void setFirstSensorValues() {
        mFirstSensorX = mSensorX;
        mFirstSensorY = mSensorY;
    }

    private void setPreviousSensorValues() {
        mPreviousSensorX = mSensorX;
        mPreviousSensorY = mSensorY;
    }

    private boolean isSensorValuesMovedEnough() {
        return mSensorX > mPreviousSensorX + mMinSensibility ||
                mSensorX < mPreviousSensorX - mMinSensibility ||
                mSensorY > mPreviousSensorY + mMinSensibility ||
                mSensorY < mPreviousSensorX - mMinSensibility;
    }

    public void registerSensorListener() {
        mSensorManager.registerListener(this, mAccelerometer, mSensorDelay);
    }

    public void registerSensorListener(SensorDelay sensorDelay) {
        switch (sensorDelay) {
            case FASTEST:
                mSensorDelay = SensorManager.SENSOR_DELAY_FASTEST;
                break;
            case GAME:
                mSensorDelay = SensorManager.SENSOR_DELAY_GAME;
                break;
            case UI:
                mSensorDelay = SensorManager.SENSOR_DELAY_UI;
                break;
            case NORMAL:
                mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;
                break;
        }
        registerSensorListener();
    }

    public void unregisterSensorListener() {
        mSensorManager.unregisterListener(this);
    }

    public void setMovementMultiplier(float multiplier) {
        mMovementMultiplier = multiplier;
    }

    public void setMinimumMovedPixelsToUpdate(int minMovedPixelsToUpdate) {
        mMinMovedPixelsToUpdate = minMovedPixelsToUpdate;
    }

    public void setMinimumSensibility(int minSensibility) {
        mMinSensibility = minSensibility;
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }
}

关于android - 不使用库的加速度计视差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42626761/

相关文章:

android - 尝试访问库项目中的 View 时出现 ClassNotFoundException

html - 滚动图像的 CSS 和视差问题

html - Skrollr - 如何制作一个 div 显示 :none on scroll

ios - TableView 部分标题中的视差效果会引发 UIView-nil 错误?

java - 访问 DialogPreference 中的小部件状态

java - Android:在页眉和页脚之间显示 ListView

android - 找不到文件异常

android - 如何确定 Android Gallery 中的运动方向?

javascript - 未捕获的类型错误 : Cannot read property 'setAttribute' of null (console error)

javascript - Skrollr、Safari、固定位置滞后