Android uses event listeners to handle user interactions. The common pattern is to set a listener on a view.
// Lambda syntax (Kotlin)
val button: Button = findViewById(R.id.myButton)
button.setOnClickListener {
Toast.makeText(this, "Button clicked!", Toast.LENGTH_SHORT).show()
}
// Anonymous inner class
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
// Handle click
}
})
// Activity implements listener
class MainActivity : AppCompatActivity(), View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
findViewById<Button>(R.id.myButton).setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.myButton -> handleButtonClick()
}
}
}
// Set touch listener on a view
view.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
println("Touch down at (${event.x}, ${event.y})")
true
}
MotionEvent.ACTION_MOVE -> {
println("Moving at (${event.x}, ${event.y})")
true
}
MotionEvent.ACTION_UP -> {
println("Touch up")
true
}
else -> false
}
}
// Custom View with touch handling
class DrawingView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
private val path = Path()
private val paint = Paint().apply {
color = Color.BLACK
strokeWidth = 8f
style = Paint.Style.STROKE
strokeCap = Paint.Cap.ROUND
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> path.moveTo(event.x, event.y)
MotionEvent.ACTION_MOVE -> path.lineTo(event.x, event.y)
else -> return false
}
invalidate() // Redraw
return true
}
override fun onDraw(canvas: Canvas) {
canvas.drawPath(path, paint)
}
}
class GestureActivity : AppCompatActivity() {
private lateinit var gestureDetector: GestureDetectorCompat
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
gestureDetector = GestureDetectorCompat(this, GestureListener())
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event)
}
inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onFling(
e1: MotionEvent?, e2: MotionEvent?,
velocityX: Float, velocityY: Float
): Boolean {
val dx = e2?.x?.minus(e1?.x ?: 0f) ?: 0f
if (Math.abs(dx) > 100 && Math.abs(velocityX) > 200) {
if (dx > 0) {
Toast.makeText(this@GestureActivity, "Swiped Right", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this@GestureActivity, "Swiped Left", Toast.LENGTH_SHORT).show()
}
return true
}
return false
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
Toast.makeText(this@GestureActivity, "Double Tap", Toast.LENGTH_SHORT).show()
return true
}
}
}
// Show keyboard
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
// Hide keyboard
imm.hideSoftInputFromWindow(currentFocus?.windowToken, 0)
// Handle keyboard enter action
editText.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
handleSearch(editText.text.toString())
true
} else false
}
// Listen for focus changes
editText.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
// EditText gained focus
} else {
// EditText lost focus
}
}
// Start drag
imageView.setOnLongClickListener { v ->
val data = ClipData.newPlainText("image", "dragged_image")
v.startDragAndDrop(data, View.DragShadowBuilder(v), null, 0)
true
}
// Receive drop
targetView.setOnDragListener { v, event ->
when (event.action) {
DragEvent.ACTION_DRAG_STARTED -> {
v.alpha = 0.5f
true
}
DragEvent.ACTION_DROP -> {
v.alpha = 1.0f
// Handle drop
Toast.makeText(context, "Item dropped!", Toast.LENGTH_SHORT).show()
true
}
DragEvent.ACTION_DRAG_ENDED -> {
v.alpha = 1.0f
true
}
else -> true
}
}