관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[안드로이드] 안드로이드 BottomSheetDialog 샘플 (with top radius)(feat. 네 아니요 질문, Ratingbar 점수주기) 본문

안드로이드/코틀린 & 아키텍처 & Recent

[안드로이드] 안드로이드 BottomSheetDialog 샘플 (with top radius)(feat. 네 아니요 질문, Ratingbar 점수주기)

막무가내막내 2020. 9. 8. 23:49
728x90

 

 

[2021-04-14 업데이트]

 

 

이 글에서 RatingBar 코드는 화면 회전시 Crash 이슈를 해결된 상태로 변경해논 상태지만 네,아니요 바텀다이얼로그는 코드를 변경해놓지 않은 상태입니다. (프로젝트에서 사용하다가 없어진 기능이어서요 ㅠ ) RatingBar 바뀐코드 보고 그대로 하시면 어려움이 없을거라 생각됩니다.  ]

밑 부분에서 itemClick 클릭 이벤트 부분을 1번에서 2번 형식으로 바꿔주면 될거에요.

 

[1번. 예, 아니요]

companion object {
        fun newInstance(
            question: String,
            itemClick: (Boolean) -> Unit
        ): BottomDialogFragment {
            return BottomDialogFragment(question, itemClick)
        }
    }

 

 

[2번. 레이팅바 점수]

lateinit var ratingClick: (Float) -> Unit
        fun newInstance(
            ratingClick: (Float) -> Unit
        ): RatingBottomDialogFragment {
            this.ratingClick = ratingClick
            return RatingBottomDialogFragment()
        }

 

youngest-programming.tistory.com/349

 

[코틀린] 안드로이드 BottomSheetDialog 콜백 구현

본 프로젝트 전에 적용하기 전 샘플 프로젝트로 잘 되나 바텀시트다이얼로그를 테스트해봤습니다. ㅎㅎ 바텀시트 다이얼로그 프래그먼트에서 아이템 선택시 기존 액티비티나 프래그먼트에서

youngest-programming.tistory.com

 

 

 

위와 같이 BottomSheetDialog 로 의문형을 묻고 네, 아니요를 선택하는 뷰를 쓸때가 많은데요. 나중에 빠르게 구현하기 위해 기록용으로 남겨놓습니다. ㅎㅎ 

먼저 구현할 바텀시트다이얼로그의 UI를 소개하자면 양쪽위모서리가 둥그런 바텀시트다이얼로그입니다. 코드는 어렵지 않으니 보시면 이해하실거라 생각합니다. !!

 

 

[BottomDialogFragment.kt]

여러개 띄워지는 것도 방지하기 위해 싱글톤을 사용하며 매번 달라질 수 있는 질문을 question 이라는 인자로 받습니다. 

package com.mtjin.nomoneytrip.views.dialog

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.mtjin.nomoneytrip.R
import kotlinx.android.synthetic.main.fragment_bottom_dialog.view.*

class BottomDialogFragment(
    private val question: String,
    val itemClick: (Boolean) -> Unit
) :
    BottomSheetDialogFragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View =
        inflater.inflate(R.layout.fragment_bottom_dialog, container, false)

    companion object {
        fun newInstance(
            question: String,
            itemClick: (Boolean) -> Unit
        ): BottomDialogFragment {
            return BottomDialogFragment(question, itemClick)
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.text_question.text = question
        view.tv_yes.setOnClickListener {
            itemClick(true)
            dialog?.dismiss()
        }
        view.tv_no.setOnClickListener {
            itemClick(false)
            dialog?.dismiss()
        }
    }
}

 

 

