How to move a view using an accelerometer with a 3D effect?

I am trying to play the following animation:

3D effect animation

1) There are no problems with the implementation of the accelerometer:

public class Accelerometer extends AppCompatActivity implements SensorEventListener {

    private SensorManager senSensorManager;
    private Sensor senAccelerometer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //...

        // Get a reference to a SensorManager
        senSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }

    // This method will update the UI on new sensor events
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        Sensor sensor = sensorEvent.sensor;

        if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            float x = sensorEvent.values[0];
            float y = sensorEvent.values[1];
        }
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
    }

    @Override
    protected void onResume() {
        super.onResume();
        senSensorManager.registerListener(this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onStop() {
        senSensorManager.unregisterListener(this);
        super.onStop();
    }
}

2) My problem is to reproduce the 3D effect depending on the position of X and Y. It should not be confused with the parallax effect.

I find this solution with Rotate3dAnimation

If you see a class, the animation is only on camera.rotateY(degrees);, so I create a custom Rotate3dAnimation function as follows:

public class CustomRotate3dAnimation extends Animation {
    private static final float DEPTHZ = 20.0f;

    private final float mFromXDegrees;
    private final float mFromYDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final boolean mRotateCameraX;
    private Camera mCamera;

    public CustomRotate3dAnimation(float fromXDegrees, float fromYDegrees, float toDegrees,
                                   float centerX, float centerY, boolean rotateCameraX) {
        mFromXDegrees = fromXDegrees;
        mFromYDegrees = fromYDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mRotateCameraX = rotateCameraX;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mRotateCameraX ? mFromXDegrees : mFromYDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;

        final Matrix matrix = t.getMatrix();

        camera.save();
        camera.translate(0.0f, 0.0f, DEPTHZ * interpolatedTime);

        if(mRotateCameraX) {
            camera.rotateY(degrees);
            camera.rotateX(mFromYDegrees);
        } else {
            camera.rotateY(mFromXDegrees);
            camera.rotateX(degrees);
        }
        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

And this is my implementation on onSensorChanged:

@Override
public void onSensorChanged(SensorEvent sensorEvent) {
    Sensor sensor = sensorEvent.sensor;

    if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        int x = (int) sensorEvent.values[0];
        int y = (int) sensorEvent.values[1];

        if (x != currentXAngle / 10 && Math.abs(x) < 2) {
            Log.e(TAG, "X: " + x);

            int end = x * 10;

            final float centerX = viewCard.getWidth() / 2.0f;
            final float centerY = viewCard.getHeight() / 2.0f;

            final CustomRotate3dAnimation rotation = new CustomRotate3dAnimation(currentXAngle, currentYAngle, end, centerX, centerY, true);
            rotation.setDuration(200);
            rotation.setFillAfter(true);
            viewCard.startAnimation(rotation);

            currentXAngle = end;
        }

        if (y != currentYAngle / 10 && Math.abs(y) < 2) {
            Log.e(TAG, "Y: " + y);

            int end = y * 10;

            final float centerX = viewCard.getWidth() / 2.0f;
            final float centerY = viewCard.getHeight() / 2.0f;

            final CustomRotate3dAnimation rotation = new CustomRotate3dAnimation(currentXAngle, currentYAngle, end, centerX, centerY, false);
            rotation.setDuration(200);
            rotation.setFillAfter(true);
            viewCard.startAnimation(rotation);

            currentYAngle = end;
        }
    }
}

The result in the picture:

Work in progress

But the result is bad, not smooth.

Does anyone know a library or article that can help me?

+4

Source: https://habr.com/ru/post/1656240/


All Articles