今天我们要做的就是,当使用者一进到我们的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去快速找到想要的约散!
成品!!
>>: Day.19 「认识 JavaScript 记忆体堆叠、传值 与 传址」 —— JavaScript 物件 与 记忆体
这次要介绍如何「自制假卷轴」 前言// 大学期间有一次网页程序课程的作业需要仿制一个网站 该网站的左...
这篇会介绍图表套件Charts的功能 graphView.leftAxis.enabled = fa...
运算子 运算子即计算、比较、位移用的种种符号,欲知详情请自行google。 让我们先来看看算数运算子...
第 31 天:初始化 LINE BOT on Heroku 事实说来可笑:别试着和任何人讨论任何关於...
Q: 还是Loading吗? A: 一大系列!接下来的样式会比较不同~ 上两篇做完圆圈的Loadi...