본문 바로가기

Android/Android의 모든 것

👋Android의 모든 것 : 1️⃣BottomSheetDialogFragment, 2️⃣Bottomsheetbehavior

728x90

https://goni95.tistory.com/173

 

👋Android에 모든 것 개념

목  차 1. Android 👋Android에 모든 것 : 1️⃣Android, 2️⃣Android SDK, 3️⃣Platform Architecture 👋Android에 모든 것 개념 : 1️⃣App Manifest, 2️⃣Android Context, 3️⃣App Components 👋Android..

goni95.tistory.com

 

예제 결과

 

1️⃣BottomSheetDialogFragment

BottomSheetDialogFragment는 떠 있는 Dialog 대신 BottomSheetDialog를 사용해 하단 시트를 보여주는 DialogFragment 버전입니다. 즉, 밑에서 올라오는 팝업창이라고 생각하면 됩니다.

 

예제를 확인하기 전 Databinding과 Style Resource에 대한 내용이 포함되어 있으니, 참고해주시기 바랍니다.

 

1. 모듈 수준의 build.gradle 파일에 material 종속성 추가가 필요합니다.

    implementation 'com.google.android.material:material:1.5.0'

 

2. BottomSheetDialogFragment에서 사용하려는 XML 레이아웃 파일을 작성합니다. 

 

bottom_sheet_food_ntr_irdnt.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"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="model"
            type="***.***.FoodNtrIrdntModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp">

        <TextView
            android:id="@+id/foodNtrIrdnt_beginYear_textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:text="@{@string/begin_year_desc_info(model.beginYear)}"
            android:textColor="@color/color_on_secondary"
            android:textSize="12sp"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_fat_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_serving_weight_textView"
            tools:text="구축년도" />

        <TextView
            android:id="@+id/foodNtrIrdnt_description_kor_textView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginTop="50dp"
            android:layout_marginEnd="10dp"
            android:maxLines="2"
            android:text="@{model.descriptionKOR}"
            android:textColor="@color/color_on_secondary"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="식품 명" />

        <TextView
            android:id="@+id/foodNtrIrdnt_company_textView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:maxLines="1"
            android:text="@{model.company}"
            android:textSize="12sp"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_description_kor_textView"
            tools:text="업체 명" />

        <TextView
            android:id="@+id/foodNtrIrdnt_serving_weight_textView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dp"
            android:layout_marginTop="30dp"
            android:layout_marginEnd="10dp"
            android:text="@{@string/serving_weight_desc_info(model.servingCount, model.servingWeight * model.servingCount)}"
            android:textColor="@color/color_on_secondary"
            android:textSize="12sp"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_beginYear_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_company_textView"
            tools:text="1회 제공량" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_carbohydrate_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/carbohydrate"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_protein_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_serving_weight_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_carbohydrate_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/carbohydrate_info(model.carbohydrate * model.servingCount)}"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_carbohydrate_textView"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_carbohydrate_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_carbohydrate_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_protein_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/protein"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_fat_textView"
            app:layout_constraintStart_toEndOf="@+id/foodNtrIrdnt_carbohydrate_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_carbohydrate_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_protein_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/protein_info(model.protein * model.servingCount)}"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_protein_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_protein_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_protein_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_fat_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/fat"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintStart_toEndOf="@+id/foodNtrIrdnt_protein_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_carbohydrate_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_fat_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/fat_info(model.fat * model.servingCount)}"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_fat_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_fat_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_fat_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_sugar_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/sugar"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_salt_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_carbohydrate_info_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_sugar_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/sugar_info(model.sugar * model.servingCount)}"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_sugar_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_sugar_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_sugar_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_salt_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/salt"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_cholesterol_textView"
            app:layout_constraintStart_toEndOf="@+id/foodNtrIrdnt_sugar_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_sugar_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_salt_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/salt_info(model.salt * model.servingCount)}"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_salt_textView"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_salt_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_salt_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_cholesterol_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/cholesterol"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_fat_textView"
            app:layout_constraintStart_toEndOf="@+id/foodNtrIrdnt_salt_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_sugar_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_cholesterol_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/cholesterol_info(model.cholesterol * model.servingCount)}"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_cholesterol_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_cholesterol_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_cholesterol_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_saturatedFattyAcid_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/saturated_fatty_acid"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_transFat_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_description_kor_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_sugar_info_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_saturatedFattyAcid_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/saturated_fatty_acid_info(model.saturatedFattyAcid * model.servingCount)}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_saturatedFattyAcid_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_saturatedFattyAcid_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_saturatedFattyAcid_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_transFat_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/trans_fat"
            app:layout_constraintEnd_toStartOf="@+id/foodNtrIrdnt_calorie_textView"
            app:layout_constraintStart_toEndOf="@+id/foodNtrIrdnt_saturatedFattyAcid_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_saturatedFattyAcid_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_transFat_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/trans_fat_info(model.transFat * model.servingCount)}"
            app:layout_constraintBottom_toBottomOf="@+id/foodNtrIrdnt_saturatedFattyAcid_info_textView"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_transFat_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_transFat_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_transFat_textView" />

        <!-- ========== 구분선 ========== -->

        <TextView
            android:id="@+id/foodNtrIrdnt_calorie_textView"
            style="@style/Theme.CalIngredientFood.Dome.Top.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:backgroundTint="@color/color_on_secondary"
            android:text="@string/calorie"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_fat_textView"
            app:layout_constraintStart_toEndOf="@+id/foodNtrIrdnt_transFat_textView"
            app:layout_constraintTop_toTopOf="@+id/foodNtrIrdnt_saturatedFattyAcid_textView" />

        <TextView
            android:id="@+id/foodNtrIrdnt_calorie_info_textView"
            style="@style/Theme.CalIngredientFood.Dome.Bottom.TextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:backgroundTint="@color/color_on_light_secondary"
            android:text="@{@string/calorie_info(model.calorie * model.servingCount)}"
            app:layout_constraintBottom_toBottomOf="@+id/foodNtrIrdnt_saturatedFattyAcid_info_textView"
            app:layout_constraintEnd_toEndOf="@+id/foodNtrIrdnt_calorie_textView"
            app:layout_constraintStart_toStartOf="@+id/foodNtrIrdnt_calorie_textView"
            app:layout_constraintTop_toBottomOf="@+id/foodNtrIrdnt_calorie_textView" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

 

