안드로이드 세계

[Android] Recycler View - Step 3 본문

안드로이드(Android)/코틀린(Kotlin)

[Android] Recycler View - Step 3

리안94 2021. 1. 16. 00:50

이번 포스팅에는 추가 및 삭제 이벤트를 넣어볼 것이다.

 

삭제 이벤트는 기본 다이얼로그인 AlertDialog와 롱 클릭 시 나타나는 팝업 메뉴를 사용할 예정이고, 추가 이벤트는 DialogFragment를 이용할 예정이다.

 

먼저 삭제 이벤트먼저 구현을 해볼 것이다.

기본 다이얼로그를 사용할 것이기 때문에 xml을 따로 추가할 필요는 없다(커스텀을 하기 위해서는 필요함)

메인에 다이얼로그를 추가한다.

 

private fun deleteDialog(position: Int) {
    val dialog: AlertDialog = this@MainActivity.let {
        val builder: AlertDialog.Builder = AlertDialog.Builder(it)
        builder.apply {
            this.setMessage("${position}번째 내용을 삭제하시겠습니까?")
            this.setCancelable(false)
            this.setPositiveButton("삭제") { dialog, _ ->
                animalAdapter.animalsDataDelete(position)
                dialog.dismiss()
            }
            this.setNegativeButton("취소") { dialog, _ ->
                dialog.cancel()
            }
        }
        builder.create()
    }
    dialog.show()
}

 

그리고 팝업 메뉴를 사용할 것이기 때문에 이전에만들어둔 롱클릭이벤트에 다음과같이 넣어준다.

override fun onItemLongClick(view: View, position: Int) {
    val popupMenu = PopupMenu(this, view, Gravity.END)
    menuInflater.inflate(R.menu.menu, popupMenu.menu)
    popupMenu.setOnMenuItemClickListener(object : PopupMenu.OnMenuItemClickListener {
        override fun onMenuItemClick(item: MenuItem?): Boolean {
            when (item!!.itemId) {
                R.id.animalDataDelete -> {
                    deleteDialog(position)
                    return true
                }
            }
            return false
        }
    })
    popupMenu.show()
}

팝업메뉴를 사용하기 위해 res폴더에 menu폴더를 만든 후 다음과 같은 xml을 작성한다.

menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/animalDataDelete"
        android:title="@string/AnimalDataDelete"
        />

    <!-- @string/AnimalDataDelete : 삭제 -->
</menu>

※ 메뉴 폴더 만드는 방법 : new -> Android Resource Directroy -> Resource Type -> Menu

 

이렇게 만들게 되면 삭제 이벤트는 완료되었다.

 

 

 

추가 이벤트는 커스텀 다이얼로그(DialogFragment)를 이용할 예정이다.

 

먼저 DialogFragment를 구성할 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/name"
        android:text="@string/Name"
        android:textSize="16sp"
        android:layout_marginTop="20sp"
        android:layout_marginStart="16sp"
        app:layout_constraintWidth_percent="0.2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <EditText
        android:id="@+id/editName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:hint="@string/HintName"
        android:layout_marginTop="10sp"
        app:layout_constraintWidth_percent="0.5"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toRightOf="@id/name"
        android:inputType="text" />

    <TextView
        android:id="@+id/phoneNumber"
        android:text="@string/PhoneNum"
        android:textSize="16sp"
        android:layout_marginTop="20sp"
        android:layout_marginStart="16sp"
        app:layout_constraintWidth_percent="0.2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/name"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <EditText
        android:id="@+id/editPhoneNumber"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:hint="@string/HintPhoneNum"
        android:layout_marginTop="10sp"
        app:layout_constraintWidth_percent="0.5"
        app:layout_constraintTop_toBottomOf="@id/name"
        app:layout_constraintLeft_toRightOf="@id/phoneNumber"
        android:inputType="phone"/>

    <Button
        android:id="@+id/cancel"
        android:text="@string/Cancel"
        android:textSize="16sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintWidth_percent="0.4"
        android:layout_marginTop="30sp"
        android:layout_marginStart="16sp"
        app:layout_constraintTop_toBottomOf="@id/phoneNumber"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <Button
        android:id="@+id/add"
        android:text="@string/Add"
        android:textSize="16sp"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="25sp"
        android:layout_marginTop="30sp"
        app:layout_constraintWidth_percent="0.4"
        app:layout_constraintTop_toBottomOf="@id/phoneNumber"
        app:layout_constraintLeft_toRightOf="@id/cancel"/>

</androidx.constraintlayout.widget.ConstraintLayout>

추가 버튼, 취소 버튼, 이름, 연락처를 적을 에딧 텍스트로 구성되어있다.

 

class AnimalDataAddDialogFragment : DialogFragment() {

    private val fragmentView get() = _fragmentView
    private var _fragmentView: View? = null
    private lateinit var name: EditText
    private lateinit var phoneNum: EditText

