Android: วิธีจัดการรูปแบบการปัดนิ้วจากขวาไปซ้าย


442

ฉันต้องการให้แอปของฉันจดจำเมื่อผู้ใช้เลื่อนจากขวาไปซ้ายบนหน้าจอโทรศัพท์

ทำอย่างไร


1
ตรวจสอบลิงค์นี้stackoverflow.com/questions/937313/…
Falmarri

ดูคำตอบของฉันเกี่ยวกับวิธีเลื่อนขึ้น / ลง / ซ้าย / ขวารูปแบบลายเส้น stackoverflow.com/questions/13095494/ …
fernandohur

ตรวจสอบห้องสมุดของฉันที่อาจเป็นประโยชน์github.com/UdiOshi85/libSwipes
Udi Oshi

1
ตรวจสอบคำตอบที่ยอมรับใน Kotlin ที่นี่: stackoverflow.com/a/53791260/2201814
MHSFisher

คำตอบ:


840

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

การใช้งาน:

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

});

6
ใช้งานได้ดี แต่ super.onTouch (ดู, motionEvent); เตือนให้ฉันเกิดข้อผิดพลาดใน eclipse "ไม่ได้กำหนดไว้สำหรับวัตถุชนิด" การลบวิธีนี้ใช้งานได้ดี
Opiatefuchs

22
ขอบคุณทำงานเหมือนมีเสน่ห์ แต่คุณควรเพิ่มนวกรรมิกให้กับOnSwipeTouchListenerบริบทเพราะคอนสตรัคเตอร์GestureDetectorนั้นเลิกใช้มาตั้งแต่ API ระดับ 3 และอินสแตนซ์GestureDetectorในคอนสตรัคเตอร์นั้น
Hugo Alves

9
ขอบคุณมันใช้งานได้สำหรับฉันด้วยการปรับเปลี่ยนเหล่านี้: stackoverflow.com/a/19506010/401403
Arash

3
แต่จะไม่เรียกว่า "onDown" ด้วยเหตุนี้ e1 ของฉันจึงเป็นโมฆะและฉันไม่สามารถทำอะไรได้เลย
mangusta

3
การแก้ไขของฉันสำหรับคำตอบนี้คือการย้ายonTouchเข้ามาในOnSwipeTouchListenerความหมายเป็นอย่างอื่น IDE ของฉันจะปรากฏขึ้น "การเข้าถึงสมาชิกเอกชน" ข้อผิดพลาด
Ge ร่อง

199

รหัสนี้จะตรวจจับการปัดซ้ายและขวาหลีกเลี่ยงการเรียกใช้ API ที่เลิกใช้แล้วและมีการปรับปรุงอื่น ๆ เพิ่มเติมสำหรับคำตอบก่อนหน้านี้

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

ใช้แบบนี้:

view.setOnTouchListener(new OnSwipeTouchListener(context) {
    @Override
    public void onSwipeLeft() {
        // Whatever
    }
});

12
@Jona คุณจะต้องการหนังสือที่ดีหรือแหล่งข้อมูลอื่น ๆ บนพื้นฐาน Android อย่างแน่นอน ไม่เช่นนั้นการลองใช้ Cobble Solution ร่วมกันจาก StackOverflow จะทำให้คุณหงุดหงิด ตัวเลือกที่ดีอย่างเป็นทางการของการฝึกอบรมสำหรับนักพัฒนา Android ส่วนการเริ่มต้นกิจกรรมบอกเกี่ยวกับตำแหน่งที่คุณจะใส่setOnTouchListener(โดยทั่วไปอยู่ในonCreate) contextเป็นthisตัวชี้ (เว้นแต่ว่าคุณกำลังสร้างแฟรกเมนต์)
Edward Brey

3
@ Lara ฉันยังไม่ได้ลอง แต่คุณสามารถลองใช้SimpleOnGestureListener.onSingleTapConfirmedได้
Edward Brey

4
ขอบคุณเอ็ดเวิร์ด ฉันยังพบว่าการเปลี่ยนการกลับมาของ onDown จาก true เป็น false นั้นเป็นการหลอกลวง
Lara

2
@Signo กิจกรรมที่มีมุมมองให้บริบท Fragment.getActivity()ในกรณีที่พบบ่อยของการเพิ่มมุมมองเป็นส่วนที่ใช้
Edward Brey

2
@coderVishal ทั้งนี้ขึ้นอยู่กับวัตถุประสงค์ของคุณคุณอาจพบว่ามีประโยชน์SwipeRefreshLayoutที่SwipeRefreshLayoutBasicตัวอย่างหรือหนึ่งในตัวแปรของมัน
Edward Brey

