TIL) 0915

Hanseul Lee·2022년 9월 15일
0

TIL

목록 보기
11/23

RecyclerView 안에 RecyclerView 만들기

다음과 같이 회원가입 시 약관을 출력하는 화면을 만들어보자!

  • fragment_sign_up.xml
    <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/sign_up_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/list_margin_top"
                android:background="@drawable/custom_signup_edittext"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/sign_up_all_check_txt">
    
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/sign_up_recycler_view"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:padding="15dp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    tools:itemCount="10"
                    tools:listitem="@layout/layout_sign_up_terms_list" />
    
            </androidx.constraintlayout.widget.ConstraintLayout>
  • layout_sign_up_terms_list.xml → 바깥의 RecyclerView
    <?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"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <CheckBox
            android:id="@+id/terms_list_checkbox"
            android:layout_width="@dimen/check_box_size"
            android:layout_height="@dimen/check_box_size"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <TextView
            android:id="@+id/terms_list_txt"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/next_btn_margin"
            android:text="[필수] 만 14세 이상입니다"
            android:textColor="@color/primaryTextColor"
            app:layout_constraintBottom_toBottomOf="@id/terms_list_checkbox"
            app:layout_constraintEnd_toStartOf="@id/terms_list_btn"
            app:layout_constraintStart_toEndOf="@id/terms_list_checkbox"
            app:layout_constraintTop_toTopOf="@id/terms_list_checkbox" />
    
        <ImageView
            android:id="@+id/terms_list_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/icons_next"
            app:layout_constraintBottom_toBottomOf="@id/terms_list_checkbox"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@id/terms_list_checkbox"
            app:tint="@color/primaryTextColor" />
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/terms_list_inner_recycler_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="@id/terms_list_txt"
            app:layout_constraintTop_toBottomOf="@id/terms_list_txt"
            tools:itemCount="3"
            tools:listitem="@layout/layout_sign_up_inner_terms_list" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
  • 바깥 Adapter
    class SignUpTermsAdapter(
        private val context: Context,
        private val mainTermsList: ArrayList<TermsList>,
        private val subTermsList: ArrayList<TermsList>
    ) :
        RecyclerView.Adapter<SignUpTermsAdapter.SignUpTermsViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SignUpTermsViewHolder {
            val view =
                LayoutSignUpTermsListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            return SignUpTermsViewHolder(view)
        }
    
        override fun onBindViewHolder(holder: SignUpTermsViewHolder, position: Int) {
            val curItem = mainTermsList[position]
    
            // checkbox
            if (position >= itemCount) {
                mainTermsList.add(position, TermsList(false, curItem.txt, curItem.dialog, curItem.sub))
            }
            holder.checkBox.isChecked = curItem.check
            holder.checkBox.setOnClickListener {
                curItem.check = holder.checkBox.isChecked
            }
    
            // text
            holder.txt.text = curItem.txt
    
            // dialog
            if (!curItem.dialog) {
                holder.dialogBtn.visibility = View.INVISIBLE
            }
    
            // 리사이클러 뷰 안 리사이클러 뷰
            if (curItem.sub) {
                holder.subTerms.layoutManager =
                    LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
    
                holder.subTerms.adapter = SignUpInnerAdapter(subTermsList)
            }
        }
    
        override fun getItemCount(): Int {
            return mainTermsList.size
        }
    
        inner class SignUpTermsViewHolder(binding: LayoutSignUpTermsListBinding) :
            RecyclerView.ViewHolder(binding.root) {
            val checkBox: CheckBox = binding.termsListCheckbox
            val txt: TextView = binding.termsListTxt
            val dialogBtn: ImageView = binding.termsListBtn
            val subTerms: RecyclerView = binding.termsListInnerRecyclerView
        }
    }
  • layout_sign_up_inner_terms_list.xml → 안쪽의 RecyclerView
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <CheckBox
            android:id="@+id/terms_list_inner_checkbox"
            android:layout_width="@dimen/check_box_size"
            android:layout_height="@dimen/check_box_size"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    
        <TextView
            android:id="@+id/terms_list_inner_txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/next_btn_margin"
            android:text="[선택] 이메일 수신 동의"
            android:textColor="@color/primaryTextColor"
            app:layout_constraintStart_toEndOf="@id/terms_list_inner_checkbox"
            app:layout_constraintTop_toTopOf="@id/terms_list_inner_checkbox"
            app:layout_constraintBottom_toBottomOf="@id/terms_list_inner_checkbox"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
  • 안쪽 어댑터
    class SignUpInnerAdapter(private val dataList: ArrayList<TermsList>) :  RecyclerView.Adapter<SignUpInnerAdapter.SignUpInnerViewHolder>() {
        override fun onCreateViewHolder(
            parent: ViewGroup,
            viewType: Int
        ): SignUpInnerAdapter.SignUpInnerViewHolder {
            val view = LayoutSignUpInnerTermsListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            return SignUpInnerViewHolder(view)
        }
    
        override fun onBindViewHolder(holder: SignUpInnerAdapter.SignUpInnerViewHolder, position: Int) {
            val curItem = dataList[position]
    
            if (position >= itemCount) {
                dataList.add(position, TermsList(false, curItem.txt, curItem.dialog, curItem.sub))
            }
            holder.checkBox.isChecked = curItem.check // data 상태에 따라 체크박스 상태 변경
            holder.checkBox.setOnClickListener {
                curItem.check = holder.checkBox.isChecked
            }
    
            holder.txt.text = curItem.txt
        }
    
        override fun getItemCount(): Int {
            return dataList.size
        }
    
        inner class SignUpInnerViewHolder(binding: LayoutSignUpInnerTermsListBinding) : RecyclerView.ViewHolder(binding.root) {
            val checkBox: CheckBox = binding.termsListInnerCheckbox
            val txt: TextView = binding.termsListInnerTxt
        }
    }
  • 약관 데이터 클래스
    data class TermsList (
        var check: Boolean,
        val txt: String,
        val dialog: Boolean, // dialog 알림이 존재하는지 여부
        val sub: Boolean // inner ReyclerView가 존재하는지 여부
        )