[fragment_bottom_dialog.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:paddingBottom="@dimen/padding_20dp"
    app:behavior_hideable="true"
    app:behavior_peekHeight="@dimen/behavior_height_56dp"
    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/text_question"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/margin_36dp"
        tools:text="질문입니까?"
        android:textSize="@dimen/text_size_24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tv_yes"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/margin_20dp"
        android:gravity="center"
        android:paddingTop="@dimen/padding_12dp"
        android:paddingBottom="@dimen/padding_12dp"
        android:text="@string/yes_text"
        android:textColor="@color/colorWhiteBlue"
        android:textSize="@dimen/text_size_16sp"
        app:layout_constraintTop_toBottomOf="@id/text_question" />

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tv_no"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/margin_20dp"
        android:gravity="center"
        android:paddingTop="@dimen/padding_12dp"
        android:paddingBottom="@dimen/padding_12dp"
        android:text="@string/no_text"
        android:textColor="@color/colorRed"
        app:layout_constraintTop_toBottomOf="@id/tv_yes" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

바텀시트의 속성에 대해서는 이전 포스팅에서 설명한 바 있으니 생략하겠습니다. 

youngest-programming.tistory.com/349

 

[코틀린] 안드로이드 BottomSheetDialog 콜백 구현

본 프로젝트 전에 적용하기 전 샘플 프로젝트로 잘 되나 바텀시트다이얼로그를 테스트해봤습니다. ㅎㅎ 바텀시트 다이얼로그 프래그먼트에서 아이템 선택시 기존 액티비티나 프래그먼트에서 �

youngest-programming.tistory.com

 

 

 

[styles.xml]

둥그런 바텀시트다이얼로그를 구현하기 위해서는 Style 속성도 다음과 같이 지정해주어야합니다.

bottom 이 붙은 item 만 보시면 될 것 같습니다.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorOrangeF79256</item>
        <item name="colorPrimaryDark">@color/colorOrangeF79256</item>
        <item name="colorAccent">@color/colorOrangeF79256</item>
        <item name="colorControlActivated">@color/colorOrangeF79256</item>
        <item name="android:textCursorDrawable">@color/colorOrangeF79256</item>
        <item name="android:windowBackground">@color/colorWhiteFDFD</item>
        <item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item>
    </style>

    <style name="AppBottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog">
        <item name="bottomSheetStyle">@style/AppModalStyle</item>
    </style>

    <style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal">
        <item name="android:background">@drawable/bg_white_top_radius_16dp</item>
    </style>

    <!-- Toolbar theme. -->
    <style name="toolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
        <item name="android:textColor">@color/colorWhiteFDFD</item>
        <item name="android:textSize">24sp</item>
    </style>
</resources>

위 Style 에서 쓰이는 bg_white_radius_8dpbg_white_top_radius_16dp 입니다.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/colorWhiteFDFD" />
    <corners
        android:topLeftRadius="16dp"
        android:topRightRadius="16dp" />
</shape>

 

 

 

 

[Fragment 뷰 단]

여기까지 하셨으면 이제 뷰단에서 다음과 같이 사용하시면 됩니다. 싱글톤을 사용합니다.

val dialog = BottomDialogFragment.newInstance(question = "예약을 취소 하시겠습니까?", 
               itemClick = {
                     if (it) viewModel.deleteReservation(reservationHistory.reservation)
               })
dialog.show(requireActivity().supportFragmentManager, dialog.tag)

 

 

 


 

[RatingbarBottomDialogFragment Sample]

 

 

 

 

[styles.xml]

<!-- Ratingbar theme -->
    <style name="RatingBarTheme" parent="Theme.AppCompat">
        <item name="colorControlNormal">@color/colorOrangeF79256</item>
        <item name="colorControlActivated">@color/colorOrangeF79256</item>
        <item name="android:progressTint">@color/colorOrangeF79256</item>
        <item name="android:secondaryProgressTint">@android:color/transparent</item>
    </style>

 

[Fragment]

package com.mtjin.nomoneytrip.views.dialog

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RatingBar
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.mtjin.nomoneytrip.R
import kotlinx.android.synthetic.main.fragment_rating_bottom_dialog.view.*

class RatingBottomDialogFragment :
    BottomSheetDialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View =
        inflater.inflate(R.layout.fragment_rating_bottom_dialog, container, false)

    companion object {
        lateinit var ratingClick: (Float) -> Unit
        fun newInstance(
            ratingClick: (Float) -> Unit
        ): RatingBottomDialogFragment {
            this.ratingClick = ratingClick
            return RatingBottomDialogFragment()
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.rb_rating.onRatingBarChangeListener =
            RatingBar.OnRatingBarChangeListener { p0, rating, p2 ->
                ratingClick(rating)
                dialog?.dismiss()
            }
    }
}
val dialog =
                    RatingBottomDialogFragment.newInstance(
                        ratingClick = { rating ->
                            showToast(rating.toString())
                            reservationProduct.product.ratingList.add(rating)
                            findNavController().navigate(
                                TourHistoryFragmentDirections.actionTourHistoryFragmentToTourWriteFragment(
                                    reservationProduct
                                )
                            )
                        })
                dialog.show(requireActivity().supportFragmentManager, dialog.tag)

 

 

 

[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:paddingBottom="@dimen/padding_36dp"
    app:behavior_hideable="true"
    app:behavior_peekHeight="@dimen/behavior_height_56dp"
    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

    <androidx.appcompat.widget.AppCompatRatingBar
        android:id="@+id/rb_rating"
        style="@style/RatingBarTheme"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="28dp"
        android:layout_marginTop="@dimen/margin_20dp"
        android:isIndicator="false"
        android:numStars="5"
        android:stepSize="0.5"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.AppCompatTextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/margin_16dp"
        android:gravity="center"
        android:text="@string/rating_then_next_text"
        android:textColor="@color/colorBlack2D2D"
        app:layout_constraintEnd_toEndOf="@id/rb_rating"
        app:layout_constraintStart_toStartOf="@id/rb_rating"
        app:layout_constraintTop_toBottomOf="@id/rb_rating" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다. !!

728x90
Comments