일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 막무가내
- flutter network call
- 부스트코스
- 막내의 막무가내
- 프로그래머스 알고리즘
- 막내의막무가내 안드로이드 코틀린
- 주택가 잠실새내
- 막내의막무가내 플러터 flutter
- 막내의막무가내 코볼 COBOL
- 프래그먼트
- 안드로이드 Sunflower 스터디
- 주엽역 생활맥주
- 막내의막무가내 안드로이드 에러 해결
- 막내의막무가내 코틀린 안드로이드
- 부스트코스에이스
- 막내의막무가내 안드로이드
- 막내의막무가내 SQL
- 안드로이드 sunflower
- 막내의막무가내
- 막내의 막무가내 알고리즘
- 막내의막무가내 일상
- 막내의막무가내 rxjava
- 막내의막무가내 플러터
- 막내의막무가내 프로그래밍
- 막내의막무가내 알고리즘
- 막내의막무가내 코틀린
- Fragment
- 안드로이드
- 2022년 6월 일상
- 막내의막무가내 목표 및 회고
- Today
- Total
막내의 막무가내 프로그래밍 & 일상
[안드로이드] 코틀린 커스텀 다이얼로그 프래그먼트 (Custom Dialog Fragment) 본문
[안드로이드] 코틀린 커스텀 다이얼로그 프래그먼트 (Custom Dialog Fragment)
막무가내막내 2020. 5. 23. 19:43
[2021-04-13 업데이트]
위와 같은 프래그먼트 위에 띄워줄 다이얼로그 프래그먼트를 직접 만들어봤습니다.
자바로는 만든적이 꽤 많은데 코틀린으로는 처음이여서 간단하게 기록하는 포스팅을 해볼까 합니다. 자바했던것을 기반으로 구현한거라 최상의 방법은 아닐 수 있습니다. (구글링해보니 코틀린 다이얼로그 프래그먼트 한국 자료는 거의 안보이더라고요)
코드를 보면 이해가 가실겁니다!!
먼저 다이얼로그 프래그먼트 xml 입니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:elevation="20dp"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="70dp"
android:gravity="center"
android:padding="8dp"
android:text="@string/dialog_favorite_add_text"
android:textColor="@color/colorBlack"
android:textSize="15sp"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorWhiteGray" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:weightSum="2">
<TextView
android:id="@+id/dialog_tv_yes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:text="@string/yes_text"
android:textColor="@color/colorBlack" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/colorWhiteGray" />
<TextView
android:id="@+id/dialog_tv_no"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="8dp"
android:text="@string/no_text"
android:textColor="@color/colorBlack" />
</LinearLayout>
</LinearLayout>
다이얼로그 프래그먼트 입니다. (Dialog Fragment)
getInstance() 통해 다이얼로그를 액비티이 또는 프래그먼트에서 다이얼로그 프래그먼트 인스턴스를 가져옵니다.
EXTRA_NOTICE_SAVE 는 원하는 태그 값을 넣어주면 됩니다. ( 추가로 번들에 전달된 값을 통해 여러 프래그먼트에서 하나의 다이얼로그를 사용하는 경우가 있을텐데 상황에 따른 텍스트 변경 같은 것도 가능합니다. => 예를들어, 위 다이얼로그처럼 모양은 같은데 질문만 달라야하는 경우 하나의 다이얼로그를 다시만들 필요가 없고 분기처리해서 텍스트만 변경해주는게 가능합니다.)
onClick() 은 다이얼로그 화면 외를 클릭 했을 때 다이얼로그 화면을 사라지게 만들기 위해 작성했습니다.
package com.mtjin.cnunoticeapp.views.dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.mtjin.cnunoticeapp.R
import com.mtjin.cnunoticeapp.constants.EXTRA_NOTICE_SAVE
import com.mtjin.cnunoticeapp.data.favorite.FavoriteNotice
import com.mtjin.cnunoticeapp.views.favorite.FavoriteViewModel
import kotlinx.android.synthetic.main.fragment_dialog_add.view.*
import org.koin.androidx.viewmodel.ext.android.viewModel
class DialogAddFragment : DialogFragment(), View.OnClickListener {
private val viewModel: FavoriteViewModel by viewModel()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dialog_add, container, false)
//어느 다이어로그에서 왔는지
val bundle = arguments
val notice = bundle?.getParcelable<FavoriteNotice>(EXTRA_NOTICE_SAVE)
view.dialog_tv_yes.setOnClickListener {
notice?.let { notice ->
viewModel.insert(notice)
dismiss()
}
}
view.dialog_tv_no.setOnClickListener {
dismiss()
}
return view
}
fun getInstance(): DialogAddFragment {
return DialogAddFragment()
}
override fun onClick(p0: View?) {
dismiss()
}
}
다음은 다이얼로그 프래그먼트를 띄워줄 부모 프래그먼트 코드입니다. 사진만 보면 됩니다.
package com.mtjin.cnunoticeapp.views.employ
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import com.mtjin.cnunoticeapp.R
import com.mtjin.cnunoticeapp.constants.EXTRA_NOTICE_SAVE
import com.mtjin.cnunoticeapp.constants.TAG_DIALOG_EVENT
import com.mtjin.cnunoticeapp.data.favorite.FavoriteNotice
import com.mtjin.cnunoticeapp.databinding.FragmentEmployBinding
import com.mtjin.cnunoticeapp.utils.NetworkManager
import com.mtjin.cnunoticeapp.views.dialog.DialogAddFragment
import org.koin.androidx.viewmodel.ext.android.viewModel
class EmployNoticeFragment : Fragment() {
private lateinit var binding: FragmentEmployBinding
private lateinit var noticeAdapter: EmployAdapter
private val viewModel: EmployNoticeViewModel by viewModel()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_employ, container, false)
binding.lifecycleOwner = this
binding.vm = viewModel
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
initAdapter()
val networkManager: NetworkManager? = context?.let { NetworkManager(it) }
if (!networkManager?.checkNetworkState()!!) {
showToast(getString(R.string.network_err_toast))
}
viewModel.requestNotice()
}
private fun initAdapter() {
noticeAdapter = EmployAdapter(
itemClick = { item ->
Intent(
Intent.ACTION_VIEW,
Uri.parse(getString(R.string.job_url) + item.link)
).run(this::startActivity)
},
longItemClick = {
val bundle = Bundle()
bundle.putParcelable(EXTRA_NOTICE_SAVE, FavoriteNotice(it.num, it.title, it.link))
val dialog: DialogAddFragment = DialogAddFragment().getInstance()
dialog.arguments = bundle
activity?.supportFragmentManager?.let { fragmentManager ->
dialog.show(
fragmentManager,
TAG_DIALOG_EVENT
)
}
}
)
binding.rvBusiness.adapter = noticeAdapter
}
private fun showToast(msg: String) =
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
}
참고로 상수는 다음과 같이 따로 보관해놨습니다.
package com.mtjin.cnunoticeapp.constants
const val EXTRA_NOTICE_SAVE = "EXTRA_NOTICE_SAVE"
const val TAG_DIALOG_EVENT = "TAG_DIALOG_EVENT"
[P.S]
여러 프래그먼트에서 다이얼로그 프래그먼트를 사용하고 질문내용만 바꿔주고 싶다면 다음과 같이 Bundle 키 값으로 분기처리 해주면 됩니다 (EXTRA_NOTICE_DELETE 키 값으로 분기처리했습니다.)
package com.mtjin.cnunoticeapp.views.dialog
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.mtjin.cnunoticeapp.R
import com.mtjin.cnunoticeapp.constants.EXTRA_NOTICE_DELETE
import com.mtjin.cnunoticeapp.constants.EXTRA_NOTICE_SAVE
import com.mtjin.cnunoticeapp.data.favorite.FavoriteNotice
import com.mtjin.cnunoticeapp.views.favorite.FavoriteViewModel
import kotlinx.android.synthetic.main.fragment_dialog_add.view.*
import org.koin.androidx.viewmodel.ext.android.viewModel
class DialogAddFragment : DialogFragment(), View.OnClickListener {
private val viewModel: FavoriteViewModel by viewModel()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dialog_add, container, false)
processBundle(view)
return view
}
private fun processBundle(view: View) {
val bundle = arguments
val notice = bundle?.getParcelable<FavoriteNotice>(EXTRA_NOTICE_SAVE)
when (bundle?.getString(EXTRA_NOTICE_DELETE, "")) {
EXTRA_NOTICE_DELETE -> {
view.dialog_tv_question.text = getString(R.string.dialog_favorite_delete_text)
view.dialog_tv_yes.setOnClickListener {
notice?.let { notice ->
viewModel.delete(notice)
dismiss()
}
}
view.dialog_tv_no.setOnClickListener {
dismiss()
}
}
else -> {
view.dialog_tv_yes.setOnClickListener {
notice?.let { notice ->
viewModel.insert(notice)
dismiss()
}
}
view.dialog_tv_no.setOnClickListener {
dismiss()
}
}
}
}
fun getInstance(): DialogAddFragment {
return DialogAddFragment()
}
override fun onClick(p0: View?) {
dismiss()
}
}
위와 같이 번들로 하기 귀찮은 경우 다음과 같이 고차함수를 사용해서 더 편하게 구현하시면 됩니다. (저는 이게 더 좋은 것 같습니다.)
package com.mtjin.nomoneytrip.views.dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.mtjin.nomoneytrip.R
import kotlinx.android.synthetic.main.fragment_dialog_yes_no.view.*
class YesNoDialogFragment(private val yesClick: (Boolean) -> Unit) : DialogFragment(),
View.OnClickListener {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dialog_yes_no, container, false)
//어느 다이어로그에서 왔는지
// val bundle = arguments
// val notice = bundle.getParcelable<FavoriteNotice>(EXTRA_NOTICE_SAVE)
view.tv_yes.setOnClickListener {
yesClick(true)
}
view.tv_no.setOnClickListener {
dismiss()
}
return view
}
companion object {
fun getInstance(yesClick: (Boolean) -> Unit): YesNoDialogFragment {
return YesNoDialogFragment(yesClick)
}
}
override fun onClick(p0: View?) {
dismiss()
}
}
val dialog =
YesNoDialogFragment.getInstance(yesClick = {
if (it) viewModel.deleteReservation(reservationHistory.reservation)
})
dialog.show(requireActivity().supportFragmentManager, dialog.tag)
추가로 위와 코드에서 하나의 네, 아니요 다이얼로그 프래그먼트를 재활용하기 위해 질문을 매개변수로 받아 세팅하는 것을 추가한 코드입니다.
[DialogFragment]
package com.mtjin.cnunoticeapp.views.dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.mtjin.cnunoticeapp.R
import kotlinx.android.synthetic.main.fragment_dialog_yes_no.view.*
class YesNoDialogFragment : DialogFragment(),
View.OnClickListener {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_dialog_yes_no, container, false)
view.apply {
tv_question.text = question
tv_yes.setOnClickListener {
yesClick(true)
dismiss()
}
tv_no.setOnClickListener {
dismiss()
}
}
return view
}
companion object {
lateinit var yesClick: (Boolean) -> Unit
lateinit var question: String
fun getInstance(yesClick: (Boolean) -> Unit, question: String): YesNoDialogFragment {
this.yesClick = yesClick
this.question = question
return YesNoDialogFragment()
}
}
override fun onClick(p0: View?) {
dismiss()
}
}
[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="wrap_content"
android:layout_marginStart="36dp"
android:layout_marginEnd="36dp">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/radius_16dp"
app:cardElevation="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="36dp"
android:gravity="center"
android:text="추천하시겠습니까?\n한번한 추천은 취소가 불가능합니다."
android:textColor="@color/colorBlack"
android:textSize="@dimen/text_size_14sp"
app:layout_constraintBottom_toTopOf="@id/view_middle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/view_middle"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="35.3dp"
android:background="@color/colorWhiteGray"
app:layout_constraintBottom_toTopOf="@id/tv_no"
app:layout_constraintTop_toBottomOf="@id/tv_question" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_no"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_12dp"
android:layout_marginBottom="@dimen/margin_15dp"
android:gravity="center"
android:text="@string/no_text"
android:textColor="@color/colorRed"
android:textSize="@dimen/text_size_14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/view_yes_no"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/view_middle" />
<View
android:id="@+id/view_yes_no"
android:layout_width="1dp"
android:layout_height="0dp"
android:background="@color/colorWhiteGray"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_yes"
app:layout_constraintStart_toEndOf="@id/tv_no"
app:layout_constraintTop_toBottomOf="@id/view_middle" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_yes"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/margin_12dp"
android:layout_marginBottom="@dimen/margin_15dp"
android:gravity="center"
android:text="@string/yes_text"
android:textColor="@color/colorWhiteBlue"
android:textSize="@dimen/text_size_14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/view_yes_no"
app:layout_constraintTop_toBottomOf="@id/view_middle" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
[생성]
val dialog =
YesNoDialogFragment.getInstance(yesClick = {
if (it) viewModel.insertBoard()
}, question = "작성완료 하시겠습니까?\n수정 및 삭제는 불가능합니다.")
dialog.show(supportFragmentManager, dialog.tag)
https://youngest-programming.tistory.com/349
바텀다이얼로그시트는 다음 링크를 참고해주세요
도움이 되셨다면 공감과 댓글은 큰 힘이 됩니다. !!
'안드로이드 > 코틀린 & 아키텍처 & Recent' 카테고리의 다른 글
[안드로이드] ViewModel 에서 context 필요로 할 때 해결방법 (0) | 2020.06.22 |
---|---|
[안드로이드] 안드로이드 MVVM + RxJava2 + Koin + Jsoup 정리 (충남대학교 컴퓨터공학과 공지사항 토이 프로젝트) (4) | 2020.06.03 |
[안드로이드] Jetpack Bottom Navigation View refactor name 관련 주의할 점 (0) | 2020.05.23 |
[안드로이드] * What went wrong:Execution failed for task ':app:kaptDebugKotlin'.> A fail (7) | 2020.05.22 |
[코틀린] Jsoup 파싱 라이브러리 사용 기록 (0) | 2020.05.21 |