코딩 일기장/Android(Kotlin)
[Android/Kotlin] TextPicker/NumberPicker를 Custom해서 TextPicker 만들기/Dialog return value/다이얼로그에서 리턴값 받기
minWachya
2022. 8. 4. 17:26
반응형
만들고자 하는 것:
- 지상/층수 Text가 들어간 Picker
- Picker divider color 변경
- '선택 완료' 버튼 클릭 시 선택한 값 반환
- Acivity에서 Dialog 생성하고 Interfase 이용해서 반환값 가져오기
- Fragment에서 Dialog 생성하고 Interfase 이용해서 반환값 가져오기
1. dialog_select_floor.xml 생성
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="@drawable/background_dialog_r15">
<NumberPicker
android:id="@+id/min_max_picker"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginEnd="20dp"
android:theme="@style/ThemeOverlay.NumberPicker"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/floor_picker"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<NumberPicker
android:id="@+id/floor_picker"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="40dp"
android:theme="@style/ThemeOverlay.NumberPicker"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/min_max_picker"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/btn_ok"
style="@style/TextMedium.bold.Orange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="20dp"
android:padding="10dp"
android:text="@string/btn_ok"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/floor_picker" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
+ Picker divider color 변경
<style name="ThemeOverlay.NumberPicker" parent="Theme.SafetyManagement2022">
<item name="colorControlNormal">@color/app_gradient_end</item>
</style>
2. SelectFloorDialog.kt 생성
package com.example.safetymanagement2022.ui.building_detail
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import com.example.safetymanagement2022.databinding.DialogSelectFloorBinding
import java.lang.Integer.max
class SelectFloorDialog(private val minFloor: Int, private val maxFloor: Int) : DialogFragment() {
private var _binding: DialogSelectFloorBinding? = null
private val binding get() = _binding!!
private val floorArr = ArrayList<String>()
private val minMaxArr = arrayListOf("지상", "지하")
// 다이얼로그에서 값 리턴하기 위한 인터페이스 객체
private lateinit var mCallback: SelectedFloorInterface
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = DialogSelectFloorBinding.inflate(inflater, container, false)
val view = binding.root
// 레이아웃 배경을 투명하게
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
// 층수 배열 생성
createMinMaxArr()
// 지상/지하 피커 설정
setMinMaxPicker()
// 층수 피커 설정
setFloorPicker(0)
// '선택완료' 버튼 누르면 층수 정보 Activity로 전달
binding.btnOk.setOnClickListener {
val minMax = binding.minMaxPicker.value
val floor = binding.floorPicker.value
val floorText = minMaxArr[minMax] + " " + floorArr[floor]
// 리턴할 값 넣기!!
mCallback.onSelectedFloor(floorText, minMax, floor)
dismiss()
}
return view
}
private fun createMinMaxArr() {
val max = max(minFloor, maxFloor) + 1
for (i in 1 until max) floorArr.add("${i}층")
}
private fun setMinMaxPicker() {
binding.minMaxPicker.let {
it.minValue = 0
it.maxValue = 1
it.wrapSelectorWheel = true
it.displayedValues = minMaxArr.toTypedArray()
it.setOnValueChangedListener { picker, oldVal, newVal ->
if (newVal == 0) setFloorPicker(minFloor-1)
else setFloorPicker(maxFloor-1)
}
}
}
private fun setFloorPicker(floorSize: Int) {
// max 인 층 보여주고 size 만 조절
binding.floorPicker.let {
it.minValue = 0
it.displayedValues = floorArr.toTypedArray()
it.maxValue = floorSize
it.wrapSelectorWheel = true
}
}
// 액티비티에서 인터페이스 객체 받아오기
override fun onAttach(context: Context) {
super.onAttach(context)
mCallback = activity as SelectedFloorInterface
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
3-1. Acivity에서 Dialog 생성하고 Interface 이용해서 반환값 가져오기
package com.example.safetymanagement2022.ui.building_detail
import android.os.Bundle
import android.util.Log
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.example.safetymanagement2022.databinding.ActivityBuildingDetailBinding
import com.example.safetymanagement2022.ui.common.MyViewModelFactory
import java.lang.Integer.max
import kotlin.math.min
// 다이얼로그에서 값 받아오기 위한 인터페이스
interface SelectedFloorInterface {
fun onSelectedFloor(floorText: String, minMax: Int, floor: Int)
}
// 위 인터페이스 상속 받기
class BuildingDetailActivity : AppCompatActivity(), SelectedFloorInterface {
private lateinit var binding: ActivityBuildingDetailBinding
private val viewModel: BuildingDetailViewModel by viewModels { MyViewModelFactory(applicationContext) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBuildingDetailBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
viewModel.detailData.observe(this@BuildingDetailActivity) { data ->
binding.detail = data
binding.rvIssueDetail.adapter = BuildingDetailAdapter(data.issueList)
setShowSelectFloorDialog(data.minFloor, data.maxFloor)
}
}
private fun setShowSelectFloorDialog(minFloor: Int, maxFloor: Int) {
binding.tvFloor.setOnClickListener {
SelectFloorDialog(minFloor, maxFloor).show(supportFragmentManager, "SelectFloorDialog")
}
}
// 다이얼로그에서 값 받고나서 할 작업들
override fun onSelectedFloor(floorText: String, minMax: Int, floor: Int) {
binding.tvFloor.text = floorText
}
}
3-2. Fragment에서 Dialog 생성하고 Interfase 이용해서 반환값 가져오기
1. Dialog class에서 setFragmentResult 사용해서 Fragment에 보낼 값을 bundle에 담고,
// 다음 버튼
binding.btnNext.setOnClickListener {
val glassId = adapter. getSmartGlassId()
val glassName = adapter.getSmartGlassName()
setFragmentResult(KEY_DIALOG_GLASS, bundleOf(
KEY_DIALOG_GLASS_ID to glassId,
KEY_DIALOG_GLASS_NAME to glassName
))
dismiss()
}
2. Fragment에서 parentFragmentManager.setFragmentResultListener 사용해서 값 받아오면 됨!
parentFragmentManager.setFragmentResultListener(KEY_DIALOG_GLASS, viewLifecycleOwner) { key, bundle ->
glassId = bundle.get(KEY_DIALOG_GLASS_ID).toString().toInt()
glassName = bundle.get(KEY_DIALOG_GLASS_NAME).toString()
buildingDialog.show(parentFragmentManager, "SelectBuildingDialog")
}
참고
https://www.flutter-code.com/2015/05/how-to-use-numberpicker-in-android.html
https://chachas.tistory.com/51
https://stackoverflow.com/questions/34526866/return-values-from-dialogfragment
반응형