【问题标题】:Moving an image using Accelerometer of android使用android的加速度计移动图像
【发布时间】:2011-06-23 16:53:35
【问题描述】:

我已阅读有关访问手机加速度计(加速度和方向)值的文章/教程。我正在尝试构建一个简单的应用程序,我可以在其中使用这些值移动球图像。这是我的代码:

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class Accelerometer extends Activity implements SensorEventListener {
    /** Called when the activity is first created. */
     CustomDrawableView mCustomDrawableView = null; 
     ShapeDrawable mDrawable = new ShapeDrawable(); 
      int x ; 
       int y ;

    private SensorManager sensorManager = null;

       /** Called when the activity is first created. */
       @Override
       public void onCreate(Bundle savedInstanceState) {

           super.onCreate(savedInstanceState);
           // Get a reference to a SensorManager
           sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
           mCustomDrawableView = new CustomDrawableView(this); 
           setContentView(mCustomDrawableView); 
         //  setContentView(R.layout.main);

       }

       // This method will update the UI on new sensor events
       public void onSensorChanged(SensorEvent sensorEvent) {
         {
         if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

         int someNumber = 100;
         float xChange = someNumber * sensorEvent.values[1];
         //values[2] can be -90 to 90
         float yChange = someNumber * 2 * sensorEvent.values[2];       
             x = x + (int)xChange;
             y = y + (int)yChange;

         }


         if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) {

         }
        }
       }

       // I've chosen to not implement this method
       public void onAccuracyChanged(Sensor arg0, int arg1) {
     // TODO Auto-generated method stub

    }

       @Override
       protected void onResume() {
        super.onResume();
        // Register this class as a listener for the accelerometer sensor
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
        // ...and the orientation sensor
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
       }

       @Override
       protected void onStop() {
        // Unregister the listener
        sensorManager.unregisterListener(this);
        super.onStop();
       } 
       public  class CustomDrawableView extends View { 

           public CustomDrawableView(Context context) { 
               super(context); 

               int width = 50; 
               int height = 50; 
               mDrawable = new ShapeDrawable(new OvalShape()); 
               mDrawable.getPaint().setColor(0xff74AC23); 
               mDrawable.setBounds(x, y, x + width, y + height); 
           } 
           protected void onDraw(Canvas canvas) { 
               mDrawable.draw(canvas); 
               invalidate(); 
           } 
       }
}

我在屏幕上显示了一个椭圆形,但之后没有任何反应。

谢谢

【问题讨论】:

  • 在你的 onDraw 中你没有做任何事情来移动你的形状。你应该在那里添加代码来设置你的drawable的位置(从你存储的X,Y值)
  • 我该怎么做..你能给我一些示例代码
  • 试着把它放在你的 onDraw 方法中 "RectF 椭圆形 = new RectF(Accelerometer.x, Accelerometer.y, Accelerometer.x + width, Accelerometer.y + height); //设置矩形画图的边界p = new Paint(); //设置一些绘画选项 canvas.drawOval(oval, p);"您需要将 X 和 Y 变量设为公共成员,并且您的宽度/高度必须是 CustomDrawableView 类中的静态值。

标签: android accelerometer


【解决方案1】:

使用此代码。初始化该类后,您从未设置可绘制对象的位置。您必须进行一些计算才能正确设置球的位置。你这样做的方式是获得超过 10000 的值,这会在屏幕上绘制椭圆。

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;

public class Accelerometer extends Activity implements SensorEventListener
{
    /** Called when the activity is first created. */
    CustomDrawableView mCustomDrawableView = null;
    ShapeDrawable mDrawable = new ShapeDrawable();
    public static int x;
    public static int y;

    private SensorManager sensorManager = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {

        super.onCreate(savedInstanceState);
        // Get a reference to a SensorManager
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mCustomDrawableView = new CustomDrawableView(this);
        setContentView(mCustomDrawableView);
        // setContentView(R.layout.main);

    }

    // This method will update the UI on new sensor events
    public void onSensorChanged(SensorEvent sensorEvent)
    {
        {
            if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                // the values you were calculating originally here were over 10000!
                x = (int) Math.pow(sensorEvent.values[1], 2); 
                y = (int) Math.pow(sensorEvent.values[2], 2);

            }

            if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) {

            }
        }
    }

    // I've chosen to not implement this method
    public void onAccuracyChanged(Sensor arg0, int arg1)
    {
        // TODO Auto-generated method stub

    }

    @Override
    protected void onResume()
    {
        super.onResume();
        // Register this class as a listener for the accelerometer sensor
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
        // ...and the orientation sensor
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onStop()
    {
        // Unregister the listener
        sensorManager.unregisterListener(this);
        super.onStop();
    }

    public class CustomDrawableView extends View
    {
        static final int width = 50;
        static final int height = 50;

        public CustomDrawableView(Context context)
        {
            super(context);

            mDrawable = new ShapeDrawable(new OvalShape());
            mDrawable.getPaint().setColor(0xff74AC23);
            mDrawable.setBounds(x, y, x + width, y + height);
        }

        protected void onDraw(Canvas canvas)
        {
            RectF oval = new RectF(Accelerometer.x, Accelerometer.y, Accelerometer.x + width, Accelerometer.y
                    + height); // set bounds of rectangle
            Paint p = new Paint(); // set some paint options
            p.setColor(Color.BLUE);
            canvas.drawOval(oval, p);
            invalidate();
        }
    }
}

