Bird
Raised Fist0
Android Kotlinmobile~20 mins

Gesture handling in Android Kotlin - Mini App: Build & Ship

Choose your learning style10 modes available
Build: GestureDemoScreen
This screen detects taps and swipes on a colored box and shows the gesture type below it.
Target UI
┌─────────────────────────────┐
│        Gesture Demo         │
├─────────────────────────────┤
│                             │
│       [ Colored Box ]        │
│                             │
│                             │
│  Gesture detected: None     │
│                             │
└─────────────────────────────┘
Display a colored box in the center of the screen.
Detect tap gestures on the box and update text below to 'Tap detected'.
Detect swipe gestures (left or right) on the box and update text to 'Swipe Left' or 'Swipe Right'.
Use Android GestureDetector for gesture detection.
Text below the box shows the last detected gesture or 'None' initially.
Starter Code
Android Kotlin
import android.os.Bundle
import android.view.GestureDetector
import android.view.MotionEvent
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout

class GestureDemoScreen : AppCompatActivity() {
    private lateinit var gestureDetector: GestureDetector
    private lateinit var gestureTextView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_gesture_demo)

        gestureTextView = findViewById(R.id.gestureTextView)
        val coloredBox = findViewById<ConstraintLayout>(R.id.coloredBox)

        // TODO: Initialize gestureDetector with a GestureListener
        // TODO: Set touch listener on coloredBox to pass events to gestureDetector
    }
}
Task 1
Task 2
Task 3
Task 4
Solution
Android Kotlin
import android.os.Bundle
import android.view.GestureDetector
import android.view.MotionEvent
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout

class GestureDemoScreen : AppCompatActivity() {
    private lateinit var gestureDetector: GestureDetector
    private lateinit var gestureTextView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_gesture_demo)

        gestureTextView = findViewById(R.id.gestureTextView)
        val coloredBox = findViewById<ConstraintLayout>(R.id.coloredBox)

        gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
                gestureTextView.text = "Tap detected"
                return true
            }

            override fun onFling(
                e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float
            ): Boolean {
                if (e1 == null || e2 == null) return false
                val deltaX = e2.x - e1.x
                if (Math.abs(deltaX) > 100 && Math.abs(velocityX) > 100) {
                    if (deltaX > 0) {
                        gestureTextView.text = "Swipe Right"
                    } else {
                        gestureTextView.text = "Swipe Left"
                    }
                    return true
                }
                return false
            }
        })

        coloredBox.setOnTouchListener { _, event ->
            gestureDetector.onTouchEvent(event)
            true
        }
    }
}

We created a GestureDetector with a listener that detects taps and swipes. The onSingleTapConfirmed method updates the text to "Tap detected" when the user taps the box. The onFling method detects horizontal swipes by checking the difference in X coordinates and velocity, then updates the text to "Swipe Left" or "Swipe Right" accordingly. The colored box forwards all touch events to the gesture detector by setting an onTouchListener. This way, the app responds to user gestures on the box and shows the detected gesture below it.

Final Result
Completed Screen
┌─────────────────────────────┐
│        Gesture Demo         │
├─────────────────────────────┤
│                             │
│       [ Colored Box ]        │
│                             │
│                             │
│  Gesture detected: Tap detected  │
│                             │
└─────────────────────────────┘
When user taps the colored box, the text below changes to 'Tap detected'.
When user swipes left on the box, the text changes to 'Swipe Left'.
When user swipes right on the box, the text changes to 'Swipe Right'.
Stretch Goal
Add detection for long press gesture and update the text to 'Long press detected'.
💡 Hint
Override the onLongPress method in GestureDetector.SimpleOnGestureListener and update the TextView text.

Practice

(1/5)
1. What is the primary purpose of using GestureDetector in Android Kotlin apps?
easy
A. To detect user gestures like taps and swipes on a view
B. To create animations for UI components
C. To manage app navigation between screens
D. To handle database operations asynchronously

Solution

  1. Step 1: Understand GestureDetector role

    GestureDetector is designed to listen for user touch gestures such as taps, swipes, and long presses on views.
  2. Step 2: Compare other options

    Options A, B, and D relate to navigation, animations, and database tasks, which are unrelated to gesture detection.
  3. Final Answer:

    To detect user gestures like taps and swipes on a view -> Option A
  4. Quick Check:

    GestureDetector = Detect gestures [OK]
Hint: GestureDetector listens for touch gestures on views [OK]
Common Mistakes:
  • Confusing GestureDetector with animation tools
  • Thinking GestureDetector manages navigation
  • Assuming GestureDetector handles data tasks
2. Which of the following is the correct way to create a GestureDetector with a simple gesture listener in Kotlin?
easy
A. val detector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {})
B. val detector = GestureDetector(object : GestureDetector.SimpleOnGestureListener() {}, this)
C. val detector = GestureDetector(this, GestureListener())
D. val detector = GestureDetector.SimpleOnGestureListener(this)

