今天要來帶大家看一下搜尋資料,Firestore最簡單的方式就是直接透過get()來拿到資料,但是如果我們今天需要增加一些篩選條件呢? 如我們要選取地區,我們總不希望我們看到的資料都是離我們很遠的地方吧!! Let go~
這邊layout就不貼囉,因為貼了的話太佔版面了,我怕礙了大家的眼睛!
LinearLayout裡面會塞checkBox,然後我們的間距跟string內容這次就不貼囉!
並且我們要新增checkBox的background,讓它被點擊後是有不同樣式的
新增後一樣到 checkBox的background來指定!
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<shape android:shape="rectangle">
<corners android:radius="10dp"/>
<gradient android:startColor="#84C1FF"
android:endColor="#4EFEB3"/>
</shape>
</item>
<item android:state_checked="false">
<shape android:shape="rectangle">
<corners android:radius="10dp"/>
<gradient android:startColor="@color/light_pewter_blue"
android:endColor="@color/pewter_blue"/>
</shape>
</item>
</selector>
首先你要去xml,把每一個checkBox新增id,並且把它加入到list,而這個list裡面的type會是checkBox,所以我們可以透過for迴圈來判斷哪一些checkBox有被點擊。
來到SearchFragment來新增以下的funtion
//我們在class新增
private lateinit var areaCheckedList: MutableList<String>
private fun getAreaCheckedList(){
//list裡面放所有的checkBox的id
val list = listOf<CheckBox>(binding.cbCityKeelung,binding.cbCityTaipei,binding.cbCityNewTaipei,binding.cbCityTaoyuan,binding.cbCityXinzhu,binding.cbCityXinzhuCounty
,binding.cbCityMiaoli,binding.cbCityMiaoliCounty,binding.cbCityTaichung,binding.cbCityZhanghua,binding.cbCityZhanghuaCounty,binding.cbCityNantou,binding.cbCityNantouCounty
,binding.cbCityYunlinCounty,binding.cbCityJiayi,binding.cbCityJaiyiCounty,binding.cbCityTainan,binding.cbCityGaoxiong,binding.cbCityPingtung,binding.cbCityPingtungCounty
,binding.cbCityYilan,binding.cbCityYilanCounty,binding.cbCityHualien,binding.cbCityHualienCounty,binding.cbCityTaidong,binding.cbCityTaidongCounty,binding.cbCityPenghuCounty
,binding.cbCityLudao,binding.cbCityLanyu,binding.cbCityJinmen,binding.cbCityMatus,binding.cbCityLianjiang)
//建立一個空的list,該list宣告在class下方,讓我們可以等等直接傳給viewModel
areaCheckedList = mutableListOf<String>()
for (i in list){
if (i.isChecked){
//透過i.text.toString()來拿到我們在xml裡面設定的text
areaCheckedList.add(i.text.toString())
}
}
}
petType的方式也是同理
private lateinit var petTypeCheckedList: MutableList<String>
private fun getPetTypeCheckedList(){
val list = listOf<CheckBox>(binding.cbPetTypeDog,binding.cbPetTypeCat,binding.cbPetTypeRabbit,binding.cbPetTypeBird,binding.cbPetTypePig,binding.cbPetTypeFish,binding.cbPetTypeOther)
petTypeCheckedList = mutableListOf<String>()
for (i in list){
if (i.isChecked){
petTypeCheckedList.add(i.text.toString())
}
}
}
binding.btnSearchSubmit.setOnClickListener {
getAreaCheckedList()
getPetTypeCheckedList()
matchingViewModel.searchInvitation(areaCheckedList,petTypeCheckedList,this)
}
我們透過when來判斷我們的使用者是否有點擊checkBox
//livedata,我們分兩個livedata,這個是搜尋過後的livedata
private val _dashboardInvitationList = MutableLiveData<List<Invitation>>()
val dashboardInvitationList: LiveData<List<Invitation>>
get() = _dashboardInvitationList
fun searchInvitation(areaList: MutableList<String>,petTypeList: MutableList<String>,fragment: SearchFragment){
when{
//如果地區的地方有點擊但是種類沒點擊
areaList.isNotEmpty()&& petTypeList.isEmpty()->{
Firebase.firestore.collection(Constant.INVITATION)
//透過whereIn來塞入list,來比較資料
.whereIn(Constant.AREA,areaList)
.get()
.addOnSuccessListener{
val list =mutableListOf<Invitation>()
for(i init.documents){
val model = i.toObject(Invitation::class.java)
model?.let{
list.add(it)
}
}
_dashboardInvitationList.postValue(list)
fragment.searchInvitationSuccess(list.size)
}
.addOnFailureListener{
fragment.searchInvitationFail(it.toString())
}
}
//地區沒被點,但是寵物有被點
areaList.isEmpty()&& petTypeList.isNotEmpty()->{
Firebase.firestore.collection(Constant.INVITATION)
.whereIn(Constant.PET_TYPE,petTypeList)
.get()
.addOnSuccessListener{
val list =mutableListOf<Invitation>()
for(i init.documents){
val model = i.toObject(Invitation::class.java)
model?.let{
list.add(model)
}
}
_dashboardInvitationList.postValue(list)
fragment.searchInvitationSuccess(list.size)
}
.addOnFailureListener{
fragment.searchInvitationFail(it.toString())
}
}
//如果地區的地方跟種類都有點擊
areaList.isNotEmpty()&& petTypeList.isNotEmpty()->{
val ref = Firebase.firestore.collection(Constant.INVITATION)
//先搜尋地區,地區符合才進行下一步篩選
ref.whereIn(Constant.AREA,areaList)
.get()
.addOnSuccessListener{
val list =mutableListOf<Invitation>()
for(eachModel init.documents){
val model = eachModel.toObject(Invitation::class.java)
//再用for迴圈來得到地區符合的這些結果裡面,又符合寵物種類的
for(type in petTypeList){
model?.let{
if(model.pet_type == type){
list.add(model)
}
}
}
}
_dashboardInvitationList.postValue(list)
fragment.searchInvitationSuccess(list.size)
}
.addOnFailureListener{
fragment.searchInvitationFail(it.toString())
}
}
//需要加入else,checkBox全部都沒有被點擊
else ->{
Firebase.firestore.collection(Constant.INVITATION)
.get()
.addOnSuccessListener{
val list =mutableListOf<Invitation>()
for(i init.documents){
val model = i.toObject(Invitation::class.java)
model?.let{
list.add(model)
}
}
_dashboardInvitationList.postValue(list)
fragment.searchInvitationSuccess(list.size)
}
.addOnFailureListener{
fragment.searchInvitationFail(it.toString())
}
}
}
}
★我們這邊要注意,Firestore搜尋有幾個限制
這也是為什麼我們要area區域跟pet_type區域都有點擊的時候,用for迴圈來新增list。
有興趣的小夥伴們可以參考:https://firebase.google.com/docs/firestore/query-data/queries?hl=zh-cn
並且回到searchFragment來新增以下的funtion
fun searchInvitationSuccess(resultSize: Int){
//我們從viewModel傳回資料,如果回傳的資料是0,我們就說沒有找到資料,如果有則跳回 DashboardFragment
if (resultSize != 0 && findNavController().currentDestination?.id == R.id.searchFragment){
findNavController().navigate(R.id.action_searchFragment_to_navigation_dashboard)
}else{
showSnackBar("沒有找到符合的資料",false)
}
}
fun searchInvitationFail(e: String){
showSnackBar(e,true)
}
因為我們的getAllInvitation(),寫在我們的onCreateView,所以當我們的SearchFragment回來的時候,他又會再叫一次getAllInvitation,這樣就有點資料又會被覆蓋上去,所以這也是為什麼我們需要把searchInvitation的結果放在另一個livedata
改寫一下觀察
//這個資料是我們透過search得到的資料
matchingViewModel.dashboardInvitationList.observe(viewLifecycleOwner, Observer {
dashboardAdapter.submitList(it)
})
//這個則是一開始得到的資料,我們讓它觀測,如果改變後,並且dashboardInvitationList是null的話,才把資料塞到adapter
matchingViewModel.allInvitationList.observe(viewLifecycleOwner, Observer {
if (matchingViewModel.dashboardInvitationList.value == null){
dashboardAdapter.submitList(it)
}else{
Timber.d("dashboardInvitation裡面有資料啦 不用更新")
}
})
這樣就大功告成啦!