Chcę, aby moja aplikacja rozpoznała, kiedy użytkownik przesuwa palcem z prawej do lewej na ekranie telefonu.
Jak to zrobić?
Chcę, aby moja aplikacja rozpoznała, kiedy użytkownik przesuwa palcem z prawej do lewej na ekranie telefonu.
Jak to zrobić?
Odpowiedzi:
OnSwipeTouchListener.java :
import android.content.Context;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
result = true;
}
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
result = true;
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onSwipeTop() {
}
public void onSwipeBottom() {
}
}
Stosowanie:
imageView.setOnTouchListener(new OnSwipeTouchListener(MyActivity.this) {
public void onSwipeTop() {
Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show();
}
public void onSwipeRight() {
Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show();
}
public void onSwipeLeft() {
Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
}
public void onSwipeBottom() {
Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show();
}
});
OnSwipeTouchListener
który odbiera kontekst, ponieważ ten konstruktor GestureDetector
jest przestarzały od poziomu API 3 i GestureDetector
tworzy instancję w tym konstruktorze.
onTouch
do OnSwipeTouchListener
definicji, w przeciwnym razie moje IDE wyświetli błąd „uzyskiwania dostępu do członka prywatnego”
Ten kod wykrywa przesunięcia w lewo i w prawo, unika przestarzałych wywołań interfejsu API i ma inne różne ulepszenia w porównaniu z wcześniejszymi odpowiedziami.
/**
* Detects left and right swipes across a view.
*/
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener(Context context) {
gestureDetector = new GestureDetector(context, new GestureListener());
}
public void onSwipeLeft() {
}
public void onSwipeRight() {
}
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_DISTANCE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float distanceX = e2.getX() - e1.getX();
float distanceY = e2.getY() - e1.getY();
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (distanceX > 0)
onSwipeRight();
else
onSwipeLeft();
return true;
}
return false;
}
}
}
Użyj tego w ten sposób:
view.setOnTouchListener(new OnSwipeTouchListener(context) {
@Override
public void onSwipeLeft() {
// Whatever
}
});
setOnTouchListener
(zwykle w onCreate
). context
jest this
wskaźnikiem (chyba że tworzysz fragment).
Fragment.getActivity()
.
Jeśli musisz również przetworzyć zdarzenia kliknięcia, niektóre modyfikacje:
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector = new GestureDetector(new GestureListener());
public boolean onTouch(final View v, final MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
result = onSwipeRight();
} else {
result = onSwipeLeft();
}
}
} else {
if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
result = onSwipeBottom();
} else {
result = onSwipeTop();
}
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
public boolean onSwipeRight() {
return false;
}
public boolean onSwipeLeft() {
return false;
}
public boolean onSwipeTop() {
return false;
}
public boolean onSwipeBottom() {
return false;
}
}
I przykładowe użycie:
background.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
toggleSomething();
}
});
background.setOnTouchListener(new OnSwipeTouchListener() {
public boolean onSwipeTop() {
Toast.makeText(MainActivity.this, "top", Toast.LENGTH_SHORT).show();
return true;
}
public boolean onSwipeRight() {
Toast.makeText(MainActivity.this, "right", Toast.LENGTH_SHORT).show();
return true;
}
public boolean onSwipeLeft() {
Toast.makeText(MainActivity.this, "left", Toast.LENGTH_SHORT).show();
return true;
}
public boolean onSwipeBottom() {
Toast.makeText(MainActivity.this, "bottom", Toast.LENGTH_SHORT).show();
return true;
}
});
Rozwijanie odpowiedzi Mireka, na przykład, gdy chcesz użyć gestów przeciągania w widoku przewijania. Domyślnie nasłuchiwanie dotykowe dla widoku przewijania jest wyłączone i dlatego przewijanie się nie dzieje. Aby to naprawić, musisz zastąpić dispatchTouchEvent
metodęActivity
i zwrócić odziedziczoną wersję tej metody po zakończeniu pracy z własnym detektorem.
Aby wprowadzić kilka zmian w kodzie Mireka: dodam getter dla gestureDetector
w OnSwipeTouchListener
.
public GestureDetector getGestureDetector(){
return gestureDetector;
}
Zadeklaruj OnSwipeTouchListener
wnętrze działania jako pole obejmujące całą klasę.
OnSwipeTouchListener onSwipeTouchListener;
Zmodyfikuj odpowiednio kod użytkowania:
onSwipeTouchListener = new OnSwipeTouchListener(MyActivity.this) {
public void onSwipeTop() {
Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show();
}
public void onSwipeRight() {
Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show();
}
public void onSwipeLeft() {
Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
}
public void onSwipeBottom() {
Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show();
}
});
imageView.setOnTouchListener(onSwipeTouchListener);
I zastąp dispatchTouchEvent
metodę wewnątrz Activity
:
@Override
public boolean dispatchTouchEvent(MotionEvent ev){
swipeListener.getGestureDetector().onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
Teraz powinny działać operacje przewijania i przeciągania.
W celu uzyskania Click Listener
, DoubleClick Listener
, OnLongPress Listener
, Swipe Left
, Swipe Right
, Swipe Up
, Swipe Down
na pojedynczych View
trzeba setOnTouchListener
. to znaczy,
view.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) {
@Override
public void onClick() {
super.onClick();
// your on click here
}
@Override
public void onDoubleClick() {
super.onDoubleClick();
// your on onDoubleClick here
}
@Override
public void onLongClick() {
super.onLongClick();
// your on onLongClick here
}
@Override
public void onSwipeUp() {
super.onSwipeUp();
// your swipe up here
}
@Override
public void onSwipeDown() {
super.onSwipeDown();
// your swipe down here.
}
@Override
public void onSwipeLeft() {
super.onSwipeLeft();
// your swipe left here.
}
@Override
public void onSwipeRight() {
super.onSwipeRight();
// your swipe right here.
}
});
}
Do tego potrzebujesz OnSwipeTouchListener
klasy, która implementuje OnTouchListener
.
public class OnSwipeTouchListener implements View.OnTouchListener {
private GestureDetector gestureDetector;
public OnSwipeTouchListener(Context c) {
gestureDetector = new GestureDetector(c, new GestureListener());
}
public boolean onTouch(final View view, final MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
onClick();
return super.onSingleTapUp(e);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
onDoubleClick();
return super.onDoubleTap(e);
}
@Override
public void onLongPress(MotionEvent e) {
onLongClick();
super.onLongPress(e);
}
// Determines the fling velocity and then fires the appropriate swipe event accordingly
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
} else {
if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeDown();
} else {
onSwipeUp();
}
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onSwipeUp() {
}
public void onSwipeDown() {
}
public void onClick() {
}
public void onDoubleClick() {
}
public void onLongClick() {
}
}
Nie potrzebujesz skomplikowanych obliczeń. Można to zrobić tylko za pomocą OnGestureListener
interfejsu z GestureDetector
klasy.
Wewnątrz onFling
metody możesz wykryć wszystkie cztery kierunki w ten sposób:
MyGestureListener.java
:
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
public class MyGestureListener implements GestureDetector.OnGestureListener{
private static final long VELOCITY_THRESHOLD = 3000;
@Override
public boolean onDown(final MotionEvent e){ return false; }
@Override
public void onShowPress(final MotionEvent e){ }
@Override
public boolean onSingleTapUp(final MotionEvent e){ return false; }
@Override
public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
final float distanceY){ return false; }
@Override
public void onLongPress(final MotionEvent e){ }
@Override
public boolean onFling(final MotionEvent e1, final MotionEvent e2,
final float velocityX,
final float velocityY){
if(Math.abs(velocityX) < VELOCITY_THRESHOLD
&& Math.abs(velocityY) < VELOCITY_THRESHOLD){
return false;//if the fling is not fast enough then it's just like drag
}
//if velocity in X direction is higher than velocity in Y direction,
//then the fling is horizontal, else->vertical
if(Math.abs(velocityX) > Math.abs(velocityY)){
if(velocityX >= 0){
Log.i("TAG", "swipe right");
}else{//if velocityX is negative, then it's towards left
Log.i("TAG", "swipe left");
}
}else{
if(velocityY >= 0){
Log.i("TAG", "swipe down");
}else{
Log.i("TAG", "swipe up");
}
}
return true;
}
}
stosowanie:
GestureDetector mDetector = new GestureDetector(MainActivity.this, new MyGestureListener());
view.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(final View v, final MotionEvent event){
return mDetector.onTouchEvent(event);
}
});
velocityX
i velocityY
w onFling
metodzie. chociaż możesz eksperymentować, aby zobaczyć, która wartość najlepiej odpowiada Twoim potrzebom, ale ostateczna liczba byłaby uniwersalna.
Użyj SwipeListView i pozwól obsłużyć wykrywanie gestów za Ciebie.
Wersja @Mirek Rusin Kotlina jest tutaj:
OnSwipeTouchListener.kt:
open class OnSwipeTouchListener(ctx: Context) : OnTouchListener {
private val gestureDetector: GestureDetector
companion object {
private val SWIPE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}
init {
gestureDetector = GestureDetector(ctx, GestureListener())
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true
}
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
var result = false
try {
val diffY = e2.y - e1.y
val diffX = e2.x - e1.x
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
result = true
}
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom()
} else {
onSwipeTop()
}
result = true
}
} catch (exception: Exception) {
exception.printStackTrace()
}
return result
}
}
open fun onSwipeRight() {}
open fun onSwipeLeft() {}
open fun onSwipeTop() {}
open fun onSwipeBottom() {}
}
Stosowanie:
view.setOnTouchListener(object : OnSwipeTouchListener(context) {
override fun onSwipeTop() {
super.onSwipeTop()
}
override fun onSwipeBottom() {
super.onSwipeBottom()
}
override fun onSwipeLeft() {
super.onSwipeLeft()
}
override fun onSwipeRight() {
super.onSwipeRight()
}
})
open
kluczowe był punkt dla mnie ...
Aby dodać również onClick, oto co zrobiłem.
....
// in OnSwipeTouchListener class
private final class GestureListener extends SimpleOnGestureListener {
.... // normal GestureListener code
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
onClick(); // my method
return super.onSingleTapConfirmed(e);
}
} // end GestureListener class
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onSwipeTop() {
}
public void onSwipeBottom() {
}
public void onClick(){
}
// as normal
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
} // end OnSwipeTouchListener class
Używam fragmentów, więc używam getActivity () do kontekstu. Tak to wdrożyłem - i działa.
myLayout.setOnTouchListener(new OnSwipeTouchListener(getActivity()) {
public void onSwipeTop() {
Toast.makeText(getActivity(), "top", Toast.LENGTH_SHORT).show();
}
public void onSwipeRight() {
Toast.makeText(getActivity(), "right", Toast.LENGTH_SHORT).show();
}
public void onSwipeLeft() {
Toast.makeText(getActivity(), "left", Toast.LENGTH_SHORT).show();
}
public void onSwipeBottom() {
Toast.makeText(getActivity(), "bottom", Toast.LENGTH_SHORT).show();
}
public void onClick(){
Toast.makeText(getActivity(), "clicked", Toast.LENGTH_SHORT).show();
}
});
Metoda @ Edwarda Brey'a działa świetnie. Jeśli ktoś chciałby również skopiować i wkleić importowane pliki OnSwipeTouchListener
, oto:
import android.content.Context;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
Mała modyfikacja odpowiedzi @Mirek Rusin, a teraz możesz wykryć przeciągnięcia wielodotykowe. Ten kod znajduje się na Kotlin:
class OnSwipeTouchListener(ctx: Context, val onGesture: (gestureCode: Int) -> Unit) : OnTouchListener {
private val SWIPE_THRESHOLD = 200
private val SWIPE_VELOCITY_THRESHOLD = 200
private val gestureDetector: GestureDetector
var fingersCount = 0
fun resetFingers() {
fingersCount = 0
}
init {
gestureDetector = GestureDetector(ctx, GestureListener())
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (event.pointerCount > fingersCount) {
fingersCount = event.pointerCount
}
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true
}
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
var result = false
try {
val diffY = e2.y - e1.y
val diffX = e2.x - e1.x
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
val gesture = when (fingersCount) {
1 -> Gesture.SWIPE_RIGHT
2 -> Gesture.TWO_FINGER_SWIPE_RIGHT
3 -> Gesture.THREE_FINGER_SWIPE_RIGHT
else -> -1
}
if (gesture > 0) {
onGesture.invoke(gesture)
}
} else {
val gesture = when (fingersCount) {
1 -> Gesture.SWIPE_LEFT
2 -> Gesture.TWO_FINGER_SWIPE_LEFT
3 -> Gesture.THREE_FINGER_SWIPE_LEFT
else -> -1
}
if (gesture > 0) {
onGesture.invoke(gesture)
}
}
resetFingers()
}
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
val gesture = when (fingersCount) {
1 -> Gesture.SWIPE_DOWN
2 -> Gesture.TWO_FINGER_SWIPE_DOWN
3 -> Gesture.THREE_FINGER_SWIPE_DOWN
else -> -1
}
if (gesture > 0) {
onGesture.invoke(gesture)
}
} else {
val gesture = when (fingersCount) {
1 -> Gesture.SWIPE_UP
2 -> Gesture.TWO_FINGER_SWIPE_UP
3 -> Gesture.THREE_FINGER_SWIPE_UP
else -> -1
}
if (gesture > 0) {
onGesture.invoke(gesture)
}
}
resetFingers()
}
result = true
} catch (exception: Exception) {
exception.printStackTrace()
}
return result
}
}}
Gdzie Gest.SWIPE_RIGHT i inne są unikatowymi wskaźnikami liczb całkowitych gestów, których używam do wykrywania rodzaju gestów w dalszej części mojej aktywności:
rootView?.setOnTouchListener(OnSwipeTouchListener(this, {
gesture -> log(Gesture.parseName(this, gesture))
}))
Widzicie więc, że gest jest zmienną całkowitą zawierającą wartość, którą wcześniej przekazałem.
Moje rozwiązanie jest podobne do powyższych, ale wyodrębniłem obsługę gestów do klasy abstrakcyjnej OnGestureRegisterListener.java
, która obejmuje gesty przeciągania , klikania i długiego kliknięcia .
OnGestureRegisterListener.java
public abstract class OnGestureRegisterListener implements View.OnTouchListener {
private final GestureDetector gestureDetector;
private View view;
public OnGestureRegisterListener(Context context) {
gestureDetector = new GestureDetector(context, new GestureListener());
}
@Override
public boolean onTouch(View view, MotionEvent event) {
this.view = view;
return gestureDetector.onTouchEvent(event);
}
public abstract void onSwipeRight(View view);
public abstract void onSwipeLeft(View view);
public abstract void onSwipeBottom(View view);
public abstract void onSwipeTop(View view);
public abstract void onClick(View view);
public abstract boolean onLongClick(View view);
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
onLongClick(view);
super.onLongPress(e);
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
onClick(view);
return super.onSingleTapUp(e);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight(view);
} else {
onSwipeLeft(view);
}
result = true;
}
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom(view);
} else {
onSwipeTop(view);
}
result = true;
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
}
I używaj go w ten sposób. Pamiętaj, że możesz łatwo przekazać swój View
parametr.
OnGestureRegisterListener onGestureRegisterListener = new OnGestureRegisterListener(this) {
public void onSwipeRight(View view) {
// Do something
}
public void onSwipeLeft(View view) {
// Do something
}
public void onSwipeBottom(View view) {
// Do something
}
public void onSwipeTop(View view) {
// Do something
}
public void onClick(View view) {
// Do something
}
public boolean onLongClick(View view) {
// Do something
return true;
}
};
Button button = findViewById(R.id.my_button);
button.setOnTouchListener(onGestureRegisterListener);
Robiłem podobne rzeczy, ale tylko dla przesunięć poziomych
import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
abstract class OnHorizontalSwipeListener(val context: Context) : View.OnTouchListener {
companion object {
const val SWIPE_MIN = 50
const val SWIPE_VELOCITY_MIN = 100
}
private val detector = GestureDetector(context, GestureListener())
override fun onTouch(view: View, event: MotionEvent) = detector.onTouchEvent(event)
abstract fun onRightSwipe()
abstract fun onLeftSwipe()
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent) = true
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float)
: Boolean {
val deltaY = e2.y - e1.y
val deltaX = e2.x - e1.x
if (Math.abs(deltaX) < Math.abs(deltaY)) return false
if (Math.abs(deltaX) < SWIPE_MIN
&& Math.abs(velocityX) < SWIPE_VELOCITY_MIN) return false
if (deltaX > 0) onRightSwipe() else onLeftSwipe()
return true
}
}
}
A potem można go użyć do wyświetlania komponentów
private fun listenHorizontalSwipe(view: View) {
view.setOnTouchListener(object : OnHorizontalSwipeListener(context!!) {
override fun onRightSwipe() {
Log.d(TAG, "Swipe right")
}
override fun onLeftSwipe() {
Log.d(TAG, "Swipe left")
}
}
)
}
To pytanie zostało zadane wiele lat temu. Teraz jest lepsze rozwiązanie: SmartSwipe: https://github.com/luckybilly/SmartSwipe
kod wygląda następująco:
SmartSwipe.wrap(contentView)
.addConsumer(new StayConsumer()) //contentView stay while swiping with StayConsumer
.enableAllDirections() //enable directions as needed
.addListener(new SimpleSwipeListener() {
@Override
public void onSwipeOpened(SmartSwipeWrapper wrapper, SwipeConsumer consumer, int direction) {
//direction:
// 1: left
// 2: right
// 4: top
// 8: bottom
}
})
;
@Mirek Rusin answeir jest bardzo dobry. Ale jest mały błąd i wymagana jest poprawka -
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
if (getOnSwipeListener() != null) {
getOnSwipeListener().onSwipeRight();
}
} else {
if (getOnSwipeListener() != null) {
getOnSwipeListener().onSwipeLeft();
}
}
result = true;
}
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
if (getOnSwipeListener() != null) {
getOnSwipeListener().onSwipeBottom();
}
} else {
if (getOnSwipeListener() != null) {
getOnSwipeListener().onSwipeTop();
}
}
result = true;
}
Co za różnica? Ustawiamy wynik = prawda, tylko jeśli sprawdziliśmy, czy wszystkie wymagania (zarówno SWIPE_THRESHOLD, jak i SWIPE_VELOCITY_THRESHOLD są w porządku). Jest to ważne, jeśli odrzucimy przesunięcie, jeśli niektóre wymagania nie zostaną osiągnięte, i musimy zrobić coś w metodzie onTouchEvent metody OnSwipeTouchListener!
Oto prosty kod Androida do wykrywania kierunku gestów
W MainActivity.java
i activity_main.xml
napisz następujący kod:
MainActivity.java
import java.util.ArrayList;
import android.app.Activity;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.gesture.GestureStroke;
import android.gesture.Prediction;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity implements
OnGesturePerformedListener {
GestureOverlayView gesture;
GestureLibrary lib;
ArrayList<Prediction> prediction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lib = GestureLibraries.fromRawResource(MainActivity.this,
R.id.gestureOverlayView1);
gesture = (GestureOverlayView) findViewById(R.id.gestureOverlayView1);
gesture.addOnGesturePerformedListener(this);
}
@Override
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
ArrayList<GestureStroke> strokeList = gesture.getStrokes();
// prediction = lib.recognize(gesture);
float f[] = strokeList.get(0).points;
String str = "";
if (f[0] < f[f.length - 2]) {
str = "Right gesture";
} else if (f[0] > f[f.length - 2]) {
str = "Left gesture";
} else {
str = "no direction";
}
Toast.makeText(getApplicationContext(), str, Toast.LENGTH_LONG).show();
}
}
Activity_main.xml
<android.gesture.GestureOverlayView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android1="http://schemas.android.com/apk/res/android"
xmlns:android2="http://schemas.android.com/apk/res/android"
android:id="@+id/gestureOverlayView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android1:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Draw gesture"
android:textAppearance="?android:attr/textAppearanceMedium" />
</android.gesture.GestureOverlayView>
import android.content.Context
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
/**
* Detects left and right swipes across a view.
*/
class OnSwipeTouchListener(context: Context, onSwipeCallBack: OnSwipeCallBack?) : OnTouchListener {
private var gestureDetector : GestureDetector
private var onSwipeCallBack: OnSwipeCallBack?=null
init {
gestureDetector = GestureDetector(context, GestureListener())
this.onSwipeCallBack = onSwipeCallBack!!
}
companion object {
private val SWIPE_DISTANCE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}
/* fun onSwipeLeft() {}
fun onSwipeRight() {}*/
override fun onTouch(v: View, event: MotionEvent): Boolean {
return gestureDetector.onTouchEvent(event)
}
private inner class GestureListener : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true
}
override fun onFling(eve1: MotionEvent?, eve2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
try {
if(eve1 != null&& eve2!= null) {
val distanceX = eve2?.x - eve1?.x
val distanceY = eve2?.y - eve1?.y
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (distanceX > 0)
onSwipeCallBack!!.onSwipeLeftCallback()
else
onSwipeCallBack!!.onSwipeRightCallback()
return true
}
}
}catch (exception:Exception){
exception.printStackTrace()
}
return false
}
}
}
Jeśli chcesz wyświetlać niektóre przyciski z akcjami po przesunięciu elementu listy, wiele bibliotek w Internecie ma takie zachowanie. Wdrożyłem bibliotekę, którą znalazłem w Internecie i jestem bardzo zadowolony. Jest bardzo prosty w użyciu i bardzo szybki. Poprawiłem oryginalną bibliotekę i dodałem nowy detektor kliknięć dla kliknięcia elementu. Dodałem również niesamowitą bibliotekę czcionek ( http://fortawesome.github.io/Font-Awesome/ ), a teraz możesz po prostu dodać nowy tytuł elementu i określić nazwę ikony z niesamowitej czcionki.
Oto link do github
public class TranslatorSwipeTouch implements OnTouchListener
{
private String TAG="TranslatorSwipeTouch";
@SuppressWarnings("deprecation")
private GestureDetector detector=new GestureDetector(new TranslatorGestureListener());
@Override
public boolean onTouch(View view, MotionEvent event)
{
return detector.onTouchEvent(event);
}
private class TranslatorGestureListener extends SimpleOnGestureListener
{
private final int GESTURE_THRESHOULD=100;
private final int GESTURE_VELOCITY_THRESHOULD=100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent event1,MotionEvent event2,float velocityx,float velocityy)
{
try
{
float diffx=event2.getX()-event1.getX();
float diffy=event2.getY()-event1.getY();
if(Math.abs(diffx)>Math.abs(diffy))
{
if(Math.abs(diffx)>GESTURE_THRESHOULD && Math.abs(velocityx)>GESTURE_VELOCITY_THRESHOULD)
{
if(diffx>0)
{
onSwipeRight();
}
else
{
onSwipeLeft();
}
}
}
else
{
if(Math.abs(diffy)>GESTURE_THRESHOULD && Math.abs(velocityy)>GESTURE_VELOCITY_THRESHOULD)
{
if(diffy>0)
{
onSwipeBottom();
}
else
{
onSwipeTop();
}
}
}
}
catch(Exception e)
{
Log.d(TAG, ""+e.getMessage());
}
return false;
}
public void onSwipeRight()
{
//Toast.makeText(this.getClass().get, "swipe right", Toast.LENGTH_SHORT).show();
Log.i(TAG, "Right");
}
public void onSwipeLeft()
{
Log.i(TAG, "Left");
//Toast.makeText(MyActivity.this, "swipe left", Toast.LENGTH_SHORT).show();
}
public void onSwipeTop()
{
Log.i(TAG, "Top");
//Toast.makeText(MyActivity.this, "swipe top", Toast.LENGTH_SHORT).show();
}
public void onSwipeBottom()
{
Log.i(TAG, "Bottom");
//Toast.makeText(MyActivity.this, "swipe bottom", Toast.LENGTH_SHORT).show();
}
}
}
wykorzystanie odpowiedzi Edwarda Breya w Kotlinie
view.setOnTouchListener(object: OnSwipeTouchListener(this) {
override fun onSwipeLeft() {
super.onSwipeLeft()
}
override fun onSwipeRight() {
super.onSwipeRight()
}
}
)