介绍:
此部分截取自领券联盟,源码GitHub或者Gitee上面应该有不少,Java和Kotlin都有,我这里采用kotlin
有完整视频讲解以及具体API:点击此处
内容多有不完整,只是记录下自己当下的学习内容,并非教程,可以自行去GitHub或者Gitee或者找视频观看学习
学到了很多,感谢!
1. 在项目的 build.gradle 中添加依赖
implementation 'androidx.recyclerview:recyclerview:1.2.0'
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
// 版本可以去官网查看
2. 需要两个布局( 下面给出完整效果图,下面代码并不完整 )
一个是RecyclerView布局,作为总体骨架,另一个则是RecyclerView列表中的那些子项
总体骨架命名为:fragment_home_pager.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"
tools:ignore="MissingConstraints"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_home_pager_content_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
子项命名为:item_category_page_content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/goods_cover"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@color/black"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/goods_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:ellipsize="end"
android:maxLines="2"
android:text="这是标题内容呀..."
android:textSize="14sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:orientation="horizontal">
<TextView
android:id="@+id/off_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/deep_red"
android:paddingLeft="5dp"
android:paddingTop="2dp"
android:paddingRight="5dp"
android:paddingBottom="2dp"
android:text="天猫"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/off_prise"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="239.90"
android:textColor="@color/origin"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="¥"
android:textColor="@color/grey"
android:textSize="10sp" />
<TextView
android:id="@+id/origin_prise"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2349.90"
android:textColor="@color/grey"
android:textSize="12sp" />
<TextView
android:id="@+id/bought_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="2349·"
android:textColor="@color/grey"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="人已购买"
android:textColor="@color/grey"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
3. 创建一个实体类
data class CategoryPagerContent(
val code: Int,
val `data`: List<Data>,
val message: String,
val success: Boolean
) {
data class Data(
val category_id: Int,
val category_name: Any,
val click_url: String,
val commission_rate: String,
val coupon_amount: Int,
val coupon_click_url: String,
val coupon_end_time: String,
val coupon_info: Any,
val coupon_remain_count: Int,
val coupon_share_url: String,
val coupon_start_fee: String,
val coupon_start_time: String,
val coupon_total_count: Int,
val item_description: String,
val item_id: Long,
val level_one_category_id: Int,
val level_one_category_name: String,
val nick: String,
val pict_url: String,
val seller_id: Long,
val shop_title: String,
val small_images: SmallImages,
val title: String,
val user_type: Int,
val volume: Int,
val zk_final_price: String
)
data class SmallImages(
val string: List<String>
)
}
4. 设置一个RecyclerView适配器
class HomePagerContentAdapter: RecyclerView.Adapter<HomePagerContentAdapter.InnerHolder>() {
private val TAG = " HomePagerContentAdapter "
// 创建一个集合来保存数据
private val contentList: ArrayList<CategoryPagerContent.Data> = ArrayList()
/**
* 创建RecyclerView列表中的那一个个item
* 每创建一个item,都会调用该方法
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InnerHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.item_category_page_content,parent,false)
return InnerHolder(itemView)
}
/**
* 实现具体功能 ,比如给控件赋值,控件的点击事件等
*/
override fun onBindViewHolder(holder: InnerHolder, position: Int) {
// 绑定数据
val itemData = contentList[position]
holder.bindContent(itemData)
logD(TAG, " onBindViewHolder() $itemData")
}
/**
* 通过onCreateViewHolder()方法,获取子布局实例, 也就是找到子布局的控件
* 此方法中的参数itemView就是子项的View,可以通过控件id获取到该控件实例
* 在此方法中可以完成具体功能,也可以在onBindViewHolder()方法中完成
*/
class InnerHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
fun bindContent(itemData: CategoryPagerContent.Data){
// 设置信息
itemView.findViewById<TextView>(R.id.goods_title).text = itemData.title //商品名称
val offPriseTv = itemView.findViewById<TextView>(R.id.off_prise) // 券后价
val offPrise = ((itemData.zk_final_price.toFloat()) - itemData.coupon_amount)
offPriseTv.text = "券后价:${String.format("%.2f", offPrise)}" // 券后价
val originPriseTv = itemView.findViewById<TextView>(R.id.origin_prise) // 原价
originPriseTv.paint.flags = Paint.STRIKE_THRU_TEXT_FLAG // 原价加上删除线(中划线)
originPriseTv.text = itemData.zk_final_price
val offAmountTv = itemView.findViewById<TextView>(R.id.off_amount) // 共省*元
offAmountTv.text = "省${itemData.coupon_amount}元"
val boughtCountTv = itemView.findViewById<TextView>(R.id.bought_count) // 购买人数
boughtCountTv.text = "${itemData.volume}·"
val url = "https://${itemData.pict_url}"
val cover = itemView.findViewById<ImageView>(R.id.goods_cover)
/**
* Glide: 图片加载库
* .with: 当前上下文对象
* .load: 加载图片,提供多种加载方案
* .override: 裁剪图片
* .into: 传入要展示图片的控件
*/
Glide
.with(itemView.context)
.load(url)
.override(cover.layoutParams.width,cover.layoutParams.height)
.into(cover)
}
}
// 子项item的数目
override fun getItemCount(): Int {
return contentList.size
}
/**
* 此处向Activity或者Fragment提供一个方法,让外部传入数据
* 外部获取到该适配器的实例就可以调用该方法,传入数据
* 然后将数据传入List列表中
*/
fun setData(data: List<CategoryPagerContent.Data>) {
contentList.clear() // 首先清空以下保存的数据,用于实时更新新数据
contentList.addAll(data)
notifyDataSetChanged() // 通知更新
}
}
5. 在Fragment中关联Adapter适配器,因为源码中涉及代码较多,删除不相关的代码
主要完成的事情:
1. 获取到适配器的实例
2. 布局中的RecyclerView适配器与自定义的适配器相关联,此处便可展现出无数据的列表了
3. 将具体数据传给自定义的适配器,通过适配器的实例调用类中的方法
class HomePageFragment{
private lateinit var contentAdapter: HomePagerContentAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 1. 获取到适配器的实例
contentAdapter = HomePagerContentAdapter()
// 2. 布局中的RecyclerView适配器与自定义的适配器相关联
binding.rvHomePagerContentList.adapter = contentAdapter
/**
* RecyclerView提供了三种布局管理器即:
* LinearLayoutManager 线性布局管理器, 横向纵向滑动都行
* StaggeredGridLayoutManager 瀑布流布局管理器
* GridLayoutManager 网格布局管理器
*/
binding.rvHomePagerContentList.layoutManager = LinearLayoutManager(context)
/**
* ItemDecoration只有3个重要的重写方法:
* getItemOffsets 用于实现item的上下左右的间距大小
* onDraw 在这个方法里绘制的文字、颜色、图形都会比item更低一层,这些绘制效果如果与item重叠,就会被item遮盖
* onDrawOver 在这个方法绘制的文字、颜色、图形都会比item更高一层,这些绘制效果始终在最上层,不会被遮盖。
*
*/
binding.rvHomePagerContentList.addItemDecoration(object : RecyclerView.ItemDecoration(){
override fun getItemOffsets(outRect: Rect, view: View,
parent: RecyclerView, state: RecyclerView.State) {
// 设置上下间距为10
outRect.top = 10
outRect.bottom = 10
}
})
// setData() 方法为适配器中的方法,调用,并将数据传入
contentAdapter.setData(result.data)
}
companion object{
private const val CATEGORY_TITLE_KEY = "category_title"
private const val CATEGORY_ID_KEY = "category_id"
fun newInstance(data: MainCategoryItem.Data?): HomePageFragment{
val bundle = Bundle()
bundle.putString(CATEGORY_TITLE_KEY, data!!.title)
bundle.putInt(CATEGORY_ID_KEY, data.id)
val fragment = HomePageFragment()
// fragment.arguments: 向fragment传参数
fragment.arguments = bundle
return fragment
}
}
}