Android : 오른쪽에서 왼쪽으로 스 와이프 동작을 처리하는 방법


442

휴대 전화 화면에서 사용자가 오른쪽에서 왼쪽으로 스 와이프하면 앱에서 인식하도록하고 싶습니다.

이것을하는 방법?


1
이 링크를 확인하십시오 stackoverflow.com/questions/937313/…
Falmarri

내 대답을 참조하는 방법을 상 / 하 / 좌 / 우 스 와이프 동작에 stackoverflow.com/questions/13095494/...
fernandohur

도움이 될 수 내 라이브러리 확인 github.com/UdiOshi85/libSwipes
우디 Oshi

1
여기 코 틀린에 허용 대답을 확인합니다 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 (view, motionEvent); 이클립스에서 "유형 객체에 대해 정의되지 않았습니다"라는 오류 경고가 표시됩니다. 이것을 삭제하면 효과적입니다.
Opiatefuchs

22
고마워는 매력처럼 작동하지만 API 레벨 3부터 OnSwipeTouchListener해당 생성자 GestureDetector가 더 이상 사용되지 않으므로 해당 생성자를 사용 하여 컨텍스트를 수신 하는 생성자를 추가해야합니다 GestureDetector.
Hugo Alves

9
고맙습니다.이 수정으로 나를 위해 일했습니다 : stackoverflow.com/a/19506010/401403
Arash

3
"onDown"은 호출되지 않습니다. 결과적으로 내 e1은 항상 null이며 아무것도 할 수 없습니다.
mangusta

3
이 답변에 대한 내 수정 onTouchOnSwipeTouchListener정의 로 이동 하는 것입니다. 그렇지 않으면 내 IDE에 "개인 멤버 액세스"오류가 표시됩니다.
Ge Rong

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 당신은 확실히 안드로이드 기초에 관한 좋은 책이나 다른 자료를 원할 것입니다; 그렇지 않으면 StackOverflow에서 솔루션을 함께 모 으려고 시도하면 실망 스러울 것입니다. 좋은 옵션은 안드로이드 개발자를위한 공식 교육입니다 . 활동 시작하기 섹션 은 어디에 넣을 것인지에 대해 알려줍니다 setOnTouchListener(일반적으로 onCreate). context는 IS 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 ()이 없습니다. 둘째, 처리기는 부울을 반환하여 이벤트 사용 여부를 알립니다. 동일한 뷰에 대해 둘 이상의 핸들러가 필요한 경우 (기본 경우 여야 함) 가장 중요합니다.
Gábor

그 toggleSomething () 메소드는 무엇입니까?
tung

1
@tung 그냥 일반 탭 (제스처가 아님) 핸들러
ruX

@NicolasZozol 자바 코드 스타일, 모든 스 와이프 방향, 클릭 핸들러
ruX

28

스크롤보기 내에서 스 와이프 제스처를 사용하려는 경우 Mirek의 답변을 확장합니다. 기본적으로 스크롤보기의 터치 리스너는 비활성화되어 스크롤 동작이 발생하지 않습니다. 이 문제를 해결하려면 자신의 리스너로 작업을 마친 후의 dispatchTouchEvent메소드 를 재정의 Activity하고이 메소드의 상속 된 버전을 리턴해야합니다.

Mirek의 코드를 약간 수정하기 위해 :에 대한 getter를 추가 gestureDetector합니다 OnSwipeTouchListener.

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

이제 스크롤 및 스 와이프 동작이 모두 작동합니다.


여기 마이너스 마이너스-스크롤보기의 어느 곳에서나 제스처를 수행하면 터치 뷰가 스크롤보기 자체에 적용되지 않았지만 그 안에있는 임의의 버튼에도 터치 리스너가 호출됩니다.
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.
            }
        });

}

이를 위해서는 OnSwipeTouchListener구현하는 클래스가 필요 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() {

}
}

2
Zala의 솔루션은 간단하고 명확하며 Android의 스 와이프 작업에 크게 도움이되었습니다. 이 솔루션은 스 와이프 제스처에 문제가있는 초보자를 해결합니다.
제니퍼

2
@Jaydipsinh Zala, 당신은 놀라운 시간을 절약합니다. 이것은 스크롤하는 동안 스크롤 상단 및 하단 표시기 문제를 해결합니다.
TejaDroid

1
이것이 내가 완전한 답이라고 부르는 것입니다. 스 와이프를 추가하면 클릭 속성이 손실되므로이 답변과 같이 onClick 메소드를 재정의해야했습니다. 고마워요!
곧 산토스

@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

@Mirek Rusin의 Kotlin 버전은 다음과 같습니다.

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

Fragments를 사용하고 있으므로 컨텍스트에 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 답변의 약간의 수정으로 이제 멀티 터치 스 와이프를 감지 할 수 있습니다. 이 코드는 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

제스처는 어떤 수입품에서 비롯된 것입니까? import android.gesture.Gesture에 SWIPE_RIGHT 전역이 없습니다.
JPM

왜 SwipeDown, left, right 등을 넣을지이 제스처의 완전한 코드를 작성하지 않은 이유는 무엇입니까?
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

나는 비슷한 일을 해왔지만 수평 스 와이프에만 해당

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


1

@Mirek Rusin answeir는 매우 좋습니다. 그러나 작은 버그가 있으며 수정이 필요합니다.

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

차이점은 무엇입니까? 모든 requirinments (SWIPE_THRESHOLD 및 SWIPE_VELOCITY_THRESHOLD가 모두 Ok인지 확인)를 확인한 경우에만 result = true로 설정합니다. requrinments 중 일부가 달성되지 않은 경우 스 와이프를 삭제하면 OnSwipeTouchListener의 onTouchEvent 메소드에서 smth를 수행해야합니다!


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 (activity, onSwipeCallBack !!))
kamal

5
코드를 덤프하지 말고 코드의 기능에 대한 설명을 포함하십시오.
Mark Rotteveel 2016 년

OnSwipeCallBack은 무엇입니까?
toshkinl

0

목록 항목을 스 와이프 할 때 동작이있는 일부 단추를 표시하려면 인터넷에이 동작이있는 많은 라이브러리가 있습니다. 인터넷에서 찾은 라이브러리를 구현했으며 매우 만족합니다. 사용이 매우 간단하고 빠릅니다. 원래 라이브러리를 개선하고 항목 클릭을위한 새로운 클릭 리스너를 추가했습니다. 또한 글꼴 멋진 라이브러리 ( 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
많은 양의 코드는 독자에게 가치를 부여하기 위해 실제로 설명이 필요합니다. 특히 사용 중단 경고를 표시하지 않는 코드입니다. 그러한 경우 그 코드가 절대적으로 필요한 이유를 실제로 설명해야합니다.
Stefan

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.