Solution

  1. Step 1: Check GestureDetector constructor syntax

    The constructor takes a Context (usually 'this') and a GestureDetector.OnGestureListener implementation, often an anonymous object of SimpleOnGestureListener.
  2. Step 2: Validate options

    val detector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {}) matches the correct syntax. val detector = GestureDetector(object : GestureDetector.SimpleOnGestureListener() {}, this) reverses parameters. val detector = GestureDetector(this, GestureListener()) uses an undefined class. val detector = GestureDetector.SimpleOnGestureListener(this) incorrectly calls SimpleOnGestureListener as a constructor.
  3. Final Answer:

    val detector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {}) -> Option A
  4. Quick Check:

    Context first, listener second in GestureDetector constructor [OK]
Hint: Context is first, listener second in GestureDetector constructor [OK]
Common Mistakes:
  • Swapping constructor parameters order
  • Using undefined listener classes
  • Calling listener as a constructor
3. Given this Kotlin code snippet inside an Activity:
val detector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
  override fun onSingleTapUp(e: MotionEvent?): Boolean {
    println("Tapped")
    return true
  }
})

view.setOnTouchListener { _, event ->
  detector.onTouchEvent(event)
  true
}
What will happen when the user taps on the view?
medium
A. The view ignores the tap and does not respond
B. Nothing happens because onSingleTapUp is not called
C. The message "Tapped" is printed to the console
D. The app crashes due to missing return statement

Solution

  1. Step 1: Understand onSingleTapUp override

    The overridden method prints "Tapped" and returns true, indicating the tap gesture was handled.
  2. Step 2: Check touch listener behavior

    The touch listener passes events to the detector, which triggers onSingleTapUp on tap, so "Tapped" is printed.
  3. Final Answer:

    The message "Tapped" is printed to the console -> Option C
  4. Quick Check:

    onSingleTapUp triggers print on tap [OK]
Hint: onSingleTapUp prints message when tap detected [OK]
Common Mistakes:
  • Assuming onSingleTapUp is never called
  • Forgetting to return true to handle gesture
  • Ignoring event forwarding to GestureDetector
4. What is wrong with this Kotlin code snippet for gesture detection?
val detector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
  override fun onLongPress(e: MotionEvent?) {
    println("Long press detected")
  }
})

view.setOnTouchListener { _, event ->
  detector.onTouchEvent(event)
}
medium
A. MotionEvent parameter cannot be nullable
B. onLongPress must return a Boolean
C. GestureDetector requires a separate listener for long press
D. The onTouchListener does not return a Boolean value

Solution

  1. Step 1: Check onTouchListener return type

    onTouchListener must return a Boolean indicating if the event was handled. This code lacks a return statement.
  2. Step 2: Validate other parts

    onLongPress returns void (Unit) correctly. GestureDetector supports long press in the same listener. MotionEvent can be nullable.
  3. Final Answer:

    The onTouchListener does not return a Boolean value -> Option D
  4. Quick Check:

    onTouchListener must return Boolean [OK]
Hint: Always return Boolean from onTouchListener [OK]
Common Mistakes:
  • Forgetting to return true or false in onTouchListener
  • Expecting onLongPress to return Boolean
  • Misunderstanding nullable MotionEvent
5. You want to detect both single taps and double taps on a view using GestureDetector in Kotlin. Which approach correctly handles both gestures without conflict?
hard
A. Use two separate GestureDetectors, one for single tap and one for double tap, attached to the same view
B. Use GestureDetector with a GestureDetector.OnDoubleTapListener and override both onSingleTapConfirmed and onDoubleTap methods
C. Override only onSingleTapUp and ignore double taps to avoid conflicts
D. Use onTouchListener to manually count taps and ignore GestureDetector

Solution

  1. Step 1: Understand GestureDetector double tap support

    GestureDetector supports double tap detection via OnDoubleTapListener interface, which includes onSingleTapConfirmed and onDoubleTap methods.
  2. Step 2: Evaluate options for handling both taps

    Use GestureDetector with a GestureDetector.OnDoubleTapListener and override both onSingleTapConfirmed and onDoubleTap methods correctly uses OnDoubleTapListener to distinguish single and double taps. Use two separate GestureDetectors, one for single tap and one for double tap, attached to the same view causes conflicts with multiple detectors. Override only onSingleTapUp and ignore double taps to avoid conflicts ignores double taps. Use onTouchListener to manually count taps and ignore GestureDetector is manual and error-prone.
  3. Final Answer:

    Use GestureDetector with a GestureDetector.OnDoubleTapListener and override both onSingleTapConfirmed and onDoubleTap methods -> Option B
  4. Quick Check:

    OnDoubleTapListener handles single and double taps [OK]
Hint: Use OnDoubleTapListener to handle single and double taps [OK]
Common Mistakes:
  • Using multiple GestureDetectors on one view
  • Ignoring double tap detection
  • Manually counting taps instead of using listener
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard