ListView Item Fling Gesture

MetBo

MetBo

Erfahrenes Mitglied
4
Hallo,

ich habe in meiner App eine ListView, in der ich gerne die "Fling Gesture" einbauen möchte. Dabei soll nicht die gesamte ListView angesprochen werden, sondern nur einzelne Einträge (wie in der Twitter-App, wenn man nach rechts oder links swipt).

Um dies umzusetzen, habe ich mir gedacht, dass ich in jedem Eintrag ein ViewFlipper einbaue und über den Adapter die Gesten steuere.

Code:
package com.scibli.audio.recorder.utils;

import java.util.ArrayList;

import android.content.Context;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.ViewFlipper;

import com.scibli.audio.recorder.R;

public class FileInfoAdapter extends BaseAdapter implements OnGestureListener, OnTouchListener {
	protected static final CharSequence TAG = Util.getPackageName();
	protected static final int SWIPE_MIN_DISTANCE = 120;
	protected static final int SWIPE_MAX_OFF_PATH = 250;
	protected static final int SWIPE_THRESHOLD_VELOCITY = 200;
	
	protected final Context mContext;
	protected final LayoutInflater mLayoutInflater;
	protected final GestureDetector mGestureDetector;
	
	protected ArrayList<FileInfo> mFileInfos;
	
	protected TextView mTextFileName;
	protected TextView mTextDateTime;
	protected TextView mTextFileSize;
	protected TextView mTextDuration;
	protected TextView mTextFileFormat;
	protected ViewFlipper mFlipperEntry;
	
	public FileInfoAdapter(Context context, ArrayList<FileInfo> fileInfos) {
		mContext = context;
		mFileInfos = fileInfos;
		mLayoutInflater = (LayoutInflater) mContext.getSystemService(
				Context.LAYOUT_INFLATER_SERVICE);
		mGestureDetector = new GestureDetector(this);
	}

	@Override
	public int getCount() {
		return mFileInfos.size();
	}

	@Override
	public Object getItem(int arg0) {
		return mFileInfos.get(arg0);
	}

	@Override
	public long getItemId(int arg0) {
		return 0;
	}

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {
		final View view = mLayoutInflater.inflate(R.layout.recorderlist_entry, null);
		final FileInfo fileInfo = mFileInfos.get(arg0);
		final CharSequence dateTime = android.text.format.DateFormat.getMediumDateFormat(mContext).format(
				fileInfo.getDateTime()) + " " + android.text.format.DateFormat.getTimeFormat(mContext).format(
						fileInfo.getDateTime());
		
		mTextFileName = (TextView) view.findViewById(R.id.textFileName);
		mTextFileName.setText(fileInfo.getFileName());
		
		mTextDateTime = (TextView) view.findViewById(R.id.textDateTime);
		mTextDateTime.setText(dateTime);
		
		mTextFileSize = (TextView) view.findViewById(R.id.textFileSize);
		mTextFileSize.setText(fileInfo.getFileSize());
		
		mTextDuration = (TextView) view.findViewById(R.id.textDuration);
		mTextDuration.setText(fileInfo.getDuration());
		
		mTextFileFormat = (TextView) view.findViewById(R.id.textFileFormat);
		mTextFileFormat.setText(fileInfo.getFileFormat());
		
		mFlipperEntry =(ViewFlipper) view.findViewById(R.id.flipperEntry);
		mFlipperEntry.setInAnimation(mContext, android.R.anim.fade_in);
		mFlipperEntry.setOutAnimation(mContext, android.R.anim.fade_out);
		
		view.setOnTouchListener((OnTouchListener) this);
		return view;
	}

	@Override
	public boolean onDown(MotionEvent arg0) {
		return true;
	}

	@Override
	public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		try {
            if(arg0.getX() > arg1.getX() && Math.abs(arg0.getX() - arg1.getX()) > SWIPE_MIN_DISTANCE 
            		&& Math.abs(arg2) > SWIPE_THRESHOLD_VELOCITY) {
                mFlipperEntry.showNext();
            }else if (arg0.getX() < arg1.getX() && arg1.getX() - arg0.getX() > SWIPE_MIN_DISTANCE 
            		&& Math.abs(arg2) > SWIPE_THRESHOLD_VELOCITY) {
            	mFlipperEntry.showPrevious();
            }
        } catch (Exception e) {
            Log.e(TAG.toString(), e.getMessage());
        }
		
		return true;
	}

	@Override
	public void onLongPress(MotionEvent arg0) {}

	@Override
	public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		return true;
	}

	@Override
	public void onShowPress(MotionEvent arg0) {}

	@Override
	public boolean onSingleTapUp(MotionEvent arg0) {
		return true;
	}

	@Override
	public boolean onTouch(View arg0, MotionEvent arg1) {
		return mGestureDetector.onTouchEvent(arg1);
	}

}

Problem dabei ist: Generell funktioniert dies ja, aber leider wird beim "flingen" immer der letzte Eintrag in der ListView angesprochen.

Habt ihr eine Idee, wie ich jeden Eintrag einzeln ansprechen kann?
Oder kennt ihr einen besseren Lösungsweg, wie ich dieses Feature von der Twitter-App nachbauen kann?

Vielen Dank,
Grüße
 
Push. Kennt keiner eine Lösung?
 
Servus,

wie hast du eigentlich die onFling() method und das amount of time we set gelöst. "Fling gesture" wird ja nur erkannt, so lange der Finger das Display berührt.
 
Zuletzt bearbeitet von einem Moderator:
Das ist die Frage. onFling wird durch
mGestureDetector.onTouchEvent(arg1);
erkannt bzw. initialisiert.

Ich habe noch einen anderen Weg getestet: Den Gesturedetector der ListView zugewiesen. Dabei kann ich auch das entsprechende Item aus der Liste mit pointToPosition ansprechen. Nur leider reagiert der ViewFlipper dann nicht.
 
Stört es Dich wenn ich an deinem Code ein paar Versuche unternehme?

PS das final float finde ich nicht
 
Zuletzt bearbeitet von einem Moderator:
Nein natürlich nicht. Was hast du denn vor? ;-)
 
Du hast da den onTouchListener anstatt den gestureListener?
 
Richtig, aber im Grunde ist der GestureListener ein onTouchListener ;-) Von daher ist es eigentlich egal, ob ich ihn implementiere, oder als Variable nutze.
 
ich nehm mal ein Beispiel für "Gesture" und "Listener":


  1. @Override
  2. public boolean onTouchEvent(MotionEvent event) {
  3. return gestures.onTouchEvent(event);
  4. }
@Overridepublic boolean onTouchEvent(MotionEvent event) { return gestures.onTouchEvent(event);}
und dann für das implementieren des Listeners:

  1. private class GestureListener implements GestureDetector.OnGestureListener,
  2. GestureDetector.OnDoubleTapListener {
  3. PlayAreaView view;
  4. public GestureListener(PlayAreaView view) {
  5. this.view = view;
  6. }
 
Meine Frage: Ist der GestureListener das richtige Instrument, um mein Problem zu lösen?
 
Ich denke schon - hoffe. :mellow:
 
Wennst die Lösung gefunden hast - schreibs hier rein, es interessiert mich!

Danke!
 
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
return false;
}

int position = mListRecords.pointToPosition((int) Math.abs(e1.getX()), (int) Math.abs(e1.getY()));
ViewFlipper viewFlipper = mFileInfoAdapter.getViewFlipper(position);

if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show();
viewFlipper.showNext();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(getApplicationContext(), "Left Swipe", Toast.LENGTH_SHORT).show();
viewFlipper.showNext();
}
} catch (Exception e) {
// nothing
}
return true;
}
}

Folgendes hatte ich eingebaut, hatte aber das gleiche Resultat wie vorher: nämlich keins!
 
Das Problem ist nicht das "Swipen" bzw "Flingen". Das funktioniert mit dem letzten Code von mir. Der ViewFlipper ist wohl das Problem ... Dieser reagiert nicht bei "showNext()". Aber gerne poste ich noch einmal meinen Code, damit du den aktuellen Code hast.
 
Ja gerne - somit ist das WE schon gerettet. :thumbup:
 
List Activity
Code:
public class ListActivity extends Activity  {
	protected static final CharSequence TAG = Util.getPackageName();
	protected static final CharSequence DIRECTORY = Util.getDirectory();
	
	protected static final int SWIPE_MIN_DISTANCE = 120;
	protected static final int SWIPE_MAX_OFF_PATH = 250;
	protected static final int SWIPE_THRESHOLD_VELOCITY = 200;
	
	protected ArrayList<FileInfo> mFileInfos;
	protected Context mContext;
	protected FileInfoAdapter mFileInfoAdapter;
	
	protected ListView mListRecords;
	
