Developer Geek

Android BottomSheetDialogFragment in Kotlin 본문

안드로이드

Android BottomSheetDialogFragment in Kotlin

devGeek 2022. 3. 2. 22:20
반응형

BottomSheetDialogFragment란...

BottomSheetDialogFragmentBottomSheetDialog를 이용하여 화면 하단에서 올라오는 DialogFragmtne의 버전 중 하나이다,

실행화면

구입한 상품에 대한 상세 내역을 확인할 수 있도록 BottomSheetDailogFragment을 이용하여 화면을 만들어 본다. 참고). DataBinding을 사용한다.

프로젝트 구조(이미지)

Code - Example

build.gradle(Module) - DataBinding 추가

dataBinding{ enabled = true } 을 추가한다.

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.example.bottomsheetdialogfragmentexample"
        minSdk 26
        targetSdk 31
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    dataBinding{
        enabled = true
    }
}

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.constraintlayout.widget.ConstraintLayout 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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var adapter: ProductAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        adapter = ProductAdapter(this)
        binding.recyclerView.adapter = adapter
        adapter.submitList(getProducts())

    }

    private fun getProducts(): ArrayList<ProductModel> {
        var list = ArrayList<ProductModel>()

        list.add(ProductModel(id = 1, name ="상품 1", price ="19,900원", date ="2022.03.01", cnt = 1, option ="옵션-1"))
        list.add(ProductModel(id = 2, name ="상품 2", price ="29,900원", date ="2022.03.01", cnt = 2, option ="옵션-1"))
        list.add(ProductModel(id = 3, name ="상품 3", price ="39,900원", date ="2022.03.02", cnt = 3, option ="옵션-2"))
        list.add(ProductModel(id = 4, name ="상품 4", price ="49,900원", date ="2022.03.03", cnt = 4, option ="옵션-3"))

        return list
    }
}

ProductModel.kt - 상품 데이터 클래스

data class ProductModel(
    val id: Long,
    val name: String,
    val price: String,
    val date: String,
    val cnt: Int,
    val option: String,
)

list_item.xml - 상품 리스트 아이템 Layout

<?xml version="1.0" encoding="utf-8"?>

<layout>

    <data>

        <variable
            name="product"
            type="com.example.bottomsheetdialogfragmentexample.ProductModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout 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"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/image_view"
            android:layout_width="75dp"
            android:layout_height="75dp"
            android:layout_marginTop="20dp"
            android:src="@mipmap/ic_launcher"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/product_name_text_view"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="20dp"
            android:text="@{product.name}"
            android:textColor="@color/black"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot"
            app:layout_constraintStart_toEndOf="@id/image_view"
            app:layout_constraintTop_toTopOf="@id/image_view"
            tools:text="상품명" />


        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/product_info_button"
            android:layout_width="77dp"
            android:layout_height="33dp"
            android:background="#ECECEC"
            android:text="제품 상세"
            android:textSize="12sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="@id/price_text_view"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot" />

        <TextView
            android:id="@+id/price_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.price}"
            android:textColor="@color/black"
            app:layout_constraintBottom_toBottomOf="@id/image_view"
            app:layout_constraintStart_toStartOf="@id/product_name_text_view"
            tools:text="19,900원" />

        <View
            android:layout_width="0dp"
            android:layout_height="1dp"
            android:layout_marginTop="20dp"
            android:background="#707070"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/image_view" />


        <View
            android:id="@+id/divider_start_pivot"
            android:layout_width="1dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias=".05"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <View
            android:id="@+id/divider_end_pivot"
            android:layout_width="1dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias=".95"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

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

ProductAdapter.kt - 상품 아이템 리스트 어댑터

참고).ListAdapter를 사용한다.

