간단하게 Todo 예제로 해당 기능을 만들어 봤습니다.
먼저 Todo 클래스입니다.
data class Todo(
val id: String,
val name: String,
val done: Boolean = false
) : Serializable
TodoAdapter
class TodoAdapter(
private val onItemClicked: (Todo) -> Unit
): ListAdapter<Todo, TodoAdapter.TodoViewHolder>(DIFF_CALLBACK) {
companion object {
private val DIFF_CALLBACK = object: DiffUtil.ItemCallback<Todo>() {
override fun areItemsTheSame(oldItem: Todo, newItem: Todo): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Todo, newItem: Todo): Boolean {
return oldItem == newItem
}
}
}
class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val text1: CheckedTextView by lazy { itemView.findViewById(android.R.id.text1) }
fun bind(todo: Todo) {
text1.text = todo.name
text1.isChecked = todo.done
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(android.R.layout.simple_list_item_checked, parent,false)
return TodoViewHolder(itemView)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val todo = getItem(position)
holder.bind(todo)
holder.itemView.setOnClickListener {
onItemClicked(todo)
}
}
}
보시다시피, 이벤트 처리는 외부에서 처리할 수 있도록 리스너 함수를 연결해 주었습니다.
아이템을 클릭하면 편집화면에서 완료 체크버튼을 누를 수 있는 TodoEditActivity를 띄울 겁니다. 이렇게 하기위해서 아래처럼,
ActivityResultContract을 상속받는 클래스를 하나 만듭니다.
class GetTodoResult : ActivityResultContract<Todo, Todo?>() {
companion object {
const val TODO_ITEM = "todoItem"
}
override fun createIntent(context: Context, input: Todo): Intent {
val intent = Intent(context, TodoEditActivity::class.java)
intent.putExtra(TODO_ITEM, input)
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?): Todo? {
if (resultCode != Activity.RESULT_OK) return null
return intent?.getSerializableExtra(TODO_ITEM) as? Todo
}
}
TodoEditActivity입니다. Todo 리스트에서 선택한 아이템의 완료 체크박스를 변경한 후 저장할 수 있도록 했습니다.
class TodoEditActivity : AppCompatActivity() {
private val binding by lazy { ActivityTodoEditBinding.inflate(layoutInflater) }
private lateinit var todo: Todo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
setupViews()
bindTodo()
}
private fun setupViews() {
binding.apply {
doneCheckBox.setOnCheckedChangeListener { _, checked ->
todo = todo.copy(done = checked)
}
saveBtn.setOnClickListener {
saveAndExit()
}
}
}
private fun saveAndExit() {
val intent = Intent()
intent.putExtra(GetTodoResult.TODO_ITEM, todo)
setResult(Activity.RESULT_OK, intent)
this.finish()
}
private fun bindTodo() {
todo = intent.getSerializableExtra(GetTodoResult.TODO_ITEM) as Todo
binding.apply {
nameTxt.text = todo.name
doneCheckBox.isChecked = todo.done
}
}
}
마지막으로 MainActivity입니다. Todo 리스트를 보여주고 클릭하면 TdoEditActivity를 띄운 후 변경시에 리스트를 갱신합니다.
class MainActivity : AppCompatActivity() {
private var todoItems: List<Todo> = listOf(
Todo("1", "Buy milk"),
Todo("2", "Finish homework"),
Todo("3", "Workout"),
Todo("4", "Walk"),
Todo("5", "Gathering with friends")
)
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
setupView()
}
private val todoAdapter by lazy {
TodoAdapter { todo ->
todoItemClicked(todo)
}
}
private fun setupView() {
binding.apply {
todoListView.adapter = todoAdapter
todoAdapter.submitList(todoItems)
}
}
private val getTodo = registerForActivityResult(GetTodoResult()) { todo: Todo? ->
if (todo != null) todoUpdated(todo)
}
private fun todoItemClicked(todo: Todo) {
getTodo.launch(todo)
}
private fun todoUpdated(todo: Todo) {
todoItems = todoItems.map {
if (it.id == todo.id) todo else it
}
todoAdapter.submitList(todoItems)
}
}