今天我們要做的就是,當使用者一進到我們的App時,就可以看到除了自己上架的其他訊息!
先上圖
我們這次做的RecylcerView跟上次做出小小的區別,我們這次做的比較有質感一點
我們首先要建立Adapter,而基本上跟上一次的HomeAdapter一樣,要注意的是我們在onCreateViewHolder的地方有換寫法,可以讓我們Recyclerview的item可以調間距。
class DashboardAdapter(private val fragment: DashboardFragment): ListAdapter<Invitation, DashboardAdapter.DashboardViewHolder>(DiffCallback){
class DashboardViewHolder(val binding: DashboardInvitationItemListBinding): RecyclerView.ViewHolder(binding.root){
fun bind(item: Invitation){
binding.invitation = item
binding.executePendingBindings()
Constant.loadPetImage(item.pet_image,binding.ivDashboardInvitationItemListImage)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DashboardViewHolder {
val binding: DashboardInvitationItemListBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.context),
R.layout.dashboard_invitation_item_list,parent,false)
return DashboardViewHolder(binding)
}
override fun onBindViewHolder(holder: DashboardViewHolder, position: Int) {
val model = getItem(position)
holder.bind(model)
//這邊一樣設定OnClick事件,並把我們選擇的item傳到viewModel
holder.itemView.setOnClickListener{
fragment.addSelectedInvitationToViewModel(model)
}
}
//會幫我們判斷list是否一樣
companion object DiffCallback: DiffUtil.ItemCallback<Invitation>(){
override fun areItemsTheSame(oldItem: Invitation, newItem: Invitation): Boolean {
return oldItem === newItem
}
override fun areContentsTheSame(oldItem: Invitation, newItem: Invitation): Boolean {
return oldItem.id == oldItem.id
}
}
}
這時候我們可以看到紅字,也就是我們傳進DashboardFragment裡面的funtion!
所以我們就要在Fragment裡面新增以下
原則上這邊就跟我們在HomeFragment裡面做的點擊事件一樣,把我們的livedata資料更新,讓我們在InvitationDetailFragment觀測Livedata
fun addSelectedInvitationToViewModel(invitation: Invitation) {
matchingViewModel.addSelectedInvitationToLiveData(invitation)
nav.navigate(R.id.action_navigation_dashboard_to_invitationDetailFragment)
}
★別忘了要在navigation裡面連連看喔,不然我們沒辦法透過id來導航。
接下來來實例化我們的Adapter,並且在我們的onCreateView呼叫
private fun setAdapter() {
//指定我們的layoutManager為GridLayoutManager,第一個參數 context,第二個則是一行幾個item
binding.rvDashboardFragment.layoutManager = GridLayoutManager(requireContext(), 2)
dashboardAdapter = DashboardAdapter(this)
//讓我們item有新增或減少時,item的size不會改變,讓RecyclerView不用重新計算大小
binding.rvDashboardFragment.setHasFixedSize(true)
binding.rvDashboardFragment.adapter = dashboardAdapter
}
LayoutManager,我們可以用以下方是來調整排版
★ 對於時做有興趣的小夥伴們可以參考這篇文章
https://givemepass.blogspot.com/2016/09/recyclerview-layoutmanager.html
在過來就是我們的Layout啦!
別忘了我們的recyclerview要有兩個layout
所以我們先在fragment_dashboard_xml 新增以下,讓它範圍佔好占滿
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_dashboard_fragment"
android:layout_width="match_parent"
android:layout_marginTop="20dp"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
因為我們這次會需要用到CardView,顧名思義它就是類似卡片的效果,看起來會比較立體
我們要先去gradle新增
implementation "androidx.cardview:cardview:1.0.0"
主要用法就是把它包在view外面,可以直接在cardView設定以下
★ 參考文章:https://ithelp.ithome.com.tw/articles/10249805
dimen
<dimen name="dashboard_cardView_radius">8dp</dimen>
<dimen name="dashboard_cardView_margin">8dp</dimen>
<dimen name="dashboard_image_height">100dp</dimen>
color
<color name="item_background">#ebf6f8</color>
新增dashboard_invitation_item_list.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">
//一樣我們在這邊設定databinding,讓我們在Adapter綁定
<data>
<variable
name="invitation"
type="com.example.petsmatchingapp.model.Invitation" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/item_background"
android:layout_margin="@dimen/dashboard_cardView_margin"
app:cardCornerRadius="@dimen/dashboard_cardView_radius">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_dashboard_invitation_item_list_image"
android:layout_width="match_parent"
android:layout_height="@dimen/dashboard_image_height"
android:scaleType="center">
</ImageView>
<com.example.petsmatchingapp.utils.JFTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/home_fragment_pet_type(invitation.pet_type,invitation.pet_type_description)}"/>
<com.example.petsmatchingapp.utils.JFTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/home_fragment_pet_place(invitation.area,invitation.date_place)}"/>
<com.example.petsmatchingapp.utils.JFTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/home_fragment_pet_time(invitation.date_time)}"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
來到 MatchingViewModel新增,一樣透過新增到livedata的方式讓我們UI層可以觀察
我們希望我們的DashboardFragment裡面的資料不要看到自己PO出來的資料,這樣才不會導致自己約自己的荒謬行為!
//設定我們的livedata讓我們好觀察
private val _allInvitationList = MutableLiveData<List<Invitation>>()
val allInvitationList: LiveData<List<Invitation>>
get() = _allInvitationList
fun getAllInvitation(userID: String,fragment: DashboardFragment){
Firebase.firestore.collection(Constant.INVITATION)
//我們直接用get拿到所有資料,之後再來篩
.get()
.addOnSuccessListener {
val list = mutableListOf<Invitation>()
for (i in it.documents){
val model = i.toObject(Invitation::class.java)
//我們這時候要確認我們的model的user_id跟我們currentUserId是不一致的
if (model != null && model.user_id != userID){
list.add(model)
}
}
_allInvitationList.postValue(list)
}
.addOnFailureListener {
fragment.getAllInvitationFail(it.toString())
}
}
一樣我們可以看到幾個紅字,也就是我們要新增我們的get失敗,回到我們的Fragment
fun getAllInvitationFail(e: String) {
showSnackBar(e, true)
}
並且在onCreateView呼叫它,在最初的時候我們就先呼叫!
accountViewModel.getCurrentUID()?.let { matchingViewModel.getAllInvitation(it,this) }
最後在觀測我們的allInvitationList,如果有變更的時候,就把list丟進我們的adapter
matchingViewModel.allI![https://ithelp.ithome.com.tw/upload/images/20210928/201380171J3BZgpzoE.png](https://ithelp.ithome.com.tw/upload/images/20210928/201380171J3BZgpzoE.png)nvitationList.observe(viewLifecycleOwner, Observer {
dashboardAdapter.submitList(it)
})
別忘了我們先在如果點進InvitationDetailFragment的時候會把ActionBar跟bottomNavigation隱藏,所以我們要在onResume呼叫。
if (requireActivity().findViewById<BottomNavigationView>(R.id.nav_view).visibility == View.GONE) {
requireActivity().findViewById<BottomNavigationView>(R.id.nav_view).visibility =
View.VISIBLE
}
★切記不能在onCreateView裡面呼叫喔! 因為在onCreateView是在Fragment初次創建時調用。但此刻Activity還沒有創建完成,因為我們的Fragment也是Activity創建的一部分。所以無法獲取Activity的一些資源
Fragment生命週期對應Activity
參考文章&圖片來源:https://www.aiwalls.com/android軟體開發教學/08/23989.html
今天就先這樣啦! 明天會新增一些篩選的選單,讓我們當今天資料比較多的時候,可以讓user去快速找到想要的約散!
成品!!