해당 레이아웃 파일에서 사용되는 Style Resource는 아래와 같습니다.

 

styles.xml

    <!--
    식품 영양정보 상제 페이지(bottomSheet)에 쓰이는 TextView style
    -->
    <style name="Theme.CalIngredientFood.Dome.Top.TextView" parent="Widget.AppCompat.TextView">
        <item name="android:background">@drawable/bg_dome_top_design</item>
        <item name="android:textColor">@color/color_primary</item>
        <item name="android:textSize">13sp</item>
        <item name="android:gravity">center</item>
        <item name="android:padding">3dp</item>
    </style>

    <!--
    식품 영양정보 상제 페이지(bottomSheet)에 쓰이는 TextView style
    -->
    <style name="Theme.CalIngredientFood.Dome.Bottom.TextView" parent="Widget.AppCompat.TextView">
        <item name="android:background">@drawable/bg_dome_bottom_design</item>
        <item name="android:textColor">@color/color_on_light_secondary</item>
        <item name="android:textSize">11sp</item>
        <item name="android:gravity">center</item>
        <item name="android:padding">3dp</item>
    </style>

    <!--
   식품 영양정보 상제 페이지(bottomSheet)의 Rounded corners / NavigationBarColor 설정
   bottomSheetStyle : custom design을 적용
   windowIsFloating : true - dialog가 자식 사이즈만큼 사용 / false : dialog가 전체 화면을 사용
                      false인 경우 navigationBarColor 속성이 적용됨
   navigationBarColor : navigationBar 색상을 설정
   -->
    <style name="Theme.CalIngredientFood.BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
        <item name="bottomSheetStyle">@style/Theme.CalIngredientFood.BottomSheet.Modal</item>
        <item name="android:windowIsFloating">false</item>
        <item name="android:navigationBarColor">@color/color_primary</item>
    </style>

    <!--
    BottomSheet에는 Persistent, Modal 두 종류 존재
    Persistent : 특정 화면의 Layout에 속하도록 하며, Behavior 속성을 설정해야함
    Modal : 안드로이드의 Toast처럼 어디에서나 표시할 수 있고, BottomSheetDialogFragment 사용
    -->
    <style name="Theme.CalIngredientFood.BottomSheet.Modal" parent="Widget.Design.BottomSheet.Modal">
        <item name="android:background">@drawable/bg_bottom_sheet_design</item>
    </style>

 

 

