Usando el Acelerómetro en Android
Spanish (Español) translation by CYC (you can also view the original English article)
En este tutorial, vamos a explorar cómo usar el acelerómetro, uno de los muchos sensores de hardware de los teléfonos inteligentes modernos, en una aplicación de Android. Explicaré qué es un acelerómetro y por qué puede ser algo que quieras aprovechar en tus aplicaciones de Android.
Introducción
Antes del comienzo de los teléfonos inteligentes, una de las pocas aplicaciones de componentes de hardware con la que podían interactuar era el teclado. Pero los tiempos han cambiado e interactuar con los componentes de hardware es cada vez más común.
Usar gestos a menudo se siente más natural que interactuar con una interfaz de usuario a través del mouse y el teclado. Esto es especialmente cierto para dispositivos táctiles, como teléfonos inteligentes y tabletas. Encuentro que usar gestos puede darle vida a una aplicación de Android, haciéndola más interesante y emocionante para el usuario.
En este tutorial, utilizaremos un gesto que encontrarás en bastantes aplicaciones móviles, el gesto de agitar. Utilizaremos el gesto de agitar para generar aleatoriamente seis números de lotería y mostrarlos en la pantalla con una bonita animación.
1. Empezando
Paso 1: Configuración del proyecto
Comienza un nuevo proyecto de Android en tu IDE (Entorno de desarrollo integrado) favorito para el desarrollo de Android. Para este tutorial, usaré IntelliJ IDEA.
Si tu IDE es compatible con el desarrollo de Android, habrá creado una clase Main para ti. El nombre de esta clase puede variar según el IDE que estés utilizando. La clase Main juega un papel clave cuando se inicia tu aplicación. Tu IDE también debe haber creado un archivo de diseño principal que utiliza la clase Main para crear la interfaz de usuario de la aplicación.
Como vamos a utilizar un gesto de agitar, es una buena idea bloquear la orientación del dispositivo. Esto asegurará que la interfaz de usuario de la aplicación no cambie constantemente entre vertical y horizontal. Abre el archivo de manifiesto del proyecto y establece la opción screenOrientation en portrait.
1 |
<activity android:name="com.Lottery.Main" |
2 |
android:screenOrientation="portrait" |
3 |
android:label="@string/app_name"> |
4 |
<intent-filter>
|
5 |
<action android:name="android.intent.action.MAIN" /> |
6 |
<category android:name="android.intent.category.LAUNCHER" /> |
7 |
</intent-filter>
|
8 |
</activity>
|
Paso 2: Configuración del Sensor
Con nuestro proyecto configurado, es hora de ensuciarnos las manos y escribir algún código. Por el momento, la clase de actividad principal tiene un método onCreate en el que establecemos el diseño principal invocando setContentView como se muestra a continuación.
1 |
public class Main extends Activity { |
2 |
|
3 |
/** Called when the activity is first created. */
|
4 |
@Override
|
5 |
public void onCreate(Bundle savedInstanceState) { |
6 |
super.onCreate(savedInstanceState); |
7 |
setContentView(R.layout.main); |
8 |
}
|
9 |
}
|
Según el IDE que estés utilizando, es posible que necesites agregar algunas instrucciones de importación a Main.java, el archivo en el que vive tu clase Main. La mayoría de los IDEs insertarán estas declaraciones de importación por ti, pero quiero asegurarme de que estamos en la misma página antes de continuar. La primera instrucción de importación, import android.app.Activity, importa la clase Activity mientras que la segunda instrucción de importación, import android.os.Bundle, importa la clase Bundle. La tercera instrucción de importación, com.example.R, contiene las definiciones de los recursos de la aplicación. Esta declaración de importación diferirá de la que ves a continuación, ya que depende del nombre de tu paquete.
1 |
import android.app.Activity; |
2 |
import android.os.Bundle; |
3 |
import com.example.R; |
En el siguiente paso, aprovecharemos la interfaz SensorEventListener, que se declara en el SDK de Android. Para usar la interfaz SensorEventListener, la clase de actividad Main debes implementarla como se muestra en el fragmento de código a continuación. Si echas un vistazo a la clase de actividad Main actualizada, encontrarás que utilizo la palabra clave implements para decirle al compilador que la clase Main implementa la interfaz SensorEventListener.
1 |
public class Main extends Activity implements SensorEventListener { |
2 |
|
3 |
/** Called when the activity is first created. */
|
4 |
@Override
|
5 |
public void onCreate(Bundle savedInstanceState) { |
6 |
super.onCreate(savedInstanceState); |
7 |
setContentView(R.layout.main); |
8 |
}
|
9 |
}
|
Para usar la interfaz SensorEventListener, debes agregar otra declaración de importación como se muestra a continuación. La mayoría de los IDEs te agregarán inteligentemente el extracto de importación, por lo que probablemente no tengas que preocuparte por esto.
1 |
import android.hardware.SensorEventListener; |
A partir del momento en que actualices la implementación de la clase Main como se muestra arriba, verás aparecer algunos errores. Esto no es sorprendente ya que necesitamos implementar dos métodos requeridos de la interfaz SensorEventListener.
Si estás utilizando IntelliJ IDEA, se te pedirá que agregues estos métodos necesarios al hacer clic en el error. Si estás utilizando un IDE diferente, este comportamiento puede ser diferente. Agreguemos los dos métodos necesarios a mano como se muestra en el fragmento de código a continuación. Asegúrate de agregar estos métodos en la clase Main y fuera del método onCreate.
1 |
@Override
|
2 |
public void onSensorChanged(SensorEvent event) { |
3 |
|
4 |
}
|
5 |
|
6 |
@Override
|
7 |
public void onAccuracyChanged(Sensor sensor, int accuracy) { |
8 |
|
9 |
}
|
Echemos un vistazo al método onSensorChanged. Usaremos este método para detectar el gesto de agitar. El método onSensorChanged se invoca cada vez que el sensor incorporado detecta un cambio. Este método se invoca repetidamente cada vez que el dispositivo está en movimiento. Para usar las clases Sensor y SensorEvent, agregamos dos instrucciones de importación adicionales como se muestra a continuación.
1 |
import android.hardware.Sensor; |
2 |
import android.hardware.SensorEvent; |
Antes de implementar onSensorChanged, debemos declarar dos variables privadas en la clase Main, senSensorManager de tipo SensorManager y senAccelerometer de tipo Sensor.
1 |
private SensorManager senSensorManager; |
2 |
private Sensor senAccelerometer; |
La clase SensorManager se declara en android.hardware.SensorManager. Si ves aparecer algún error, vuelve a verificar que también se importe la clase SensorManager.
1 |
import android.hardware.SensorManager; |
En el método onCreate, inicializamos las variables que acabamos de declarar y registramos un receptor. Echa un vistazo a la implementación actualizada del método onCreate.
1 |
@Override
|
2 |
protected void onCreate(Bundle savedInstanceState) { |
3 |
super.onCreate(savedInstanceState); |
4 |
setContentView(R.layout.activity_main); |
5 |
|
6 |
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); |
7 |
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); |
8 |
senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL); |
9 |
}
|
Para inicializar la instancia de SensorManager, invocamos a getSystemService para buscar la instancia del SensorManager del sistema, el cual a su vez usamos para acceder a los sensores del sistema. El método getSystemService se usa para obtener una referencia de un servicio del sistema al pasar el nombre del servicio. Con el administrador de sensores a nuestra disposición, obtenemos una referencia al acelerómetro del sistema invocando getDefaultSensor en el administrador del sensor y pasando el tipo de sensor que nos interesa. Luego registramos el sensor usando uno de los métodos públicos de SensorManager, registerListener. Este método acepta tres argumentos, el contexto de la actividad, un sensor y la velocidad a la que se nos envían los eventos del sensor.
1 |
public class Main extends Activity implements SensorEventListener { |
2 |
private SensorManager senSensorManager; |
3 |
private Sensor senAccelerometer; |
4 |
|
5 |
/** Called when the activity is first created. */
|
6 |
@Override
|
7 |
public void onCreate(Bundle savedInstanceState) { |
8 |
super.onCreate(savedInstanceState); |
9 |
setContentView(R.layout.main); |
10 |
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); |
11 |
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); |
12 |
senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_NORMAL); |
13 |
}
|
14 |
|
15 |
@Override
|
16 |
public void onSensorChanged(SensorEvent sensorEvent) { |
17 |
|
18 |
}
|
19 |
|
20 |
@Override
|
21 |
public void onAccuracyChanged(Sensor sensor, int accuracy) { |
22 |
|
23 |
}
|
24 |
}
|
Hay otros dos métodos que debemos anular, onPause y onResume. Estos son métodos de la clase Main. Es una buena práctica anular el registro del sensor cuando la aplicación hiberne y registre el sensor nuevamente cuando la aplicación se reanude. Echa un vistazo a los fragmentos de código a continuación para tener una idea de cómo funciona esto en la práctica.
1 |
protected void onPause() { |
2 |
super.onPause(); |
3 |
senSensorManager.unregisterListener(this); |
4 |
}
|
1 |
protected void onResume() { |
2 |
super.onResume(); |
3 |
senSensorManager.registerListener(this, senAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); |
4 |
}
|
Paso 3: Detectar el gesto de sacudida
Ahora podemos comenzar a enfocarnos en la sustancia de la aplicación. Se requerirá un poco de matemática para saber cuándo se produce un gesto de sacudida. La mayor parte de la lógica irá al método onSensorChanged. Comenzamos declarando algunas variables en nuestra clase Main. Echa un vistazo al fragmento de código a continuación.
1 |
private long lastUpdate = 0; |
2 |
private float last_x, last_y, last_z; |
3 |
private static final int SHAKE_THRESHOLD = 600; |
Vamos a ampliar la implementación del método onSensorChanged. Tomamos una referencia a la instancia Sensor utilizando la instancia SensorEvent que se nos pasa. Como puedes ver en el siguiente fragmento de código, verificamos que obtengamos una referencia al tipo de sensor correcto, el acelerómetro del sistema.
1 |
public void onSensorChange(SensorEvent sensorEvent) { |
2 |
Sensor mySensor = sensorEvent.sensor; |
3 |
|
4 |
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) { |
5 |
|
6 |
}
|
7 |
}
|
El siguiente paso es extraer la posición del dispositivo en el espacio, los ejes x, y y z. Echa un vistazo a la imagen a continuación para entender mejor a qué me refiero. El eje x define el movimiento lateral, mientras que el eje y define el movimiento vertical. El eje z es un poco más complicado ya que define el movimiento dentro y fuera del plano definido por los ejes x e y.