【讨论】:

  • 谢谢你..我的图像现在移动了..还没有完成代码..只需复制粘贴并部署到我的手机上。再次感谢
  • 如果这对您有用,请务必将其标记为答案。
  • 这段代码在 Android 2.3 上能用吗,我不这么认为.. 如果我想在 android 2.3 中使用它怎么办
  • @SahilMahajanMj - 当时(2011 年 6 月)只有 2.3 可用于移动设备,我在发布代码之前在自己的设备上进行了测试。它应该工作正常。你能告诉我你遇到了什么问题吗?
  • @SahilMahajanMj - 我刚刚在运行 2.3.7 的三星 Nexus S 上进行了测试,它运行良好
【解决方案2】:

这是我对这个问题的实现。 Dymmeh 的解决方案一直给我带来问题,所以我对其进行了重构,直到我让它工作为止。

package edu.ian495.accelerometertest;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ImageView;

public class MainActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor accelerometer;
    private long lastUpdate;

    AnimatedView animatedView = null;
    ShapeDrawable mDrawable = new ShapeDrawable();
    public static int x;
    public static int y;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);

        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        accelerometer = sensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        lastUpdate = System.currentTimeMillis();

        animatedView = new AnimatedView(this);
        setContentView(animatedView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_GAME);
    }

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // TODO Auto-generated method stub
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

            x -= (int) event.values[0];
            y += (int) event.values[1];

        }
    }

    public class AnimatedView extends ImageView {

        static final int width = 50;
        static final int height = 50;

        public AnimatedView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub

            mDrawable = new ShapeDrawable(new OvalShape());
            mDrawable.getPaint().setColor(0xffffAC23);
            mDrawable.setBounds(x, y, x + width, y + height);

        }

        @Override
        protected void onDraw(Canvas canvas) {

            mDrawable.setBounds(x, y, x + width, y + height);
            mDrawable.draw(canvas);
            invalidate();
        }
    }

}

【讨论】:

  • 终于得到了一个可以工作的代码,但是图像超出了屏幕...如何设置边界?
  • @RishabhSrivastava 我会在 onSensorChanged 函数中加入一个条件 - 例如。 x= (x-(int) event.values[0] > someValue) ? someValue : x-(int) event.values[0]
【解决方案3】:

我对 onSensorChange 代码进行了一些更改,以在屏幕中移动球。在我的例子中,球没有正确移动,为此我做了改变。这个例子很适合我。