    interface OnClickEvent {
        fun positiveButtonClick(animal: Animal)
        fun negativeButtonClick()
    }

    companion object {
        private var clickListener: OnClickEvent? = null
        fun getInstance(listener: OnClickEvent): AnimalDataAddDialogFragment {
            clickListener = listener
            return AnimalDataAddDialogFragment()
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _fragmentView = inflater.inflate(R.layout.dialog_animal_add, container, false)
        return fragmentView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

	//다이얼로그 뒤의 화면을 흐리게만들어주는 역할
        val layoutParam = WindowManager.LayoutParams().apply {
            flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND
            dimAmount = 0.8f
        }
        dialog?.window?.attributes = layoutParam

        initUI()
    }

    override fun onResume() {
        super.onResume()
        //다이얼로그 크기 조절
        requireContext().dialogFragmentResize(this@AnimalDataAddDialogFragment, 0.95f, 0.5f)
    }

    private fun initUI() {
        fragmentView?.let {
            name = it.findViewById(R.id.editName)
            phoneNum = it.findViewById(R.id.editPhoneNumber)
        }
        setButton()
    }

    private fun setButton() {
        fragmentView?.let {
            it.findViewById<Button>(R.id.cancel).setOnClickListener {
                negative()
            }
            it.findViewById<Button>(R.id.add).setOnClickListener {
                positive()
            }
        }
    }

    private fun positive() {
        val strName = name.text.toString()
        val strPhoneNum = phoneNum.text.toString()

        if (strName.isNotEmpty() && strPhoneNum.isNotEmpty()) {
            val animal = Animal("Cat", strName, strPhoneNum)
            clickListener?.positiveButtonClick(animal)
            exit()
        } else {
            Toast.makeText(requireContext(), "이름이나 휴대폰번호를 확인해주세요.", Toast.LENGTH_SHORT).show()
        }
    }

    private fun negative() {
        clickListener?.negativeButtonClick()
        exit()
    }

    private fun exit() {
        val fragment = fragmentManager?.findFragmentByTag("Add")
        if (fragment is AnimalDataAddDialogFragment)
            fragment.dismiss()
    }
}

에딧 텍스트의 값을 입력받은 후, 이름과 연락처 둘 다 입력이 되어있다면 메인으로 넘겨주는 간단한 다이얼로그이다.

 

다이얼로그 리사이즈하는 부분은 아래의 포스팅을 참고해주면 좋을 것 같다.

 

ryan94.tistory.com/6

 

다이얼로그 크기조절하기(Dialog or Dialog Fragment Resize)

커스텀 다이얼로그를 사용하다가보면 원하는 크기대로 다이얼로그가 생성되지 않는다. 아래의 내용은 해당 커스텀 다이얼로그를 디바이스 크기비율로 조절하는법이다. 다이얼로그 프래그먼트

ryan94.tistory.com

 

추가 버튼을 이용할 것이기 때문에 버튼을 추가해주어야 한다.

<?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=".ui.activity.MainActivity">
    
    <!-- @string/AnimalDataAdd : 추가 -->

    <Button
        android:id="@+id/add"
        android:text="@string/AnimalDataAdd"
        android:textSize="16sp"
        app:layout_constraintHeight_percent="0.1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/animalRecyclerView"
        app:layout_constraintHeight_percent="0.9"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="15sp"
        app:layout_constraintTop_toBottomOf="@id/add"/>



</androidx.constraintlayout.widget.ConstraintLayout>

 

그리고 다음과 같은 내용을 메인에 추가해준다.

private fun addDialog() {
    val animalDataAddDialog = AnimalDataAddDialogFragment.getInstance(object :
        AnimalDataAddDialogFragment.OnClickEvent {
        override fun positiveButtonClick(animal: Animal) {
            animalAdapter.animalsDataAdd(animal)
        }

        override fun negativeButtonClick() {
            Toast.makeText(this@MainActivity, "취소하셨습니다.", Toast.LENGTH_SHORT).show()
        }
    })
    animalDataAddDialog.show(supportFragmentManager, "Add")
}

해당 내용은 우리가 만든 다이얼로그를 보여주는 부분이다. 이제 버튼과 연동시켜주면 된다.

private fun addData() {
    findViewById<Button>(R.id.add).setOnClickListener {
        addDialog()
    }
}

추가 이벤트 구현까지 완료하였다.

 

이제 어뎁터를 수정해주면 완료된다.

//Add List Data
fun animalsDataAdd(animal: Animal) {
    animalsData.add(animal)
    notifyDataSetChanged()
}

//Delete List Data
fun animalsDataDelete(position: Int) {
    animalsData.removeAt(position)
    notifyItemRemoved(position)
}

위의 내용을 우리가 만들어둔 커스텀 어뎁터 내에 추가해주면 삭제 추가 이벤트를 완료하였다.

 

해당 리사이클 러뷰 샘플의 전체 소스는 다음 포스팅에 공유할 예정이다.

Comments