[android/kotlin] firebase-firestore recyclerView Filter하기

남윤희·2023년 10월 20일
0

kotlin

목록 보기
19/25

Dialog - chipGroup으로 category를 선택 한 뒤 Addapter에서 filter 하기

#각 파일 마다 중요한 점만 정리 해 두고 자세한 사항은 코드주석으로 남겼다.


1. Dialog Layout을 작성한다.

category_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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.chip.ChipGroup
        android:id="@+id/chipgroup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="20dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2"
        app:singleSelection="true">

        <com.google.android.material.chip.Chip
            android:id="@+id/cloths_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="의류"
            android:textSize="12sp" />

        <com.google.android.material.chip.Chip
            android:id="@+id/machine_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="가전제품"
            android:textSize="12sp" />


        <com.google.android.material.chip.Chip
            android:id="@+id/sport_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="스포츠"
            android:textSize="12sp" />

        <com.google.android.material.chip.Chip
            android:id="@+id/art_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="예술"
            android:textSize="12sp" />

        <com.google.android.material.chip.Chip
            android:id="@+id/book_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="독서"
            android:textSize="12sp" />

        <com.google.android.material.chip.Chip
            android:id="@+id/beauty_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="뷰티"
            android:textSize="12sp" />

        <com.google.android.material.chip.Chip
            android:id="@+id/toy_chip"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:checkable="true"
            android:text="문구"
            android:textSize="12sp" />
    </com.google.android.material.chip.ChipGroup>
    

</androidx.constraintlayout.widget.ConstraintLayout>

2. DialogFregment를 작성한다.

  • interface CategorySelectionListener {
    fun onCategorySelected(category: String)
    } 리스너를 달아줘서 카테고리 변환을 감지하고,

  • fun setCategorySelectionListener(listener: CategorySelectionListener) {
    categorySelectionListener = listener
    }로 선택 된 category 값을 전달한다.

DialogFragment

class CategoryDialogFragment : DialogFragment() {
    private lateinit var binding: FragmentCategoryDialogBinding

    //카테고리 선택 이벤트 리스닝
    interface CategorySelectionListener {
        fun onCategorySelected(category: String)
    }

    private var categorySelectionListener: CategorySelectionListener? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentCategoryDialogBinding.inflate(inflater, container, false)
        return binding.root
    }

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

        binding.chipgroup.setOnCheckedChangeListener { group, checkedId ->
            val selectedChip = view.findViewById<Chip>(checkedId)
            val selectedCategory = selectedChip.text.toString()
            //selected된 값 전달
            categorySelectionListener?.onCategorySelected(selectedCategory)
            dismiss()
        }
    }

    //home으로 기능 내보내기
    fun setCategorySelectionListener(listener: CategorySelectionListener) {
        categorySelectionListener = listener
    }
}

3.Adapter 설정하기

  • 기존 RecyclerView에 들어간 List와 Filter된 List가 필요하다.
  • Default 값을 filter 된 List로 두고, 선택되지 않았을 때 조건을 추가한다.
  • 그 함수를 데이터를 받아오는 곳에서 적용한다.

Adapter



class HomeAdapter(private val context: Context):
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private var homeDataItem: ArrayList<PostData> = ArrayList()
    private var filteredDataItem: List<PostData> = ArrayList()

    fun postDataFromFirestore() {

        val fireStore = FirebaseFirestore.getInstance()
        fireStore.collection("Post").get()
            .addOnSuccessListener { result ->

                Log.d("postDataFromFirestore", "nyh postDataFromFirestore suc: $result")

                val newData = mutableListOf<PostData>()
                for (i in result) {
                    if (i.exists()) {
                        Log.d("postDataFromFirestore", "nyh postDataFromFirestore suc: ${newData.size}, $newData")
                        val postData = i.toObject(PostData::class.java)
                        newData.add(postData)
                    }
                }
                homeDataItem.clear()
                homeDataItem.addAll(newData)
                filterByCategory("")
                notifyDataSetChanged()
            }
            .addOnFailureListener { e ->

                Log.e("FirestoreAdapter", "Error getting documents: $e")
            }
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = WriteItemBinding.inflate(inflater,parent,false)
        return HomeHolder(binding)
    }

    override fun getItemCount(): Int {
        return filteredDataItem.size
    }


    fun filterByCategory(category: String) {
        if (category.isEmpty()) {
            Log.d("nyh", "filterByCategory: ${filteredDataItem.size}")
            filteredDataItem = homeDataItem // 전체 데이터 표시
        } else {
            filteredDataItem = homeDataItem.filter { it.category == category }
        }
        notifyDataSetChanged()
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val homeItem = homeDataItem[position]
        val homeHolder = holder as HomeHolder
        val storage = Firebase.storage
        val storageRef = storage.getReference("image")
        val fileName = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
        val mountainRef = storageRef.child("${fileName}.png")

        homeHolder.title.text = homeItem.title
        homeHolder.subtitle.text = homeItem.mainText
        homeHolder.category.text = homeItem.category
        homeHolder.value.text = homeItem.value.toString()

    }


    inner class HomeHolder(val binding : WriteItemBinding):
        RecyclerView.ViewHolder(binding.root) {

        val title  = binding.writeTittle
        val subtitle = binding.writeSubtittle
        val value = binding.writePrice
        val category = binding.writeCategory
        val image = binding.writeImage
    }


}

4. View에 적용하기

  • filter 된 값을 받아오는 함수
  • dialog에 있는 listner

위 두가지를 추가한다.

class HomeFragment : Fragment(), CategoryDialogFragment.CategorySelectionListener {
    private lateinit var binding: FragmentHomeBinding
    private lateinit var mContext: Context
    private lateinit var homeAdapter: HomeAdapter
    private val viewModel: HomeViewModel by viewModels()
    private var selectedCategory: String = ""


    override fun onAttach(context: Context) {
        super.onAttach(context)
        mContext = context
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onResume() {
        super.onResume()

        homeAdapter.postDataFromFirestore()
        Log.d("HomeFrag onResume", "nyh backbtnsuc??")

        viewModel.refreshData.observe(viewLifecycleOwner) { refresh ->
            if (refresh) {
                homeAdapter.postDataFromFirestore()
                viewModel.onRefreshComplete()
            }
        }
    }

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

        Log.d("Homefrag", "nyh backbtnsuc??")

        mContext = requireContext()
        homeAdapter = HomeAdapter(mContext)

        binding.homeRecycle.layoutManager =
            LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)
        binding.homeRecycle.adapter = homeAdapter

        binding.btnFilter.setOnClickListener {
            val filterDialogFragment = CategoryDialogFragment()
            //다이얼로그에있는 리스너를 달아준다
            filterDialogFragment.setCategorySelectionListener(this)
            filterDialogFragment.show(childFragmentManager, "filter_dialog_tag")
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    override fun onCategorySelected(category: String) {
        selectedCategory = category

        // 선택된 카테고리로 항목을 filter한다
        if (category.isNotEmpty()) {
            homeAdapter.filterByCategory(category)
            Log.d("HomeFrag", "nyh category = $category")
        } else {
            Log.d("nyh", "onCategorySelected: gg")
        }
        homeAdapter.notifyDataSetChanged()
    }
}

작성자는 Adapter에서 초기설정함수를 데이터를 받아오는 곳에서 적용하는 부분을 놓쳐서 꽤 오랜 시간이 걸렸따..😂

profile
안드로이드 주니어 개발자

0개의 댓글