[UI] Context Menu 사용법
View를 롱 터치하면 컨텍스트 메뉴가 생성되고 View근처에 뜨게 된다.
컨텍스트 메뉴를 사용하기 위해 View.onCreateContextMenuListener인터페이스를 구현( onCreateContextMenu메서드)
뷰에 setOnCreateContextMenuListener(구현객체)로 등록
롱 터치시 구현객체의 onCreateContextMenu메서드가 호출되어 컨텍스트 메뉴가 호출된다.
Activity의 onContextItemSelected를 오버라이딩 ( 컨텍스트 메뉴의 메뉴아이템이 선택되면 호출된다 )
1. 관련된 View의 메서드들과 인터페이스
- setOnCreateContextMenuListener
setOnClickListener를 통해 리스너를 등록하고 뷰가 클릭이 되면
View.OnClickListener구현객체의 onClick에 구현해놓은 내용이 호출되었다.
마찬가지로 setOnCreateContextMenuListener도 뷰가 롱 터치되면
View.OnCreateContextMenuListener구현객체의 onCreateContextMenu가 호출되어 컨텍스트 메뉴를 생성한다.
- View.OnCreateContextMenuListener 인터페이스의 onCreateContextMenu메서드
뷰에 컨텍스트메뉴 리스너를 설정하고 롱터치가 발생하면 onCreateContextMenu메서드가 호출되는데
여기서 적절한 컨텍스트 메뉴를 생성해주면 된다.
abstract fun onCreateContextMenu( menu: ContextMenu!, v: View!, menuInfo: ContextMenu.ContextMenuInfo! ): Unit menu- 현재 만들어질 컨텍스트 메뉴
v- 어떤 뷰를 위해 컨텍스트 메뉴를 생성하고 있는지( 롱 터치된 뷰)
menuInfo- 컨텍스트 메뉴의 메뉴 아이템 추가 정보. v에 따라 다르다.
onCreateContextMenu{
//뷰에 따라 생성해야할 컨텍스트 메뉴가 다르다면
if(뷰1){
//메뉴1.xml 인플레이션
}
if(뷰2){
//메뉴2.xml 인플레이션
}
}
Activity또한 View.OnCreateContextMenuListener를 구현했기 떄문에
Activity에서 onCreateContextMenu메서드를 오버라이딩한후
뷰.setOnCreateContextMenuListener( this //액티비티) 로 사용할 수 있다.
2. 관련된 Activity의 메서드들
- onCreateContextMenu 메서드(롱 터치시 onCreateContextMenu를 통해 컨텍스트 메뉴가 만들어지고 화면 출력됨)
Activity는 View.OnCreateContextMenuListener를 구현하고 있다.
다음과 같은 방식으로 View에 컨텍스트 메뉴 리스너를 등록할 수 있다.
MainActivity
//MainActivity
//리스너 메서드 구현
override fun onCreateContextMenu(...){}
onStart메서드 {
뷰1.setOnCreateContextListener(this)
뷰2.setOnCreateContextListener(this)
}
onStop메서드{
뷰1.setOnCreateContextListener(null)
뷰2.setOnCreateContextListener(null)
}
뷰1, 뷰2는 이제 롱 클릭이 되면 액티비티에 구현된 onCreateContextMenu가 호출되어 컨텍스트 메뉴가 생성된다.
RecyclerView의 itemView에 컨텍스트 메뉴를 사용하려면
ViewHolder 생성자 내에서 따로 리스너를 만들어 사용할 수 있다.
- registerForContextMenu(view), unregisterForContextMenu(view)
바로 위의 뷰1.setOnCreateContextListener(this)는 registerForContextMenu(뷰1)과 동일하다.
Activity.java
Activity의 구현체를 리스너로 설정할 수도있으며, 직접 객체를 만들어서 리스너를 설정할 수도있다.
View가 롱 터치되고 설정된 리스너의 콜백 메서드 onCreateContextMenu를 통해 컨텍스트 메뉴를 만들게 된다.
작업이 끝나면 컨텍스트 메뉴가 화면에 출력되고 사용자가 아이템을 선택하면 onContextItemSelected메서드가 호출된다.
- onContextItemSelected(item: MenuItem) : Boolean
만들어진 컨텍스트 메뉴안의 메뉴 아이템이 선택되면 호출된다.
- onContextMenuClosed(menu: Menu): Unit
컨텍스트 메뉴가 화면에 보이는 상태에서 메뉴 아이템이 선택되지 않고 back버튼, 또는 컨텍스트 메뉴 바깥의 공간을 터치하면 호출된다.
테스트
context_menu1.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/context_menu_item1"
android:title="컨텍스트 메뉴 아이템1" />
<item
android:id="@+id/context_menu_item2"
android:title="컨텍스트 메뉴 아이템2" />
<item
android:id="@+id/context_menu_item3"
android:title="컨텍스트 메뉴 아이템3" />
<item
android:id="@+id/context_menu_item4"
android:title="컨텍스트 메뉴 아이템4" />
<item
android:id="@+id/context_menu_item5"
android:title="컨텍스트 메뉴 아이템5"/>
</menu>
context_menu2.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/context_menu2_item1"
android:title="컨텍스트 메뉴2 아이템1" />
<item
android:id="@+id/context_menu2_item2"
android:title="컨텍스트 메뉴2 아이템2" />
<item
android:id="@+id/context_menu2_item3"
android:title="컨텍스트 메뉴2 아이템3" />
<item
android:id="@+id/context_menu2_item4"
android:title="컨텍스트 메뉴2 아이템4" />
<item
android:id="@+id/context_menu2_item5"
android:title="컨텍스트 메뉴2 아이템5"/>
</menu>
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".TestActivity">
<TextView
android:id="@+id/textView"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#e2e2e2"
android:gravity="center"
android:text="타입1"
app:layout_constraintBottom_toTopOf="@+id/textView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#e2e2e2"
android:gravity="center"
android:text="타입2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
TestActivity.kt
package com.source.ui.contextmenutext
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.*
import android.widget.TextView
import android.widget.Toast
class TestActivity : AppCompatActivity() {
lateinit private var textView: TextView
lateinit private var textView2: TextView
private fun log(str: String) { //로그 출력
Log.d("ContextMenu", str)
}
private fun toast(str: String) { //토스트 출력
Toast.makeText(this, str, Toast.LENGTH_SHORT).show()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
log("onCreate")
setContentView(R.layout.activity_test)
textView = findViewById<TextView>(R.id.textView)
textView2 = findViewById<TextView>(R.id.textView2)
}
override fun onStart() { //리스너 등록 -
super.onStart()
log("onStart")
registerForContextMenu(textView) //Activity method
//= textView.setOnCreateContextMenuListener(this)
registerForContextMenu(textView2) //Activity method
//= textView2.setOnCreateContextMenuListener(this)
}
override fun onStop() { //리스너 해제
super.onStop()
log("onStop")
unregisterForContextMenu(textView)
//= textView.setOnCreateContextMenuListener(null)
unregisterForContextMenu(textView2)
//= textView2.setOnCreateContextMenuListener(null)
}
//Activity implements View.OnCreateContextMenuListener
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) { //롱 터치시 호출됨-> 컨텍스트 메뉴 생성
super.onCreateContextMenu(menu, v, menuInfo)
log("onCreateContextMenu")
val menuInflater = this.getMenuInflater()
if (v != null) { //View에 따라 분기
if (v.id == R.id.textView) {
menuInflater.inflate(R.menu.context_menu1, menu)
}
if (v.id == R.id.textView2) {
menuInflater.inflate(R.menu.context_menu2, menu)
}
} else {
Toast.makeText(this, "onCreateContextMenu View parameter is null", Toast.LENGTH_SHORT).show()
}
}
//어떠한 컨텍스트 메뉴인지 알수 없어 적절히 분기해야한다.
override fun onContextItemSelected(item: MenuItem): Boolean {
log("onContextItemSelected")
when (item.itemId) {
//컨텍스트 메뉴가 context_menu1.xml일때
R.id.context_menu_item1 -> {
toast("1")
return true
}
R.id.context_menu_item2 -> {
toast("2")
return true
}
R.id.context_menu_item3 -> {
toast("3")
return true
}
R.id.context_menu_item4 -> {
toast("4")
return true
}
R.id.context_menu_item5 -> {
toast("5")
return true
}
//컨텍스트 메뉴가 context_menu2.xml일때
R.id.context_menu2_item1 -> {
toast("one")
return true
}
R.id.context_menu2_item2 -> {
toast("two")
return true
}
R.id.context_menu2_item3 -> {
toast("three")
return true
}
R.id.context_menu2_item4 -> {
toast("four")
return true
}
R.id.context_menu2_item5 -> {
toast("five")
return true
}
else -> return false
}
//boolean Return false to allow normal context menu processing to proceed, true to consume it here.
}
}