1.设计思想
其实当你看到一个布局或界面时,你首先要想怎么实现,用什么控件,当时我第一个想到的就是listview,但listview没有办法实现横向滑动,所以决定用RecycleView,最开始想的是用2个RecycleView(一个横向和一个竖向)。其实这里有一个问题,当滑动竖向RecycleView时,横向RecycleView是不会跟着一起动的,这从用户的角度来看体验肯定不好(开发者可以以用户的角度去开发,这样产品会有更多的用户体验)
最后的设计是,外面有一个顶层竖向RecycleView,横向RecycleView是其中一个Item。
1.准备横向RecycleView的布局
<?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="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/hrecycleview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
2.准备横向RecycleView的Item的布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="169dp">
<TextView
android:id="@+id/text5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imagemap"
android:layout_marginLeft="4dp"
android:layout_marginTop="16dp"
android:text="精选栏目"
/>
<ImageView
android:id="@+id/imagemap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:src="@drawable/shape"
/>
<ImageView
android:id="@+id/imageview"
android:layout_width="239dp"
android:layout_height="143dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="46dp"
android:src="#ad226bff" />
<TextView
android:id="@+id/text1"
android:layout_width="215dp"
android:layout_height="36dp"
android:layout_alignTop="@id/imageview"
android:layout_marginLeft="12dp"
android:layout_alignStart="@id/imageview"
android:layout_marginTop="54dp"
android:text="RecycleView实现首页复杂布局效果(横向和竖向)…"
android:textColor="#ffffffff"/>
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text1"
android:layout_marginTop="16dp"
android:layout_alignStart="@id/text1"
android:layout_marginLeft="2dp"
android:text="05-04 15:20 | 9999阅"
android:textColor="#ffffffff"/>
<View
android:layout_width="3dp"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageview"/>
</RelativeLayout>
3.设置横向RecycleView的适配器
class SecondAdapter(val datalist1: List<DateMessage>) :
RecyclerView.Adapter<SecondAdapter.MyViewHolder>() {
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val text1 = view.findViewById<TextView>(R.id.text1)
val text2 = view.findViewById<TextView>(R.id.text2)
val text5 = view.findViewById<TextView>(R.id.text5)
val imagemap = view.findViewById<ImageView>(R.id.imagemap)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item2, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
when (position) {
0 -> {
holder.text5.visibility = View.VISIBLE
holder.imagemap.visibility = View.VISIBLE
}
else -> {
holder.text5.visibility = View.GONE
holder.imagemap.visibility = View.GONE
}
}
val data = datalist1[position]
holder.apply {
text1.text = data.title
text2.text = data.desc
}
}
override fun getItemCount(): Int {
return datalist1.size
}
}
这里都是适配器的正常步骤,主要讲解下下面这段代码
when (position) {
0 -> {
holder.text5.visibility = View.VISIBLE
holder.imagemap.visibility = View.VISIBLE
}
else -> {
holder.text5.visibility = View.GONE
holder.imagemap.visibility = View.GONE
}
}
这是通过判断数据的数组下标,如果是第一个数据,就让2个控件为显示状态,相当于标识这是第一个数据(达到置顶效果),以后的数据不显示这2个控件。
4.写一个数据类
data class MultiItem(
//用于标识传入的数据是横向RecycleView还是竖向RecycleView的
var itemType: Int,
//横向 rv
var listData: List<DateMessage>? = null,
//竖向
var data: DateMessage? = null
)
5.总布局
<?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"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:src="@mipmap/map1"
tools:ignore="MissingConstraints"
/>
<EditText
android:id="@+id/edittext1"
android:layout_width="259dp"
android:layout_height="30dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="7dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="60dp"
android:background="@null"
tools:ignore="MissingConstraints" />
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
app:layout_constraintTop_toTopOf="@id/edittext1"
app:layout_constraintLeft_toLeftOf="@id/edittext1"
android:layout_marginTop="7dp"
android:layout_marginLeft="8dp"
android:src="@mipmap/map2"/>
<TextView
android:id="@+id/text2"
android:layout_width="116dp"
android:layout_height="17dp"
app:layout_constraintTop_toTopOf="@id/edittext1"
app:layout_constraintLeft_toLeftOf="@id/edittext1"
android:layout_marginTop="7dp"
android:layout_marginLeft="30dp"
android:text="点击搜索精彩内容"
android:textSize="14sp"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@mipmap/map3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/mainRecycleView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/edittext1"
android:layout_marginTop="54dp"
app:layout_constraintBottom_toTopOf="@id/view"
tools:ignore="MissingConstraints" />
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="48dp"
/>
<ImageView
android:id="@+id/image2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/bottommap1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="25dp"
android:layout_marginBottom="21dp"
tools:ignore="MissingConstraints" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/image2"
app:layout_constraintTop_toBottomOf="@id/image2"
android:text="首页"
android:textSize="11sp"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/image3"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@mipmap/boottommap2"
tools:ignore="MissingConstraints"
app:layout_constraintLeft_toRightOf="@id/image2"
android:layout_marginLeft="49dp"
app:layout_constraintTop_toTopOf="@id/image2"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/image3"
app:layout_constraintTop_toBottomOf="@id/image3"
android:text="今日头条"
android:textSize="11sp"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/image4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/bottommap3"
app:layout_constraintLeft_toRightOf="@id/image3"
android:layout_marginLeft="49dp"
app:layout_constraintTop_toTopOf="@id/image3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/image4"
app:layout_constraintTop_toBottomOf="@id/image4"
android:text="选择"
android:textSize="11sp"/>
<ImageView
android:id="@+id/image5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/image4"
android:layout_marginLeft="49dp"
app:layout_constraintTop_toTopOf="@id/image4"
android:src="@mipmap/bottommap4"
tools:ignore="MissingConstraints" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/image5"
app:layout_constraintTop_toBottomOf="@id/image5"
android:text="行情分析"
android:textSize="11sp"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/image6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints"
android:src="@mipmap/bottommap5"
app:layout_constraintLeft_toRightOf="@id/image5"
android:layout_marginLeft="49dp"
app:layout_constraintTop_toTopOf="@id/image5"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/image6"
app:layout_constraintTop_toBottomOf="@id/image6"
android:text="好友会"
android:textSize="11sp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
6.顶层RecycleView的适配器
class HeadRefactorAdapter(private val dataList: ArrayList<MultiItem>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
private const val BANNER = 1
private const val HORIZONTAL = 2
private const val VERTICAL = 3
}
class HorizontalViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val rvContentList = view.findViewById<RecyclerView>(R.id.hrecycleview)
fun bind(data: List<DateMessage>?) {
if (data.isNullOrEmpty()) {
return
}
rvContentList.apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
adapter = SecondAdapter(data)
}
}
}
class VerticalViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val text1: TextView = view.findViewById(R.id.text1)
private val text2: TextView = view.findViewById(R.id.text2)
private val text3: TextView = view.findViewById(R.id.text3)
private val image: ImageView = view.findViewById(R.id.image)
fun bind(listData: DateMessage?) {
if (listData == null) {
return
}
if (adapterPosition == 0) {
text2.visibility = View.VISIBLE
} else {
text2.visibility = View.GONE
}
text1.text = listData.title
text3.text = listData.desc
image.setImageResource(listData.image)
}
}
override fun getItemViewType(position: Int): Int {
return when (dataList[position].itemType) {
2 -> HORIZONTAL
else -> VERTICAL
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return when (viewType) {
HORIZONTAL -> HorizontalViewHolder(
layoutInflater.inflate(
R.layout.hrecycleview,
parent,
false
)
)
VERTICAL -> VerticalViewHolder(
layoutInflater.inflate(
R.layout.item1,
parent,
false
)
)
else -> {}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is HorizontalViewHolder -> {
holder.bind(dataList[position].listData)
}
is VerticalViewHolder -> {
holder.bind(dataList[position].data)
}
}
}
override fun getItemCount(): Int {
return dataList.size
}
}
这里主要说下 getItemViewType方法,根据传入数据的itemType可以判断出是横向还是竖向的RecycleVIew的数据
override fun getItemViewType(position: Int): Int {
return when (dataList[position].itemType) {
2 -> HORIZONTAL
else -> VERTICAL
}
}
最后在 onCreateViewHolder方法中根据viewType来解析不同的布局,这里如果对 LayoutInflater有疑惑可以看我的另一篇博客LayoutInflater详解
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return when (viewType) {
HORIZONTAL -> HorizontalViewHolder(
layoutInflater.inflate(
R.layout.hrecycleview,
parent,
false
)
)
VERTICAL -> VerticalViewHolder(
layoutInflater.inflate(
R.layout.item1,
parent,
false
)
)
else -> {}
}
}
最后通过onBindViewHolder判断ViewHolder的类型进行数据展示
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is HorizontalViewHolder -> {
holder.bind(dataList[position].listData)
}
is VerticalViewHolder -> {
holder.bind(dataList[position].data)
}
}
}
7.MainActivity的代码
class MainActivity : AppCompatActivity() {
//RecycleView 数据
private val mDataList = ArrayList<MultiItem>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//add hor
mDataList.add(MultiItem(1, listData = listOf(
DateMessage(title = "1RecycleView实现首页复杂布局效果(横向和竖向)…", desc = "05-04 15:20 | 9999阅", image = R.drawable.ic_launcher_background),
DateMessage(title = "2RecycleView实现首页复杂布局效果(横向和竖向)…", desc = "05-04 15:20 | 9999阅", image = R.drawable.ic_launcher_background),
DateMessage(title = "11RecycleView实现首页复杂布局效果(横向和竖向)…", desc = "05-04 15:20 | 9999阅", image = R.drawable.ic_launcher_background),
)))
//add ver
repeat(10){
mDataList.add(MultiItem(1, data = DateMessage(title = "${it}RecycleView实现首页复杂布局效果(横向和竖向)…", desc = "05-04 15:20 | 9999阅", image = R.drawable.ic_launcher_background)))
}
val recyclerview = findViewById<RecyclerView>(R.id.mainRecycleView)
recyclerview.layoutManager = LinearLayoutManager(this)
recyclerview.adapter = HeadRefactorAdapter(mDataList)
}
你没有看错,当你把前面的准备好了,其实主代码不多。
这里解释下,MultiItem的第一个参数就是item,用来区分数据
mDataList.add(MultiItem(1, listData = listOf(
DateMessage(title = “1RecycleView实现首页复杂布局效果(横向和竖向)…”, desc = “05-04 15:20 | 9999阅”, image = R.drawable.ic_launcher_background),
DateMessage(title = “2RecycleView实现首页复杂布局效果(横向和竖向)…”, desc = “05-04 15:20 | 9999阅”, image = R.drawable.ic_launcher_background),
DateMessage(title = “11RecycleView实现首页复杂布局效果(横向和竖向)…”, desc = “05-04 15:20 | 9999阅”, image = R.drawable.ic_launcher_background),
最后祝大家周末快乐!