49

หากคุณต้องการประมวลผลเหตุการณ์การคลิกที่นี่ด้วยการแก้ไขบางอย่าง:

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

และการใช้งานตัวอย่าง:

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

5
ฉันไม่เห็นการแก้ไขใน OnSwipeTouchListener ที่คุณแก้ไขได้อย่างง่ายดาย มันอยู่ที่ไหนกันแน่?
Nicolas Zozol

5
นี่ควรเป็นคำตอบที่ยอมรับได้ ... ความแตกต่างนั้นบอบบาง แต่สำคัญมาก ก่อนอื่นไม่มี onDown () ประการที่สองตัวจัดการคืนค่าบูลีนเพื่อส่งสัญญาณว่าพวกเขาใช้เหตุการณ์หรือไม่ นี่เป็นสิ่งสำคัญที่สุดหากคุณต้องการตัวจัดการมากกว่าหนึ่งตัวสำหรับมุมมองเดียวกัน (ซึ่งควรเป็นกรณีเริ่มต้น)
บอร์

toggleSomething () วิธีการคืออะไร?
ตุง

1
@tung เพียงแตะปกติ (ไม่ใช่ท่าทาง) ตัวจัดการ
ruX

@NicolasZozol สไตล์โค้ด Java, ทุกทิศทางกวาด, เมื่อคลิกตัวจัดการ
ruX

28

ขยายคำตอบของ Mirek สำหรับกรณีที่เมื่อคุณต้องการใช้ท่าทางการปัดนิ้วในมุมมองเลื่อน โดยค่าเริ่มต้นฟังแบบสัมผัสสำหรับมุมมองการเลื่อนถูกปิดใช้งานและการกระทำแบบเลื่อนจะไม่เกิดขึ้น ในการแก้ไขปัญหานี้คุณจะต้องแทนที่dispatchTouchEventเมธอดของActivityและส่งคืนเวอร์ชันที่สืบทอดของเมธอดนี้หลังจากคุณทำกับ listener ของคุณเอง

เพื่อที่จะทำการแก้ไขรหัสของ Mirek: ฉันเพิ่มทะเยอทะยานสำหรับ gestureDetectorOnSwipeTouchListenerใน

public GestureDetector getGestureDetector(){
    return  gestureDetector;
}

ประกาศ OnSwipeTouchListenerภายในกิจกรรมเป็นฟิลด์กว้างระดับ

OnSwipeTouchListener onSwipeTouchListener;

แก้ไขรหัสการใช้งานให้สอดคล้อง:

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

และแทนที่dispatchTouchEventวิธีการด้านในActivity :

@Override
    public boolean dispatchTouchEvent(MotionEvent ev){
        swipeListener.getGestureDetector().onTouchEvent(ev); 
            return super.dispatchTouchEvent(ev);   
    }

ตอนนี้ทั้งการดำเนินการเลื่อนและปัดจะทำงาน


ยักษ์ลบนี่ - ถ้าฉันทำท่าทางที่ใดก็ได้ใน scrollview ของฉัน touchListener เรียกว่าแม้ว่ามันจะไม่ได้นำไปใช้กับ scrollview ตัวเอง แต่กับปุ่มสุ่มอยู่ข้างใน
Starwave

23

เพื่อให้มีClick Listener, DoubleClick Listener, OnLongPress Listener, Swipe Left, Swipe Right, Swipe Up, Swipe Downเพียงครั้งเดียวที่คุณจำเป็นต้องView setOnTouchListenerกล่าวคือ

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

}

สำหรับนี้คุณต้องคลาสที่ใช้OnSwipeTouchListenerOnTouchListener

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() {

}
}

2
วิธีแก้ปัญหาของ Zala นั้นง่ายและชัดเจน วิธีนี้จะแก้ปัญหาผู้เริ่มต้นที่มีปัญหากับการเลื่อนนิ้ว
Jennifer

2
@ Jaydipsinh Zala คุณประหยัดเวลาของฉันน่าทึ่ง สิ่งนี้จะแก้ปัญหาตัวบ่งชี้การเลื่อนบนและล่างในขณะที่เลื่อน
TejaDroid

1
นี่คือสิ่งที่ฉันเรียกว่าคำตอบที่สมบูรณ์ เมื่อฉันเพิ่ม swipes ฉันสูญเสียคุณสมบัติการคลิกของฉันดังนั้นฉันจึงจำเป็นต้องแทนที่เมธอด onClick เช่นเดียวกับในคำตอบนี้ ขอบคุณมาก!
เร็ว ๆ นี้ Santos