CoordinatorLayout와 CollapsingToolbarLayout으로 뷰끼리 상호작용시키기(스크롤에 따라 나타났다 사라졌다하는 뷰 만들기)

app:layout_scrollFlagsapp:layout_behavior를 활용하면 만들 수 있다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".src.main.home.HomeFragment">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="150dp">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|enterAlways">

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="테스트"
            android:textSize="400sp"/>

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

app:layout_scrollFlags의 속성

  • scroll : 스크롤에 반응해 사라짐
  • enterAlways : 위로 스크롤하면 사라지고 아래로 스크롤하면 나타남
  • enterAlwaysCollapsed : 아래로 스크롤 시 가장 끝에 도달했을 때 다시 나타남. minHeight를 설정하면 그 값에 도달했을 때만 나타남.
  • exitUntilCollapsed : 위로 스크롤하는 동안 minHeight에 도달할 때까지 사라짐. 스크롤 방향이 바뀌면 minHeight에 남아있음.

app:layout_scrollFlags 속성

xml에서 취소선 텍스트 만들기

<RelativeLayout
        android:id="@+id/recommend_list_inner_price_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/list_margin_top">

        <TextView
            android:id="@+id/recommend_list_inner_origin_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="22,000원"
            android:textSize="15sp" />

        <View
            android:layout_width="wrap_content"
            android:layout_height="1dp"
            android:layout_alignStart="@id/recommend_list_inner_origin_price"
            android:layout_alignEnd="@id/recommend_list_inner_origin_price"
            android:layout_centerVertical="true"
            android:background="@color/primaryColor" />

    </RelativeLayout>

0개의 댓글