코딩 일기장/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

 

How to use NumberPicker in Android

Table of contents NumberPicker Example setOnValueChangedListener onValueChange() setWrapSelectorWheel() setMinValue...

www.flutter-code.com

https://chachas.tistory.com/51

 

🎨 Number/Time Picker Divider 색상 변경

 android kotlin - NumberPicker divider color  를 참고하였습니다. NumberPicker 도 TimePicker 와 동일하게 적용하면 Divider의 색상이 변경됩니다. Divider color를 변경하고 싶은 xml 파일에서 theme 속성..

chachas.tistory.com

https://stackoverflow.com/questions/34526866/return-values-from-dialogfragment

 

Return values from DialogFragment

I am doing task in which I need to show a dialog after clicking on EditText. In that dialog I show contents with RadioButtons using RecyclerView. Now, what I want to do is, after selecting RadioB...

stackoverflow.com

 

반응형