티스토리 뷰

반응형

1. 업무 삭제 기능

 

먼저, 삭제 기능을 담당하는 함수를 정의합니다. 업무 추가 기능과 마찬가지로 notifyDataSetChanged( )를 사용해 변동 사항을 어댑터로 보내야 합니다. 삭제를 담당하는 기능은 remove 메소드를 통해서 이루어집니다.

private fun deleteTodo(todo: Todo){
        data.remove(todo)
        binding.recyclerView.adapter?.notifyDataSetChanged()
}

 

어댑터 부분의 인자로 리턴값이 없는 함수를 넣어줍니다. val onClickDeleteIcon:(todo: Todo) -> Unit) 처럼, 아이콘 클릭 시 업무 삭제를 의미하는 '표면적인' 함수를 어댑터 인자로 넣어줍니다. 당연히 리턴값이 없으므로 Unit 타입으로 리턴값을 정의합니다. 이 함수는 onBindViewHolder 메소드에서 벡터 아이콘을 클릭 시 함수가 실행될 수 있도록 전달받기 위한 인자로 사용될 것입니다.

class TodoAdapter(private val dataSet: List<Todo>,
                  val onClickDeleteIcon:(todo: Todo) -> Unit) :
    RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() { ..생략.. }
반응형

실제 뷰가 보여지는 부분인 onBindViewHolder 메소드를 살펴 봅니다. 위에서 말한 것 처럼, 이미지뷰(삭제 모양 아이콘)를 클릭했을 때 어댑터의 인자로 넣었던 onClickDeleteIcon 함수를 실행하도록 합니다. 이때 invoke 메소드를 사용해서 todo 변수에 정의해둔 dataSet[position]을 해당 함수 인자로 넣도록 합니다.

override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        ** 생략 **
        holder.binding.deleteImageView.setOnClickListener {
            onClickDeleteIcon.invoke(todo)
        }
}

 

이제는 onCreate 메소드의 어댑터 부분을 수정해줘야 합니다. 어댑터에 onClickDeleteIcon 함수를 담고 deleteTodo 메소드가 실행될 수 있도록 합니다. it은 Todo 타입의 todo 값이 들어 있습니다.

결국 흐름은 벡터 아이콘을 클릭하면, onClickDeleteIcon.invoke(todo)가 실행되는데, 리사이클러뷰의 어댑터에 할당된 TodoAdapter에 그대로 onClickDeleteIcon의 실행이 반영되도록 하는 것입니다. 이때 it을 통해 todo를 전달받게 되는 것이죠. 

override fun onCreate(savedInstanceState: Bundle?) {
   binding.recyclerView.adapter = TodoAdapter(data,
                onClickDeleteIcon = {
                    deleteTodo(it)
                }
              )
}

 

2. 업무 완료 기능

 

이제는 업무 완료 기능을 구현해 봅시다. 업무가 완료되면 paintFlag를 사용해서 사선이 그어지고, 글자체가 바뀌도록 할 것입니다.

 

먼저 어댑터에 val onClickItem: (todo: Todo) -> Unit) 인자를 추가로 선언하여 onBindViewHolder에서 전달받을 수 있도록 합니다. onBindViewHolder 메소드는 실제 화면에 표시되는 부분을 담당하기에, 해당 메소드에서 업무 완료 기능을 수행합니다. apply 함수를 사용해서 중복되는 holder.binding.todoText 부분을 그대로 넘겨 주도록 합니다. 

STRIKE_THRU_TEXT_FLAG를 통해 사선을 그어주고, setTypeface(null, Typeface.ITALIC)를 사용해 글자체를 바꿔줍니다.

'paintFlags = 0' 은 객체 원래대로의 모습으로 놔두겠다는 의미입니다.

if (todo.isDone) {
            holder.binding.todoText.apply {
                paintFlags = paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
                setTypeface(null, Typeface.ITALIC)
            }
        } else {
            holder.binding.todoText.apply {
                paintFlags = 0
                setTypeface(null, Typeface.NORMAL)
            }
}

 

삭제 기능에서 이미지뷰에 접근했던 것처럼, 바인딩된 객체 전체에 접근해서 어댑터의 onClickItem 함수를 전달하도록 할 것입니다. 전체에 접근하려면 binding.root를 사용합니다.

 holder.binding.root.setOnClickListener {
            onClickItem.invoke(todo)
}

이제는 onCreate 메소드의 어댑터를 수정해줄 차례입니다. 마찬가지로 binding.recyclerView의 중복을 간결하게 정리하기 위해 apply 함수를 이용합니다. this는 리사이클러뷰이기 때문에, @MainActivity를 추가하여 명시적으로 알려주도록 합니다.

binding.recyclerView.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = TodoAdapter(
                emptyList(),
                onClickDeleteIcon = {
                    deleteTodo(it)
                },
                onClickItem = {
                    toggleTodo(it)
                }
            )
}

 

클릭 시 실행되는 toggleTodo 함수는 isDone 인자의 값이 true로 바뀌어야 하므로 아래와 같이 정의해줍니다.

private fun toggleTodo(todo: Todo) {
       todo.isDone = !todo.isDone
       binding.recyclerView.adapter?.notifyDataSetChanged()
}

마지막으로, 뷰 모델과 라이브 데이터를 적용하여 회전에 따른 데이터 유실을 방지하고 관리 포인트를 손쉽게 만들도록 간결한 코드를 작성하면 앱이 최종적으로 완성됩니다.

 

뷰 모델과 라이브 데이터는 제 블로그의 관련 내용을 참조 바랍니다.

* 뷰 모델

https://itknowledgeshare.tistory.com/106

 

뷰 모델 View Model

앱 제작 시 안드로이드 생명 주기에 따라 회전 처리가 이루어지면 앱의 데이터가 날라가 버리게됩니다. 이러한 부분을 방지하기 위해 뷰 모델 클래스를 사용됩니다. 뷰 모델을 사용하면, 화면

itknowledgeshare.tistory.com

* 라이브 데이터

https://itknowledgeshare.tistory.com/107

 

라이브 데이터 Live Data

뷰 모델 클래스를 사용할 때, 함께 사용할 수 있는 좋은 기능이 라이브 데이터입니다. 라이브 데이터는 관찰 가능한 데이터를 담아두는 클래스입니다. 쉽게 말해, 데이터를 지켜보고 있다가 변

itknowledgeshare.tistory.com

 

최종 완성된 앱은 다음과 같습니다.

반응형
댓글