@Jaydipsinh Zala ไม่แน่ใจว่าฉันทำอะไรผิดเมื่อฉันเพิ่ม OnSwipeTouchListener ใน webView ของฉันมันจะลบการโต้ตอบกับเว็บไซต์ภายใน webview คุณช่วยได้ไหม
AL̲̳I

11

คุณไม่ต้องการการคำนวณที่ซับซ้อน สามารถทำได้โดยใช้OnGestureListenerส่วนต่อประสานจากGestureDetectorชั้นเรียน

onFlingวิธีการภายในคุณสามารถตรวจจับทั้งสี่ทิศทางดังนี้:

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

การใช้งาน:

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

ร่อนผ่านขยะทั้งหมดที่นี่คุณพูดถูกไม่จำเป็นต้องทำสิ่งที่ยุ่งยากเกินไป - อันนี้ทำงานได้อย่างสมบูรณ์แบบ
Starwave

VELOCITY_THRESHOLD ควรขึ้นอยู่กับความหนาแน่นของหน้าจอหรือไม่
Gerrit Beuze

@GerritBeuze ไม่ระบบ Android จัดการสิ่งนั้น มันส่งค่าที่ถูกต้องผ่านvelocityXและvelocityYในonFlingวิธีการ แม้ว่าคุณจะสามารถทดสอบเพื่อดูว่าค่าใดเหมาะสมกับความต้องการของคุณมากที่สุด แต่หมายเลขสุดท้ายจะเป็นสากล
MDP

คำตอบที่นี่สมมติว่าตรงกันข้าม: พวกเขาไม่ได้ปรับขนาด? : stackoverflow.com/questions/18812479/…
Gerrit Beuze

@GerritBeuze เป็นเพราะพวกเขากำลังทำการคำนวณทางคณิตศาสตร์ด้วยตัวเองโดยการคำนวณจำนวนพิกเซลที่นิ้วมือเดินทางและนั่นก็ผิดเพราะมันขึ้นอยู่กับความหนาแน่นของพิกเซล คุณควรใช้ความเร็วแบบเดียวกับที่ฉันทำความเร็วเป็นเกือบ dpi อิสระ
MDP


10

รุ่น Kotlin ของ @Mirek Rusin อยู่ที่นี่:

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

การใช้งาน:

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คำหลักคือจุดสำหรับฉัน ...


9

หากต้องการเพิ่ม onClick เช่นกันนี่คือสิ่งที่ฉันทำ

....
// 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

ฉันใช้แฟรกเมนต์ดังนั้นใช้ getActivity () สำหรับบริบท นี่คือวิธีที่ฉันใช้มัน - และมันใช้งานได้


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

5

วิธีการ @Edward Brey ใช้งานได้ดี หากใครบางคนต้องการที่จะคัดลอกและวางการนำเข้าสำหรับที่OnSwipeTouchListenerนี่พวกเขาคือ:

 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;

3

การแก้ไขเล็กน้อยของคำตอบ @Mirek Rusin และตอนนี้คุณสามารถตรวจจับ swipes แบบมัลติทัชได้แล้ว รหัสนี้อยู่บน 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
    }
}}

ที่ Gesture.SWIPE_RIGHT และอื่น ๆ เป็นตัวระบุจำนวนเต็มเฉพาะของท่าทางที่ฉันใช้เพื่อตรวจจับท่าทางในภายหลังในกิจกรรมของฉัน:

rootView?.setOnTouchListener(OnSwipeTouchListener(this, {
    gesture -> log(Gesture.parseName(this, gesture))
}))

ดังนั้นคุณจะเห็นท่าทางที่นี่เป็นตัวแปรจำนวนเต็มที่เก็บค่าที่ฉันได้ผ่านมาก่อน


ใครช่วยกรุณายกตัวอย่างให้ฉันดูวิธีใช้ Kotlin เพื่อตรวจจับการกวาดนิ้วซ้ายและคลิกปกติบนมุมมองเดียวกัน
user3561494

คุณใช้สิ่งนี้ในมุมมองรายการอย่างไร มันไม่ส่งคืนตำแหน่งของมุมมองที่ได้รับการสัมผัสดังนั้นคุณจะรู้ได้อย่างไรว่าแถวไหนถูกแตะ
user3561494

