Mover una imagen usando Accelerometer of android

He leído artículos / tutoriales sobre cómo acceder a los valores del acelerómetro (aceleración y orientación) del teléfono. Intento crear una aplicación simple donde pueda mover una imagen de bola usando estos valores. Aquí está mi código:

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(); } } } 

Me aparece una forma ovalada en la pantalla, pero no pasa nada después de eso.

Gracias

Usa este código Nunca estableciste la ubicación del dibujable después de haber inicializado esa clase. Tendrás que hacer algunos cálculos para establecer la ubicación de las bolas correctamente. La forma en que lo hacían era obteniendo valores por encima de 10000 que sacaban el óvalo de la pantalla.

 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(); } } } 

Aquí está mi implementación de este problema. La solución de Dymmeh me seguía causando problemas, así que lo reformulé hasta que lo puse en funcionamiento.

 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(); } } } 

He hecho algunos cambios en el código onSensorChange para mover la bola en la pantalla. Con el ejemplo en mi caso, la pelota no se mueve correctamente y para eso hice los cambios. Este ejemplo funciona bien para mi.

 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; } } } } 

La clase de vista donde dibujo el balón

 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(); } } 

}

Eso es todo, espero que nos ayuden.

Intente utilizar sensorEvent.values[0] para su xChange y sensorEvents.values[1] para su yChange si desea usar el sensor de aceleración, si no utiliza los mismos valores y muévalo al ( sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION ) if instrucción, esto le dará la inclinación del teléfono en lugar de la rapidez con que se mueve a lo largo de un eje.

También necesita llamar a invalidate(); en la Vista cuando configura o cambia un sensor.

El Sensor.TYPE_ACCELEROMETER regresa:

 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 

El Sensor.TYPE_ORIENTATION regresa:

values[0] : Azimut, ángulo entre la dirección del norte magnético y el eje y, alrededor del eje z (0 a 359). 0 = Norte, 90 = Este, 180 = Sur, 270 = Oeste

values[1] : Paso, rotación alrededor del eje x (-180 a 180), con valores positivos cuando el eje z se mueve hacia el eje y.

values[2] : Roll, rotación alrededor del eje y (-90 a 90), con valores positivos cuando el eje x se mueve hacia el eje z.

utilice la siguiente biblioteca en lugar de movimiento de desplazamiento

agregue esta línea en la vista XML superior

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

para el diseño

   

para el código en su método onCreate ()

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

en su método onResume ()

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

en su método onDestroy ()

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

Creo que debe invalidar su vista en el método onSensorChanged () o en una tasa de fps específica que debe implementar.