Para obtener los valores de cada eje, le pedimos al evento del sensor sus valores como se muestra a continuación. El atributo values del evento es una matriz flotante.
1 |
public void onSensorChange(SensorEvent sensorEvent) { |
2 |
Sensor mySensor = sensorEvent.sensor; |
3 |
|
4 |
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) { |
5 |
float x = sensorEvent.values[0]; |
6 |
float y = sensorEvent.values[1]; |
7 |
float z = sensorEvent.values[2]; |
8 |
}
|
9 |
}
|
Los sensores del sistema son increíblemente sensibles. Cuando sostienes un dispositivo en la mano, está constantemente en movimiento, sin importar qué tan firme sea tu mano. El resultado es que el método onSensorChanged se invoca varias veces por segundo. No necesitamos todos estos datos, por lo que debemos asegurarnos de que solo mostremos un subconjunto de los datos que obtenemos del acelerómetro del dispositivo. Almacenamos la hora actual del sistema (en milisegundos), la almacenamos en curTime y verificamos si han pasado más de 100 milisegundos desde la última vez que se invocó OnSensorChanged.
1 |
public void onSensorChange(SensorEvent sensorEvent) { |
2 |
Sensor mySensor = sensorEvent.sensor; |
3 |
|
4 |
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) { |
5 |
float x = sensorEvent.values[0]; |
6 |
float y = sensorEvent.values[1]; |
7 |
float z = sensorEvent.values[2]; |
8 |
|
9 |
long curTime = System.currentTimeMillis(); |
10 |
|
11 |
if ((curTime - lastUpdate) > 100) { |
12 |
long diffTime = (curTime - lastUpdate); |
13 |
lastUpdate = curTime; |
14 |
}
|
15 |
}
|
16 |
}
|
La última pieza del rompecabezas es detectar si el dispositivo ha sido sacudido o no. Usamos la clase Math para calcular la velocidad del dispositivo como se muestra a continuación. La variable SHAKE_THRESHOLD declarada estáticamente se usa para ver si se ha detectado o no un gesto de sacudida. La modificación de SHAKE_THRESHOLD aumenta o disminuye la sensibilidad, así que no dudes en jugar con su valor.
1 |
public void onSensorChange(SensorEvent sensorEvent) { |
2 |
Sensor mySensor = sensorEvent.sensor; |
3 |
|
4 |
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) { |
5 |
float x = sensorEvent.values[0]; |
6 |
float y = sensorEvent.values[1]; |
7 |
float z = sensorEvent.values[2]; |
8 |
|
9 |
long curTime = System.currentTimeMillis(); |
10 |
|
11 |
if ((curTime - lastUpdate) > 100) { |
12 |
long diffTime = (curTime - lastUpdate); |
13 |
lastUpdate = curTime; |
14 |
|
15 |
float speed = Math.abs(x + y + z - last_x - last_y - last_z)/ diffTime * 10000; |
16 |
|
17 |
if (speed > SHAKE_THRESHOLD) { |
18 |
|
19 |
}
|
20 |
|
21 |
last_x = x; |
22 |
last_y = y; |
23 |
last_z = z; |
24 |
}
|
25 |
}
|
26 |
}
|
2. Acabando la aplicación de la lotería
Ahora tenemos una aplicación que puede detectar un gesto de sacudida con el acelerómetro. Terminemos este proyecto usando el gesto de agitar para elegir seis números aleatorios de lotería. Te mostraré cómo generar un número aleatorio entre 1 y 49, pero puedes modificar mi implementación para que funcione con la forma en que se juega en tu país.
Comencemos configurando el archivo de diseño principal de la aplicación que usaremos para la interfaz de usuario. Como puedes ver a continuación, utilizo seis diseños de cuadros con un fondo de una imagen de una pelota.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
android:orientation="vertical" |
4 |
android:layout_width="fill_parent" |
5 |
android:layout_height="fill_parent"> |
6 |
<LinearLayout
|
7 |
android:layout_height="wrap_content" |
8 |
android:layout_width="fill_parent" |
9 |
android:weightSum="6" |
10 |
android:orientation="horizontal"> |
11 |
<FrameLayout
|
12 |
android:layout_height="wrap_content" |
13 |
android:layout_width="wrap_content" |
14 |
android:layout_margin="5dp" |
15 |
android:layout_weight="2" |
16 |
android:id="@+id/ball_1" |
17 |
android:background="@drawable/blue"> |
18 |
<TextView
|
19 |
android:layout_width="fill_parent" |
20 |
android:layout_height="fill_parent" |
21 |
android:id="@+id/number_1" |
22 |
android:gravity="center" |
23 |
android:layout_gravity="center_vertical" |
24 |
android:textColor="@android:color/white"/> |
25 |
</FrameLayout>
|
26 |
<FrameLayout
|
27 |
android:layout_height="wrap_content" |
28 |
android:layout_width="wrap_content" |
29 |
android:layout_margin="5dp" |
30 |
android:layout_weight="2" |
31 |
android:id="@+id/ball_2" |
32 |
android:background="@drawable/blue"> |
33 |
<TextView
|
34 |
android:layout_width="fill_parent" |
35 |
android:layout_height="fill_parent" |
36 |
android:id="@+id/number_2" |
37 |
android:gravity="center" |
38 |
android:layout_gravity="center_vertical" |
39 |
android:textColor="@android:color/white"/> |
40 |
</FrameLayout>
|
41 |
<FrameLayout
|
42 |
android:layout_height="wrap_content" |
43 |
android:layout_width="wrap_content" |
44 |
android:layout_margin="5dp" |
45 |
android:layout_weight="2" |
46 |
android:id="@+id/ball_3" |
47 |
android:background="@drawable/blue"> |
48 |
<TextView
|
49 |
android:layout_width="fill_parent" |
50 |
android:layout_height="fill_parent" |
51 |
android:id="@+id/number_3" |
52 |
android:gravity="center" |
53 |
android:layout_gravity="center_vertical" |
54 |
android:textColor="@android:color/white"/> |
55 |
</FrameLayout>
|
56 |
</LinearLayout>
|
57 |
|
58 |
<LinearLayout
|
59 |
android:layout_height="wrap_content" |
60 |
android:layout_width="fill_parent" |
61 |
android:weightSum="6" |
62 |
android:orientation="horizontal"> |
63 |
<FrameLayout
|
64 |
android:layout_height="wrap_content" |
65 |
android:layout_width="wrap_content" |
66 |
android:layout_margin="5dp" |
67 |
android:layout_weight="2" |
68 |
android:id="@+id/ball_4" |
69 |
android:background="@drawable/blue"> |
70 |
<TextView
|
71 |
android:layout_width="fill_parent" |
72 |
android:layout_height="fill_parent" |
73 |
android:id="@+id/number_4" |
74 |
android:gravity="center" |
75 |
android:layout_gravity="center_vertical" |
76 |
android:textColor="@android:color/white"/> |
77 |
</FrameLayout>
|
78 |
<FrameLayout
|
79 |
android:layout_height="wrap_content" |
80 |
android:layout_width="wrap_content" |
81 |
android:layout_margin="5dp" |
82 |
android:id="@+id/ball_5" |
83 |
android:layout_weight="2" |
84 |
android:background="@drawable/blue"> |
85 |
<TextView
|
86 |
android:layout_width="fill_parent" |
87 |
android:layout_height="fill_parent" |
88 |
android:id="@+id/number_5" |
89 |
android:gravity="center" |
90 |
android:layout_gravity="center_vertical" |
91 |
android:textColor="@android:color/white"/> |
92 |
</FrameLayout>
|
93 |
<FrameLayout
|
94 |
android:layout_height="wrap_content" |
95 |
android:layout_width="wrap_content" |
96 |
android:layout_margin="5dp" |
97 |
android:id="@+id/ball_6" |
98 |
android:layout_weight="2" |
99 |
android:background="@drawable/blue"> |
100 |
<TextView
|
101 |
android:layout_width="fill_parent" |
102 |
android:layout_height="fill_parent" |
103 |
android:id="@+id/number_6" |
104 |
android:gravity="center" |
105 |
android:layout_gravity="center_vertical" |
106 |
android:textColor="@android:color/white"/> |
107 |
</FrameLayout>
|
108 |
</LinearLayout>
|
109 |
|
110 |
</LinearLayout>
|
Cada diseño de marco contiene una vista de texto que mostrará un número de lotería generado aleatoriamente. Ten en cuenta que cada diseño de marco y vista de texto tiene una identificación id para asegurarnos de que podamos hacer referencia a ellos más tarde.
Con el diseño principal listo para usar, revisemos la clase Main. Comenzamos creando getRandomNumber, un método privado para generar seis números aleatorios entre 1 y 49.
1 |
private void getRandomNumber() { |
2 |
ArrayList numbersGenerated = new ArrayList(); |
3 |
|
4 |
for (int i = 0; i < 6; i++) { |
5 |
Random randNumber = new Random(); |
6 |
int iNumber = randNumber.nextInt(48) + 1; |
7 |
|
8 |
if(!numbersGenerated.contains(iNumber)) { |
9 |
numbersGenerated.add(iNumber); |
10 |
} else { |
11 |
i--; |
12 |
}
|
13 |
}
|
14 |
}
|
Primero creamos una instancia de ArrayList, que usaremos para almacenar los seis números. En cada bucle del bucle for, aprovechamos la clase Random de Java para generar un número aleatorio. Para asegurarnos de obtener un número entre 1 y 49, agregamos 1 al resultado. El siguiente paso es verificar si el número generado ya está en la lista de arreglos, porque solo queremos números únicos en la lista de arreglos.
Ten en cuenta que puede ser necesario agregar dos instrucciones de importación más para mantener feliz al compilador.
1 |
import java.util.ArrayList; |
2 |
import java.util.Random; |
El último paso es mostrar el número generado aleatoriamente en la interfaz de usuario. Obtenemos una referencia a las vistas de texto que creamos anteriormente y llenamos cada vista de texto con un número aleatorio. También agregamos una animación ordenada a los diseños de cuadros, pero no dudes en omitir o modificar la animación.
1 |
private void getRandomNumber() { |
2 |
ArrayList numbersGenerated = new ArrayList(); |
3 |
|
4 |
for (int i = 0; i < 6; i++) { |
5 |
Random randNumber = new Random(); |
6 |
int iNumber = randNumber.nextInt(48) + 1; |
7 |
|
8 |
if(!numbersGenerated.contains(iNumber)) { |
9 |
numbersGenerated.add(iNumber); |
10 |
} else { |
11 |
i--; |
12 |
}
|
13 |
}
|
14 |
|
15 |
TextView text = (TextView)findViewById(R.id.number_1); |
16 |
text.setText(""+numbersGenerated.get(0)); |
17 |
|
18 |
text = (TextView)findViewById(R.id.number_2); |
19 |
text.setText(""+numbersGenerated.get(1)); |
20 |
|
21 |
text = (TextView)findViewById(R.id.number_3); |
22 |
text.setText(""+numbersGenerated.get(2)); |
23 |
|
24 |
text = (TextView)findViewById(R.id.number_4); |
25 |
text.setText(""+numbersGenerated.get(3)); |
26 |
|
27 |
text = (TextView)findViewById(R.id.number_5); |
28 |
text.setText(""+numbersGenerated.get(4)); |
29 |
|
30 |
text = (TextView)findViewById(R.id.number_6); |
31 |
text.setText(""+numbersGenerated.get(5)); |
32 |
|
33 |
FrameLayout ball1 = (FrameLayout) findViewById(R.id.ball_1); |
34 |
ball1.setVisibility(View.INVISIBLE); |
35 |
|
36 |
FrameLayout ball2 = (FrameLayout) findViewById(R.id.ball_2); |
37 |
ball2.setVisibility(View.INVISIBLE); |
38 |
|
39 |
FrameLayout ball3 = (FrameLayout) findViewById(R.id.ball_3); |
40 |
ball3.setVisibility(View.INVISIBLE); |
41 |
|
42 |
FrameLayout ball4 = (FrameLayout) findViewById(R.id.ball_4); |
43 |
ball4.setVisibility(View.INVISIBLE); |
44 |
|
45 |
FrameLayout ball5 = (FrameLayout) findViewById(R.id.ball_5); |
46 |
ball5.setVisibility(View.INVISIBLE); |
47 |
|
48 |
FrameLayout ball6 = (FrameLayout) findViewById(R.id.ball_6); |
49 |
ball6.setVisibility(View.INVISIBLE); |
50 |
|
51 |
Animation a = AnimationUtils.loadAnimation(this, R.anim.move_down_ball_first); |
52 |
ball6.setVisibility(View.VISIBLE); |
53 |
ball6.clearAnimation(); |
54 |
ball6.startAnimation(a); |
55 |
|
56 |
ball5.setVisibility(View.VISIBLE); |
57 |
ball5.clearAnimation(); |
58 |
ball5.startAnimation(a); |
59 |
|
60 |
ball4.setVisibility(View.VISIBLE); |
61 |
ball4.clearAnimation(); |
62 |
ball4.startAnimation(a); |
63 |
|
64 |
ball3.setVisibility(View.VISIBLE); |
65 |
ball3.clearAnimation(); |
66 |
ball3.startAnimation(a); |
67 |
|
68 |
ball2.setVisibility(View.VISIBLE); |
69 |
ball2.clearAnimation(); |
70 |
ball2.startAnimation(a); |
71 |
|
72 |
ball1.setVisibility(View.VISIBLE); |
73 |
ball1.clearAnimation(); |
74 |
ball1.startAnimation(a); |
75 |
}
|
Tendremos que agregar algunas declaraciones de importación para que todo esto funcione. Echa un vistazo al fragmento de código a continuación.
1 |
import android.view.View; |
2 |
import android.view.animation.Animation; |
3 |
import android.view.animation.AnimationUtils; |
4 |
import android.widget.FrameLayout; |
5 |
import android.widget.TextView; |
En cuanto a las animaciones, echa un vistazo al contenido del archivo de animación a continuación. Ten en cuenta que debes crear una carpeta anim en el directorio de recursos de tu proyecto y asignarle el nombre move_down_ball_first.xml. Al ajustar los valores del elemento scale, puedes modificar la duración de la animación y la posición de cada bola.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<set xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
android:fillAfter="true" |
4 |
android:interpolator="@android:anim/bounce_interpolator"> |
5 |
|
6 |
<scale
|
7 |
android:duration="1500" |
8 |
android:fromXScale="1.0" |
9 |
android:fromYScale="-10.0" |
10 |
android:toXScale="1.0" |
11 |
android:toYScale="1.0" /> |
12 |
</set>
|
Todo lo que nos queda por hacer es llamar a getRandomNumber en onSensorChanged en la clase Main. Echa un vistazo a la implementación completa de onSensorChanged que se muestra a continuación.
1 |
public void onSensorChange(SensorEvent sensorEvent) { |
2 |
Sensor mySensor = sensorEvent.sensor; |
3 |
|
4 |
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) { |
5 |
float x = sensorEvent.values[0]; |
6 |
float y = sensorEvent.values[1]; |
7 |
float z = sensorEvent.values[2]; |
8 |
|
9 |
long curTime = System.currentTimeMillis(); |
10 |
|
11 |
if ((curTime - lastUpdate) > 100) { |
12 |
long diffTime = (curTime - lastUpdate); |
13 |
lastUpdate = curTime; |
14 |
|
15 |
float speed = Math.abs(x + y + z - last_x - last_y - last_z)/ diffTime * 10000; |
16 |
|
17 |
if (speed > SHAKE_THRESHOLD) { |
18 |
getRandomNumber(); |
19 |
}
|
20 |
|
21 |
last_x = x; |
22 |
last_y = y; |
23 |
last_z = z; |
24 |
}
|
25 |
}
|
26 |
}
|

Conclusión
En este tutorial, te he mostrado cómo funciona el acelerómetro y cómo puedes usarlo para detectar un gesto de sacudida. Por supuesto, hay muchos otros casos de uso para el acelerómetro. Con un entendimiento básico de la detección de gestos usando el acelerómetro, te animo a experimentar con el acelerómetro para ver qué más puedes hacer con él.