ท่าทางมาจากสิ่งที่นำเข้า นำเข้า android.gesture.Gesture ไม่มี SWIPE_RIGHT ทั่วโลก
JPM

ทำไมคุณไม่ได้เขียนรหัสที่สมบูรณ์ของท่าทางนี้ซึ่งจะวาง SwipeDown, ซ้าย, ขวา ฯลฯ
Anonymous-E

3

วิธีการแก้ปัญหาของฉันคือคล้ายกับที่ดังกล่าวข้างต้น แต่ฉันได้ใจลอยจัดการลงในระดับนามธรรมท่าทางOnGestureRegisterListener.javaซึ่งรวมถึงการรูด , คลิกและคลิกที่ยาวท่าทาง

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

    }
}

และใช้มันอย่างนั้น โปรดทราบว่าคุณสามารถส่งผ่านViewพารามิเตอร์ของคุณได้อย่างง่ายดาย

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

3

ฉันได้ทำสิ่งที่คล้ายกัน แต่สำหรับ swipes แนวนอนเท่านั้น

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

และจากนั้นมันสามารถใช้สำหรับส่วนประกอบมุมมอง

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")
            }

        }
    )
}

3

คำถามนี้ถูกถามเมื่อหลายปีก่อน ตอนนี้มีทางออกที่ดีกว่า: SmartSwipe: https://github.com/luckybilly/SmartSwipe

รหัสดูเหมือนว่านี้:

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

มี SwipeConsumers มากมายสำหรับเอฟเฟกต์ด้านข้างที่แตกต่างกันเช่น SlidingConsumer / StretchConsumer / SpaceConsumer / ... และอื่น ๆ ภายในSmartSwipe
luckybilly

1

@Mirek Rusin ตอบเป็นสิ่งที่ดีมาก แต่มีข้อผิดพลาดเล็ก ๆ น้อย ๆ และการแก้ไขจะต้อง -

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

ความแตกต่างคืออะไร? เราตั้งค่า result = true เฉพาะเมื่อเราตรวจสอบแล้วว่าข้อกำหนดทั้งหมด (ทั้ง SWIPE_THRESHOLD และ SWIPE_VELOCITY_THRESHOLD เป็น Ok) นี่เป็นสิ่งสำคัญหากเรายกเลิกการปัดหากการร้องขอบางอย่างไม่สำเร็จและเราต้องทำ smth ในวิธี onTouchEvent ของ OnSwipeTouchListener!


1

นี่คือรหัส Android ที่ง่ายสำหรับการตรวจจับทิศทางท่าทาง

ในMainActivity.javaและactivity_main.xmlเขียนรหัสต่อไปนี้:

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>

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


    }
}

สำหรับ Kotlin คุณสามารถใช้สิ่งนี้:
kamal

การใช้งาน: gv_calendar !!. setOnTouchListener (OnSwipeTouchListener (กิจกรรม, onSwipeCallBack !!))
kamal

5
โปรดอย่าเพิ่งถ่ายโอนรหัสรวมคำอธิบายว่ารหัสของคุณทำอะไร
Mark Rotteveel

OnSwipeCallBack คืออะไร
toshkinl

0

หากคุณต้องการที่จะแสดงปุ่มบางอย่างที่มีการกระทำเมื่อรายการเป็นรายการที่รูดเป็นจำนวนมากของห้องสมุดบนอินเทอร์เน็ตที่มีพฤติกรรมนี้ ฉันใช้งานห้องสมุดที่ฉันพบบนอินเทอร์เน็ตและฉันพอใจมาก มันใช้งานง่ายและรวดเร็วมาก ฉันปรับปรุงไลบรารีดั้งเดิมและฉันเพิ่ม listener การคลิกใหม่สำหรับการคลิกไอเท็ม นอกจากนี้ฉันได้เพิ่มห้องสมุดที่ยอดเยี่ยมแบบอักษร ( http://fortawesome.github.io/Font-Awesome/ ) และตอนนี้คุณสามารถเพิ่มชื่อรายการใหม่และระบุชื่อไอคอนจากแบบอักษรที่ยอดเยี่ยม

นี่คือลิงค์ GitHub


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

  }

 }

2
โค้ดจำนวนมากต้องการคำอธิบายเพื่อให้คุณค่าแก่ผู้อ่าน รหัสเฉพาะที่ไม่แสดงคำเตือน คุณต้องอธิบายว่าทำไมรหัสนั้นมีความสำคัญอย่างยิ่งในกรณีเช่นนี้
สเตฟาน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.