I have a ListActivity in my android application that works perfectly. Until I decided to add scrolling capabilities by using the accelerometer.
Here's my code:
package be.pxl.minecraftguide;
import android.app.ListActivity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ListView;
import be.pxl.minecraftguide.providers.RecipeCategoryProvider;
public class Crafting extends ListActivity implements SensorEventListener {
private SimpleCursorAdapter adapter;
private SensorManager sensorManager;
private Sensor acceleroMeter;
private float[] history = new float[2];
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.categorylist);
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(RecipeCategoryProvider.CONTENT_URI, null, null, null, null);
String[] from = {RecipeCategoryProvider.COL_CATID, RecipeCategoryProvider.COL_CATIMG, RecipeCategoryProvider.COL_CATDESC};
int[] to = { R.id.txtCatID, R.id.imgCatImage, R.id.txtCatDescription };
adapter = new SimpleCursorAdapter(getApplicationContext(), R.layout.categoryrow, cursor, from, to, 0);
/*SimpleCursorAdapter.ViewBinder viewBinder = new SimpleCursorAdapter.ViewBinder() {
@Override
public boolean setViewValue(View view, Cursor cursor, int arg2) {
if(view.getId() == R.id.imgCatImage) {
ImageView image = (ImageView)findViewById(R.id.imgCatImage);
image.setImageResource(R.drawable.ic_launcher);
}
return false;
}
};*/
setListAdapter(adapter);
//__________BRON/ http://stackoverflow.com/questions/18751878/android-using-the-accelerometer-to-create-a-simple-maraca-app_____________
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
acceleroMeter = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, acceleroMeter, 1000000);
/*recipeListView.setOnClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View row,
int position, long id) {
TextView txtId = (TextView)row.findViewById(R.id.txtRecipeID);
int recipeID = Integer.parseInt(txtId.getText().toString());
String description = ((TextView)row.findViewById(R.id.txtRecipeDescription)).getText().toString();
// Launching new Activity on selecting single List Item
// Intent craftingDetailIntent = new Intent(getApplicationContext(), craftingdetail.class);
// sending data to new activity
//craftingDetailIntent.putExtra("Category", item);
//startActivity(craftingDetailIntent);
}
});*/
}
/*@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
int recipeID = Integer.parseInt(v.getTag().toString());
}*/
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
sensorManager.unregisterListener(this); //De accelerometer afzetten
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
sensorManager.registerListener(this, acceleroMeter, SensorManager.SENSOR_DELAY_UI); //De accelerometer opnieuw starten
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float xChange = history[0] - event.values[0];
float yChange = history[1] - event.values[1]; //Verschil tussen nieuwe en oude positie ophalen.
history[0] = event.values[0];
history[1] = event.values[1]; //Nieuwe waarden bewaren voor volgende event trigger
if (xChange > 2){
//Links
}
else if (xChange < -2){
//Rechts
}
if (yChange > 2){
getListView().smoothScrollBy(getListView().getHeight() * adapter.getCount(), 2000);
getListView().postDelayed(new Runnable() {
@Override
public void run() {
getListView().smoothScrollBy(0, 0); //Geanimeerd scrollen naar laatste positie
getListView().setSelection(adapter.getCount() - 1);
}
}, 1000);
}
else if (yChange < -2){
getListView().smoothScrollBy(getListView().getHeight() * adapter.getCount(), 2000);
getListView().postDelayed(new Runnable() {
@Override
public void run() {
getListView().smoothScrollBy(0, 0); //Geanimeerd scrollen naar eerste positie positie
getListView().setSelection(0);
}
}, 1000);
}
}
}
}
The problem is, when I make an upward movement, the list should scroll down ad stay at the bottom. But my list scrolls down and then back up occasionally. Same goes for downward movements.
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/minecraft_portrait"
android:transcriptMode="alwaysScroll" >
</ListView>
And not really relevant, but here's my row xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recipeRow"
android:layout_width="match_parent"
android:layout_height="65sp"
android:background="@drawable/listview_selector" >
<TextView
android:id="@+id/txtCatID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:textColor="@android:color/black" />
<ImageView
android:id="@+id/imgCatImage"
android:layout_width="wrap_content"
android:layout_height="55sp"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:src="@drawable/ic_launcher"
android:contentDescription="@string/recipecategory" />
<TextView
android:id="@+id/txtCatDescription"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/imgCatImage"
android:gravity="center"
android:background="#99FFFFFF"
android:textSize="20sp"
android:textColor="@android:color/black"
android:text="test" />
</RelativeLayout>
How can I fix this?
I was looking for the same solution for scrolling a ListActivity using sensors (in context of Google Glass), and the other answer didn't work for me (scrolling was erratic).
I was able to get another version working though, based just on the ListView
(mList
, in the example below). Note that this also assumes a fixed number of items on the screen at one time (since all Glass displays are the same size), but this could be changed to check how many items are on the screen for a more general Android solution. This solution also uses the Sensor.TYPE_ROTATION_VECTOR
, which does some sensor fusion on supported devices, and therefore has a less noisy output (resulting in less unwanted up/down movement).
Register the listener:
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR),
SensorManager.SENSOR_DELAY_UI);
...and here's the onSensorChanged()
method:
@Override
public void onSensorChanged(SensorEvent event) {
if (mList == null) {
return;
}
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
// Only uncomment the below two lines if you're running on Google Glass
//SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X,
// SensorManager.AXIS_Z, mRotationMatrix);
SensorManager.getOrientation(mRotationMatrix, mOrientation);
mHeading = (float) Math.toDegrees(mOrientation[0]);
mPitch = (float) Math.toDegrees(mOrientation[1]);
float xDelta = history[0] - mHeading; // Currently unused
float yDelta = history[1] - mPitch;
history[0] = mHeading;
history[1] = mPitch;
float Y_DELTA_THRESHOLD = 0.10f;
//Log.d(TAG, "Y Delta = " + yDelta);
int scrollHeight = mList.getHeight()
/ 19; // 4 items per page, scroll almost 1/5 an item
//Log.d(TAG, "ScrollHeight = " + scrollHeight);
if (yDelta > Y_DELTA_THRESHOLD) {
//Log.d(TAG, "Detected change in pitch up...");
mList.smoothScrollBy(-scrollHeight, 0);
} else if (yDelta < -Y_DELTA_THRESHOLD) {
//Log.d(TAG, "Detected change in pitch down...");
mList.smoothScrollBy(scrollHeight, 0);
}
}
}
Additional details are in this answer: https://stackoverflow.com/a/23298377/937715
For code that remaps the sensor coordinate system to handle all possible orientation changes on Android devices, see: https://stackoverflow.com/a/22138449/937715