그래픽 또는 이미지를 선택적으로 표현할 수 있는 xml 파일인 drawable은 아래와 같습니다.

 

bg_bottom_sheet_design.xml

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

    <item
        android:top="15dp"
        android:left="150dp"
        android:right="150dp"
        android:height="4dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/color_shadow_dark" />
            <corners
                android:radius="10dp" />
        </shape>
    </item>
</layer-list>

 

bg_dome_top_design.xml

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

 

bg_dome_bottom_design.xml

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

    <item
        android:top="-2dp">
        <shape>
            <solid android:color="@android:color/transparent" />

            <stroke
                android:width="1dp"
                android:color="@color/color_primary" />
            <corners
                android:bottomLeftRadius="5dp"
                android:bottomRightRadius="5dp" />
        </shape>
    </item>

</layer-list>

 

layout, style, drawable에서 사용되는 color, string resource는 아래와 같습니다.

<string name="serving_weight_desc_info">%s회 제공량 : %s(g)</string>
<string name="begin_year_desc_info">구축년도 : %s년</string>
    
<string name="calorie">칼로리</string>
<string name="carbohydrate">탄수화물</string>
<string name="protein">단백질</string>
<string name="fat">지방</string>
<string name="sugar">당류</string>
<string name="salt">나트륨</string>
<string name="cholesterol">콜레스테롤</string>
<string name="saturated_fatty_acid">포화지방산</string>
<string name="trans_fat">트랜스지방산</string>

<string name="calorie_info">%1$.2f(kcal)</string>
<string name="carbohydrate_info">%1$.2f(g)</string>
<string name="protein_info">%1$.2f(g)</string>
<string name="fat_info">%1$.2f(g)</string>
<string name="sugar_info">%1$.2f(g)</string>
<string name="salt_info">%1$.2f(mg)</string>
<string name="cholesterol_info">%1$.2f(mg)</string>
<string name="saturated_fatty_acid_info">%1$.2f(g)</string>
<string name="trans_fat_info">%1$.2f(g)</string>
<color name="color_primary">#EFEEEE</color>
<color name="color_shadow_dark">#D1CDC7</color>
<color name="color_on_secondary">#585858</color>
<color name="color_on_light_secondary">#787878</color>

 

3. BottomSheetDialogFragment를 상속받아 정의

 

FoodNtrIrdntBottomSheet.kt

/**
 * Gon [22.01.24] : Google Material Design에서 제공하는 BottomSheetDialogFragment를 상속받아 구현한 FoodNtrIrdntBottomSheet
 *                  internal constructor() : 내부 생성자가 있는 class에서 접근제한자를 internal로 하여 외부에선 개체를 만들지 못하게하는 효과
 */
class FoodNtrIrdntBottomSheet internal constructor(private val model: FoodNtrIrdntModel) : BottomSheetDialogFragment() {

    companion object {
        /**
         * Gon [22.01.24] : 여러 번 표시되지 않도록 SingleTon Pattern으로 구현
         */
        fun newInstance(model: FoodNtrIrdntModel) : FoodNtrIrdntBottomSheet =
            FoodNtrIrdntBottomSheet(model).also {
                DebugLog.d("called : ${hashCode()}")
            }
    }