public void onSensorChanged(SensorEvent sensorEvent)
{
    //Try synchronize the events
    synchronized(this){
    //For each sensor
    switch (sensorEvent.sensor.getType()) {
    case Sensor.TYPE_MAGNETIC_FIELD: //Magnetic sensor to know when the screen is landscape or portrait
        //Save values to calculate the orientation
        mMagneticValues = sensorEvent.values.clone();
        break;
    case Sensor.TYPE_ACCELEROMETER://Accelerometer to move the ball
        if (bOrientacion==true){//Landscape
            //Positive values to move on x
            if (sensorEvent.values[1]>0){
                //In margenMax I save the margin of the screen this value depends of the screen where we run the application. With this the ball not disapears of the screen
                if (x<=margenMaxX){
                    //We plus in x to move the ball
                    x = x + (int) Math.pow(sensorEvent.values[1], 2);
                }
            }
            else{
                //Move the ball to the other side
                if (x>=margenMinX){
                    x = x - (int) Math.pow(sensorEvent.values[1], 2);
                }
            }
            //Same in y
            if (sensorEvent.values[0]>0){
                if (y<=margenMaxY){
                    y = y + (int) Math.pow(sensorEvent.values[0], 2);
                }
            }
            else{
                if (y>=margenMinY){
                    y = y - (int) Math.pow(sensorEvent.values[0], 2);
                }
            }
        }
        else{//Portrait
            //Eje X
            if (sensorEvent.values[0]<0){
                if (x<=margenMaxX){
                    x = x + (int) Math.pow(sensorEvent.values[0], 2);
                }
            }
            else{
                if (x>=margenMinX){
                    x = x - (int) Math.pow(sensorEvent.values[0], 2);
                }
            }
            //Eje Y
            if (sensorEvent.values[1]>0){
                if (y<=margenMaxY){
                    y = y + (int) Math.pow(sensorEvent.values[1], 2);
                }
            }
            else{
                if (y>=margenMinY){
                    y = y - (int) Math.pow(sensorEvent.values[1], 2);
                }
            }

        }
        //Save the values to calculate the orientation
        mAccelerometerValues = sensorEvent.values.clone();
        break;  
    case Sensor.TYPE_ROTATION_VECTOR:  //Rotation sensor
        //With this value I do the ball bigger or smaller
        if (sensorEvent.values[1]>0){
            z=z+ (int) Math.pow(sensorEvent.values[1]+1, 2);
        }
        else{
            z=z- (int) Math.pow(sensorEvent.values[1]+1, 2);                    
        }

    default:
        break;
    }
    //Screen Orientation
    if (mMagneticValues != null && mAccelerometerValues != null) {
        float[] R = new float[16];
        SensorManager.getRotationMatrix(R, null, mAccelerometerValues, mMagneticValues);
        float[] orientation = new float[3];
        SensorManager.getOrientation(R, orientation);
        //if x have positives values the screen orientation is landscape in other case is portrait
        if (orientation[0]>0){//LandScape
            //Here I change the margins of the screen for the ball not disapear
            bOrientacion=true;
            margenMaxX=1200;
            margenMinX=0;
            margenMaxY=500;
            margenMinY=0;
        }
        else{//Portrait
            bOrientacion=false;
            margenMaxX=600;
            margenMinX=0;
            margenMaxY=1000;
            margenMinY=0;
        }

    }
    }
}

我画球的视图类

public class CustomDrawableView extends View
{
    static final int width = 50;
    static final int height = 50;
    //Constructor de la figura
    public CustomDrawableView(Context context)
    {
        super(context);

        mDrawable = new ShapeDrawable(new OvalShape());
        mDrawable.getPaint().setColor(0xff74AC23);
        mDrawable.setBounds(x, y, x + width, y + height);
    }
    //Dibujamos la figura
    protected void onDraw(Canvas canvas)
    {
        //Actividad_Principal x,y,z are variables from the main activity where I have the onSensorChange
        RectF oval = new RectF(Actividad_Principal.x+Actividad_Principal.z, Actividad_Principal.y+Actividad_Principal.z, Actividad_Principal.x + width, Actividad_Principal.y + height);             
        Paint p = new Paint(); 
        p.setColor(Color.BLUE);
        canvas.drawOval(oval, p);
        invalidate();
    }
}

}

仅此而已,希望对我们有所帮助。

【讨论】:

    【解决方案4】:

    如果您想使用加速度传感器,请尝试将sensorEvent.values[0] 用于您的xChangesensorEvents.values[1] 用于您的yChange,如果不使用相同的值并将其移动到 (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) if 语句中,这将为您提供手机的倾斜度,而不是手机沿轴移动的速度。

    设置或更改传感器时,您还需要在视图上调用invalidate();

    Sensor.TYPE_ACCELEROMETER 返回:

    values[0]: Acceleration minus Gx on the x-axis
    values[1]: Acceleration minus Gy on the y-axis
    values[2]: Acceleration minus Gz on the z-axis
    

    Sensor.TYPE_ORIENTATION 返回:

    values[0]:方位角,磁北方向和 y 轴之间的角度,围绕 z 轴(0 到 359)。 0=北,90=东,180=南,270=西

    values[1]:俯仰,绕 x 轴旋转(-180 到 180),当 z 轴向 y 轴移动时为正值。

    values[2]:滚动,绕 y 轴旋转(-90 到 90),当 x 轴向 z 轴移动时为正值。

    【讨论】:

      【解决方案5】:

      改用以下库scrolling motion

      在顶部 XML 视图中添加这一行

      xmlns:parallax="http://schemas.android.com/apk/res-auto"
      

      用于布局

       <com.nvanbenschoten.motion.ParallaxImageView
                  android:id="@+id/parallex"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:src="@drawable/image_hd"
                  parallax:motionTiltSensitivity="2.5" />
      

      onCreate() 方法中的代码

      ParallaxImageView mBackground = (ParallaxImageView) findViewById(R.id.parallex);
      

      在你的 onResume() 方法中

      if(mBackground!=null)
      mBackground.registerSensorManager();
      

      在你的 onDestroy() 方法中

      // Unregister SensorManager when exiting
      mBackground.unregisterSensorManager();
      

      【讨论】:

        【解决方案6】:

        我认为您需要在 onSensorChanged() 方法中或以您必须实施的特定 fps 速率使您的视图无效。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多