移动球与加速度计在Android中的相机预览视图内

时间:2013-05-07 11:39:21

标签: android-layout android-animation accelerometer

我一直在搜索和编码这个问题3天,没有结果:(

我制作了一个代码在这里的相机覆盖图+加速度计

public class CameraActivity extends Activity implements SurfaceHolder.Callback, SensorEventListener {
    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;
    boolean previewing = false;
    LayoutInflater controlInflater = null;

    static String TAG = CameraActivity.class.getSimpleName();

    // Accelerometer
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.surface_view);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        controlInflater = LayoutInflater.from(getBaseContext());
        View viewControl = controlInflater.inflate(R.layout.camera_control,
                null);

        LayoutParams layoutParamsControl = new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

        this.addContentView(viewControl, layoutParamsControl);


        // Accelerometer
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mAccelerometer,
                SensorManager.SENSOR_DELAY_NORMAL);

    }

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

    }

    @Override
    public void onSensorChanged(SensorEvent event) {

    }


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
        if (previewing) {
            camera.stopPreview();
            previewing = false;
        }

        if (camera != null) {
            try {
                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                previewing = true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        camera = Camera.open();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();
        camera = null;
        previewing = false;
    }
}

然后在camera_control.xml中我有这个:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_holder"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/transparent"
    android:gravity="bottom" >

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/camera_red_button"
        android:layout_alignLeft="@+id/camera_back_button"
        android:layout_marginBottom="27dp"
        android:src="@drawable/camera_accelerometer_red" />

</RelativeLayout>

camera_accelerometer_red

ball

并在surface_view.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/camerapreview_holder"
    >

<SurfaceView
    android:id="@+id/camerapreview"  
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    />
</LinearLayout>

图像视图是精神层面的图像。

这个想法是用户在拍摄照片之前需要调平相机。我已经清除了所有不需要的代码。上面的代码是工作代码。

问题: 我需要为精神层面制造一个球。它不需要是最平滑的精神层面。如果我能找到将球限制在精神层面并根据加速度计结果移动它的方法,我会像拉里一样快乐:)/

如果有人请我就这三件事指出正确的方向:

  1. 将动画限制在某个区域内
  2. 禁区是Circle,如何制作
  3. 提前致谢。 小时。

1 个答案:

答案 0 :(得分:1)

好的我已经得到了答案。希望它可以帮助某人。您需要使用计算从中间到角落的距离(半径)偏移角落。

此外,我已将Accelerometor更改为方向传感器,然后我可以在X和Y轴上获得手机的3D旋转。

以下代码是工作代码,我测试了它们。我使用的是Android 2.3.3+ 球的运动不是很平滑,因为这不是应用的目的。

我认为为了平滑移动,您可能还需要添加计时器和碰撞检测。请检查android示例。

我还没有重构代码。所以这不是生产级代码:)

代码:

public class CameraActivity extends Activity implements SurfaceHolder.Callback,
        SensorEventListener {

    // Accelerometer
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;

    /** Called when the activity is first created. */
    public static float x;
    public static float y;

    FrameLayout layout_holder;
    FrameLayout ball_holder;

    // private float hOriginSize;
    float halfOfWidth;
    int centerYOnImage;
    private Sensor mOrientation;

        // float viewInset = 14.0f; // I remove this simply to make the code cleaner. I used this to calculate the radius and the offset later on

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.surface_view);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        controlInflater = LayoutInflater.from(getBaseContext());
        View viewControl = controlInflater.inflate(R.layout.camera_control,
                null);

        LayoutParams layoutParamsControl = new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

        this.addContentView(viewControl, layoutParamsControl);

        // Accelerometer
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mOrientation = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        mSensorManager.registerListener(this, mAccelerometer,
                SensorManager.SENSOR_DELAY_NORMAL);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.ball);
        CustomDrawableView mCustomDrawableView = new CustomDrawableView(this,
                bitmap);

        ball_holder = (FrameLayout) findViewById(R.id.ball_holder);
        ball_holder.addView(mCustomDrawableView);

        halfOfWidth = 40; // You can calculate this, I just put this so I can test it. This is the half of the width of target image - attached in the question

        centerYOnImage = 40; // Not important :)

    }

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

    }

    // This method will update the UI on new sensor events
    public void onSensorChanged(SensorEvent event) {

        // float azimuth_angle = event.values[0];
        x = event.values[1];
        y = event.values[2];

        // FIXME: Fine tune this for the image taking part
        float ratio = 70.0f / 25.0f;
        x = x * ratio;
        y = y * ratio;

        Log.d(TAG, "x and y: " + x + " " + y);

        float maxDistance = 35; // To calculate this halfOfWidth - viewInset;

                // to calculate between 2 distances 
        float distance = (float) Math.sqrt(((x) * (x)) + ((y) * (y)));

        if (distance > maxDistance) {

            float angle = (float) Math.atan2(x, y);

            / Get new point on the edge of the circle
            y = (float) (Math.cos(angle) * maxDistance);
            x = (float) (Math.sin(angle) * maxDistance);
        }

        x = x + 40; // 40 is the half od the distance of the full width
        y = (y * -1.0f) + 40; // -1.0f is so orientation works like the actual spirit level

        canUserTakePhoto(distance);

    }

    // Change the background
    public void canUserTakePhoto(float treshold) {
        if (treshold > 10) {
            // Not Yet
        } else {
            // take it
        }
    }


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

    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
    }

    public class CustomDrawableView extends ImageView {

        Bitmap b;

        public CustomDrawableView(Context context, Bitmap bitmap) {
            super(context);

            this.b = bitmap;
        }

        @Override
        protected void onDraw(Canvas canvas) {

            canvas.drawBitmap(this.b, x, y, null);

            invalidate();
        }
    }

    @Override
    public void onDestroy() // main thread stopped
    {
        super.onDestroy();
        // wait for threads to exit before clearing app
        System.runFinalizersOnExit(true);
        // remove app from memory
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
        if (previewing) {
            camera.stopPreview();
            previewing = false;
        }

        if (camera != null) {
            try {

                camera.setPreviewDisplay(surfaceHolder);
                camera.startPreview();
                previewing = true;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        camera = Camera.open();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        camera.stopPreview();
        camera.release();
        camera = null;
        previewing = false;
    }

}

干杯。