    /**
     * Gon [22.01.24] : BottomSheetDialogFragment의 테마 설정 (Theme.CalIngredientFood.BottomSheetDialog)
     */
    override fun getTheme(): Int = R.style.Theme_CalIngredientFood_BottomSheetDialog

    private lateinit var binding : BottomSheetFoodNtrIrdntBinding

    private fun getDataBinding(): BottomSheetFoodNtrIrdntBinding =
        BottomSheetFoodNtrIrdntBinding.inflate(layoutInflater)

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = getDataBinding()
        binding.lifecycleOwner = this
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        binding.model = this.model
    }
}

 

4. 사용

사용 시엔 FoodNtrIrdntBottomSheet의 인스턴스를 생성해 show() 메서드를 통해 FragmentManager와 TAG를 넘기면 됩니다. Constants 파일에 따로 TAG를 관리하거나 하드코딩하면 됩니다.

FoodNtrIrdntBottomSheet.newInstance(model)
	.show(requireActivity().supportFragmentManager, Constants.BOTTOM_SHEET_TAG)

 

디자인과 관련된 코드들 중 공통으로 사용될 수 있는 부분들을 include 등을 이용해서 수정하면 더 깔끔하고 보기좋게 만들 수 있을 것 같아 기회가 된다면 수정해서 변경해보겠습니다.


 

 

2️⃣Bottomsheetbehavior

CoordinatorLayout에서 자식 뷰에 대한 플러그인 중 하나이기 때문에 CoordinatorLayout으로 감싸진 형태여야 합니다.

 

자식 뷰에 아래와 같이 속성을 설정해주면 하단에서 펼쳐지듯이 동작하도록 할 수 있습니다.

//Behavior를 적용하기 위해선 id가 필요
android:id="@+id/bottomsheet"

//하단 시트로 사용할 View가 기본적으로 미리보기가 가능하도록 사용
//미리보기 비활성화( true ) | 미리보기 활성화( false )
app:behavior_hideable="false"

//미리보기를 활성화한 경우 기본적으로 노출될 값
app:behavior_peekHeight="50dp"

//behavior를 적용시키는 코드입니다.
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

 

이외에 추가적인 속성은 디벨로퍼 사이트에서 XML attributes에서 확인할 수 있습니다.

https://developer.android.com/reference/com/google/android/material/bottomsheet/BottomSheetBehavior

 

BottomSheetBehavior  |  Android Developers

From class androidx.coordinatorlayout.widget.CoordinatorLayout.Behavior boolean blocksInteractionBelow(CoordinatorLayout arg0, V arg1) boolean getInsetDodgeRect(CoordinatorLayout arg0, V arg1, Rect arg2) int getScrimColor(CoordinatorLayout arg0, V arg1) fl

developer.android.com

 

 

View Controller에서 Behavior를 지정해주면 기본적인 준비는 끝났습니다.

val sheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottomsheet))
sheetBehavior.isGestureInsetBottomIgnored = true

 

여기에 Bottomsheetbehavior의 상태값에 따라 변화를 주고 싶다면 아래와 같이 addBottomSheetCallback을 통해 이벤트 알림을 위한 콜백을 추가해 이용하면 됩니다.

	sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
            override fun onSlide(bottomSheet: View, slideOffset: Float) {
                //slideOffest 0.0 ~ 1.0(접힘 ~ 펼침)
                //위 값을 이용해 펼쳐질 수록 디자인을 변경하는 등의 작업을 하면 됩니다.
            }

            override fun onStateChanged(bottomSheet: View, newState: Int) {
                when (newState) {
                    STATE_EXPANDED -> {
                        //완전히 펼쳐진 상태
                    }
                    STATE_DRAGGING -> {
                        //드래그 되고있는 상태
                    }
                    STATE_SETTLING -> {
                        //드래그되가 고정된 상태
                    }
                    STATE_HALF_EXPANDED -> {
                        //절반이 펼쳐진 상태
                    }
                    STATE_COLLAPSED -> {
                        //접혀있는 상태
                    }
                    STATE_HIDDEN -> {
                        아래로 숨겨져 보이지 않는 상태
                    }
                }
            }
        })