728x90
안드로이드 앱을 개발하다 보면 사용자 터치에 반응하는 정교한 기능을 구현해야 할 때가 많습니다.
단순히 한 번 탭하는 것을 넘어, 더블 탭, 길게 누르기, 스크롤, 빠르게 스와이프(플링)와 같은 다양한 제스처를 인식해야 하는 경우가 그렇죠. View의 기본적인 onTouchEvent() 메소드만으로는 이런 복합적인 제스처를 직접 구현하기가 상당히 복잡합니다.
이럴 때 안드로이드에서 제공하는 GestureDetector 클래스가 큰 도움을 줍니다. GestureDetector는 사용자 정의 리스너를 통해 일반적인 터치 이벤트를 해석하고, 미리 정의된 제스처들을 감지하여 콜백 메소드를 호출해 줍니다. 이번 포스팅에서는 GestureDetector를 사용하여 간단한 뷰에서 다양한 터치 제스처를 감지하는 방법을 MainActivity.java와 activity_main.xml 두 파일만을 사용하여 구현해 보겠습니다.
전체 코드입니다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="20dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/gesture_output_text_view"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#E0E0E0"
android:gravity="center"
android:text="여기를 터치하여 제스처를 인식해보세요!"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@android:color/black" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TextView gestureOutputTextView;
private GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gestureOutputTextView = findViewById(R.id.gesture_output_text_view);
// 1. GestureDetector 인스턴스 생성
// GestureDetector.SimpleOnGestureListener는 OnGestureListener와 OnDoubleTapListener를
// 모두 구현한 추상 클래스로, 필요한 메소드만 오버라이드할 수 있어 편리합니다.
gestureDetector = new GestureDetector(this, new MyGestureListener());
// 2. TextView에 터치 리스너 설정
gestureOutputTextView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// MotionEvent를 GestureDetector로 전달
return gestureDetector.onTouchEvent(event);
}
});
// 중요: setOnTouchListener에서 true를 반환해야 해당 뷰에서 터치 이벤트를 계속 처리합니다.
// false를 반환하면 터치 이벤트가 다른 뷰나 부모 뷰로 전달됩니다.
}
// 3. GestureDetector.OnGestureListener 구현 클래스
// GestureDetector.SimpleOnGestureListener를 상속받아 필요한 메소드만 오버라이드합니다.
private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100; // 스와이프 최소 거리
private static final int SWIPE_VELOCITY_THRESHOLD = 100; // 스와이프 최소 속도
@Override
public boolean onDown(MotionEvent e) {
// 터치 다운 이벤트 발생 시 호출 (모든 제스처의 시작)
gestureOutputTextView.setText("터치 다운: " + e.getX() + ", " + e.getY());
return true; // true를 반환해야 다음 제스처 이벤트를 받을 수 있습니다.
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// 한 번 탭하고 손가락을 떼는 순간 호출
gestureOutputTextView.setText("한 번 탭 감지!");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
// 길게 누르기 감지 (짧은 지연 후 호출)
gestureOutputTextView.setText("길게 누르기 감지!");
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 스크롤 감지 (터치 후 드래그 시 계속 호출)
// e1: 첫 번째 터치 다운 이벤트
// e2: 현재 터치 이동 이벤트
// distanceX, distanceY: 마지막 이벤트 이후 X, Y축으로 이동한 거리
gestureOutputTextView.setText(String.format("스크롤 중... (dx: %.1f, dy: %.1f)", distanceX, distanceY));
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// 빠르게 스크롤(플링) 감지 (손가락을 떼면서 빠른 속도로 이동했을 때 호출)
// velocityX, velocityY: X, Y축 이동 속도 (픽셀/초)
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) {
gestureOutputTextView.setText("오른쪽으로 플링!");
} else {
gestureOutputTextView.setText("왼쪽으로 플링!");
}
result = true;
}
} else { // 상하 스와이프
if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
gestureOutputTextView.setText("아래쪽으로 플링!");
} else {
gestureOutputTextView.setText("위쪽으로 플링!");
}
result = true;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
}
시연 영상입니다.
'안드로이드 자바' 카테고리의 다른 글
| [Java][Android] Shared Element Transition 사용하여 화면전환 (2) | 2025.07.21 |
|---|---|
| [Java][Android] AnimationDrawable 로 간단한 프레임 애니메이션 만들기 (1) | 2025.07.20 |
| [Java][Android] RXJava 사용하기 (0) | 2025.07.13 |
| [Java][Android] PackageManager 사용해서 앱 정보 가져오기 (0) | 2025.07.07 |
| [Java][Android] AssetManager를 활용하여 앱 내 에셋 파일에 접근하기 (0) | 2025.07.01 |