class ProductAdapter(val fa: FragmentActivity) :
    ListAdapter<ProductModel, ProductAdapter.ViewHolder>(diffUtil) {

    inner class ViewHolder(var binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(item: ProductModel) {
            binding.apply {
                product = item
                productInfoButton.setOnClickListener {
                    val productInfoFragment = ProductInfoBottomSheetDialogFragment(item)
                    productInfoFragment.show(fa.supportFragmentManager, "TAG")
                }
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            ListItemBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(currentList[position])
    }

    companion object {
        val diffUtil = object : DiffUtil.ItemCallback<ProductModel>() {
            override fun areItemsTheSame(oldItem: ProductModel, newItem: ProductModel): Boolean {
                return oldItem.id == newItem.id
            }

            override fun areContentsTheSame(oldItem: ProductModel, newItem: ProductModel): Boolean {
                return oldItem == newItem
            }
        }
    }

}

fragment_product_info_bottom_sheet_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
            name="product"
            type="com.example.bottomsheetdialogfragmentexample.ProductModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout 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"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:context=".ProductInfoBottomSheetDialogFragment">

        <TextView
            android:id="@+id/product_name_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{product.name}"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="상품명" />

        <View
            android:id="@+id/divider_product_info"
            android:layout_width="0dp"
            android:layout_height="1dp"
            android:layout_marginTop="18dp"
            android:background="#707070"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/product_name_text_view" />

        <TextView
            android:id="@+id/date_title_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="구입 날짜"
            android:textSize="13sp"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/divider_product_info" />

        <TextView
            android:id="@+id/date_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="20dp"
            android:text="@{product.date}"
            app:layout_constraintBottom_toBottomOf="@id/date_title_text_view"
            app:layout_constraintStart_toEndOf="@id/date_title_text_view"
            app:layout_constraintTop_toTopOf="@id/date_title_text_view"
            tools:text="2022.03.02" />

        <TextView
            android:id="@+id/count_title_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="수량"
            android:textSize="13sp"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/date_text_view" />

        <TextView
            android:id="@+id/count_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(product.cnt)}"
            app:layout_constraintBottom_toBottomOf="@id/count_title_text_view"
            app:layout_constraintStart_toStartOf="@id/date_text_view"
            app:layout_constraintTop_toTopOf="@id/count_title_text_view"
            tools:text="333" />

        <TextView
            android:id="@+id/option_title_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="옵션"
            android:textSize="13sp"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/count_text_view" />

        <TextView
            android:id="@+id/option_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.option}"
            app:layout_constraintBottom_toBottomOf="@id/option_title_text_view"
            app:layout_constraintStart_toStartOf="@id/date_text_view"
            app:layout_constraintTop_toTopOf="@id/option_title_text_view"
            tools:text="옵션 설명" />

        <View
            android:id="@+id/divider_product_info_bottom"
            android:layout_width="0dp"
            android:layout_height="2dp"
            android:layout_marginTop="18dp"
            android:background="@color/black"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/option_title_text_view" />

        <TextView
            android:id="@+id/total_price_title_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="총 결제 금액"
            android:textColor="@color/black"
            android:textSize="20sp"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/divider_product_info_bottom" />

        <TextView
            android:id="@+id/total_price_text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{product.price}"
            android:textColor="@color/black"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="@id/total_price_title_text_view"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot"
            app:layout_constraintTop_toTopOf="@id/total_price_title_text_view"
            tools:text="20,000원" />

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/close_button"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_marginTop="20dp"
            android:text="확인"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="@id/divider_end_pivot"
            app:layout_constraintStart_toStartOf="@id/divider_start_pivot"
            app:layout_constraintTop_toBottomOf="@id/total_price_title_text_view" />

        <View
            android:id="@+id/divider_start_pivot"
            android:layout_width="1dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias=".05"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <View
            android:id="@+id/divider_end_pivot"
            android:layout_width="1dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias=".95"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ProductInfoBottomSheetDialogFragment.kt

class ProductInfoBottomSheetDialogFragment(val item: ProductModel) : BottomSheetDialogFragment() {
    private lateinit var binding: FragmentProductInfoBottomSheetDialogBinding
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        binding =
            FragmentProductInfoBottomSheetDialogBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.apply {
            product = item
            closeButton.setOnClickListener {
                dismiss()
            }
        }

    }
}
반응형
Comments