	protected GestureDetector mGestureDetector;
	protected View.OnTouchListener mGestureListener;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recordlist);
        
        // Liste der Aufnahmen
        mListRecords = (ListView) findViewById(R.id.listRecords);
        
        mContext = getApplicationContext();
        	
		// Alle Dateien aus dem Verzeichnis in der ListView anzeigen
		mFileInfos = getFileArray();
		
		mFileInfoAdapter = new FileInfoAdapter(mContext, mFileInfos);
		mListRecords.setAdapter(mFileInfoAdapter);
		
		mGestureDetector = new GestureDetector(new MyGestureDetector());
		mGestureListener = new View.OnTouchListener() {
            public boolean onTouch(View v, MotionEvent aEvent) {
            	return mGestureDetector.onTouchEvent(aEvent);
            }
		};
		mListRecords.setOnTouchListener(mGestureListener);
	}
	
	class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
                	return false;
                }

                int position = mListRecords.pointToPosition((int) Math.abs(e1.getX()), (int) Math.abs(e1.getY()));
                ViewFlipper viewFlipper = mFileInfoAdapter.getViewFlipper(position);
                
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                	Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show();
                	viewFlipper.showNext();
                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                	Toast.makeText(getApplicationContext(), "Left Swipe", Toast.LENGTH_SHORT).show();
                	viewFlipper.showNext();
                }
            } catch (Exception e) {
                // nothing
            }
            return true;
        }
	}
}

FileInfo Adapter
Code:
public class FileInfoAdapter extends BaseAdapter {
	protected static final CharSequence TAG = Util.getPackageName();
	protected static final int SWIPE_MIN_DISTANCE = 120;
	
	protected final Context mContext;
	protected final LayoutInflater mLayoutInflater;
	protected final ArrayList<SwipedViewFlipper> mSwipedViewFlipperList;
	
	protected ArrayList<FileInfo> mFileInfos;
	
	protected ViewFlipper mFlipperEntry;
	
	public FileInfoAdapter(Context context, ArrayList<FileInfo> fileInfos) {
		mContext = context;
		mFileInfos = fileInfos;
		mLayoutInflater = (LayoutInflater) mContext.getSystemService(
				Context.LAYOUT_INFLATER_SERVICE);
		mSwipedViewFlipperList = new ArrayList<FileInfoAdapter.SwipedViewFlipper>();
	}

	@Override
	public int getCount() {
		return mFileInfos.size();
	}

	@Override
	public Object getItem(int arg0) {
		return mFileInfos.get(arg0);
	}

	@Override
	public long getItemId(int arg0) {
		return 0;
	}

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {
		final View view = mLayoutInflater.inflate(R.layout.recorderlist_entry, null);
		final FileInfo fileInfo = mFileInfos.get(arg0);
		
		mFlipperEntry = (ViewFlipper) view.findViewById(R.id.flipperEntry);
		
		SwipedViewFlipper swipedViewFlipper = null;
		try {
			swipedViewFlipper = mSwipedViewFlipperList.get(arg0);
		} catch (IndexOutOfBoundsException e) {
			swipedViewFlipper = null;
		}
		
		if (swipedViewFlipper == null) {
			Log.e(TAG.toString(), "jo232");
			mSwipedViewFlipperList.add(new SwipedViewFlipper(arg0, mFlipperEntry));
		}
		
		return view;
	}
	
	public ViewFlipper getViewFlipper(int position) {
		try {
			return mSwipedViewFlipperList.get(position).getViewFlipper();
		} catch(IndexOutOfBoundsException e) {
			return null;
		}
	}
	
	protected class SwipedViewFlipper {
		protected int mPosition;
		protected ViewFlipper mViewFlipper;
		
		public SwipedViewFlipper(int position, ViewFlipper viewFlipper) {
			mPosition = position;
			mViewFlipper = viewFlipper;
		}
		
		public ViewFlipper getViewFlipper() {
			return mViewFlipper;
		}
	}
}

Nun ... Wie kriege ich es nun hin, dass in der ListActivity der ViewFlipper mit showNext auf das "onFling" reagiert?
 
Na schau ma mal - ich melde mich im laufe des WEs!
 

Ähnliche Themen

J
Antworten
5
Aufrufe
929
swa00
swa00
A
Antworten
10
Aufrufe
1.021
swa00
swa00
D
Antworten
9
Aufrufe
1.765
jogimuc
J
Zurück
Oben Unten