关于PopupWindow,首先要解决popupwindow在Android7.0显示错误的问题
open class PopupWindowV24 : PopupWindow {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
constructor() : super()
constructor(contentView: View?) : super(contentView)
constructor(width: Int, height: Int) : super(width, height)
constructor(contentView: View?, width: Int, height: Int) : super(contentView, width, height)
constructor(contentView: View?, width: Int, height: Int, focusable: Boolean) : super(contentView, width, height, focusable)
override fun showAsDropDown(anchor: View) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
val rect = Rect()
anchor.getGlobalVisibleRect(rect)
val h = anchor.resources.displayMetrics.heightPixels - rect.bottom
height = h
}
super.showAsDropDown(anchor)
}
}
WechatIMG14.jpeg
然后,我们需要先写一个类似京东地址选择的xml,因为radioGroup可以方便监听选择状态,而且可以复用recyclerview,
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<!-- 阴影区 -->
<View
android:id="@+id/backgroundView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/black"
android:alpha="0.5"
<!-- 这里不是在titleCl而是tabRg是为了控制圆角效果 -->
app:layout_constraintBottom_toTopOf="@id/tabRg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- 用来添加背景 -->
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/bg_popupwindow_radius"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/titleCl" />
<!-- 顶部title和取消 -->
<android.support.constraint.ConstraintLayout
android:id="@+id/titleCl"
android:layout_width="0dp"
android:layout_height="65dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toTopOf="@id/tabRg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:id="@+id/titleTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#333333"
android:textSize="18dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/cancelTv"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="20dp"
android:gravity="center"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:background="@drawable/close_drawable"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
<!-- 选择器顶部的tab -->
<RadioGroup
android:id="@+id/tabRg"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/contentLl"
app:layout_constraintStart_toStartOf="parent">
<RadioButton
android:id="@+id/firstRb"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="20dp"
android:button="@null"
android:paddingTop="10dp"
android:gravity="center_horizontal"
android:text="请选择"
android:maxLines="1"
android:ellipsize="end"
android:checked="true"
android:textColor="#333333"
android:textSize="13dp"
tools:checked="true" />
<RadioButton
android:id="@+id/secondRb"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="25dp"
android:button="@null"
android:maxLines="1"
android:ellipsize="end"
android:paddingTop="10dp"
android:visibility="gone"
android:gravity="center_horizontal"
android:text="请选择"
android:textColor="#333333"
android:textSize="13dp" />
<RadioButton
android:id="@+id/thridRb"
android:layout_marginStart="25dp"
android:layout_width="wrap_content"
android:button="@null"
android:maxLines="1"
android:visibility="gone"
android:ellipsize="end"
android:paddingTop="10dp"
android:gravity="center_horizontal"
android:text="请选择"
android:textColor="#333333"
android:textSize="13dp"
android:layout_height="match_parent" />
</RadioGroup>
<android.support.constraint.ConstraintLayout
android:id="@+id/contentLl"
android:layout_width="0dp"
android:layout_height="400dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/listItemRv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
分析一些三级选择器的参数,我们需要一个标题title,一个数据源dataSource,一个选择完成的回调,注意这里的数据源可以根据实际情况进行修改,不一定非要传三个list。
class ThirdLevelListPopupWindow(
private val context: Context,
private val title: String = "标题",
private val dataSource: () -> ThirdLevelListDataModel,
private val commitCallback: (param1: String,param2: Sting,param3: String) -> Unit
) : PopupWindowV24(context) {
...
}
分析一下这个三级列表的属性,首先,因为是三级列表,所以一定是每一级都依赖上一级的选择来进行联动,所以需要监听每次RecyclerView的点击位置。
同时,我们要根据点击的item来设置顶部tab的文字内容,所以需要在数据源中取出item中的数据,默认赋值为-1来表示初始化没有选择item的情况。
private var firstList: ArrayList<String> = ArrayList()
private var secondList: ArrayList<String> = ArrayList()
private var thirdList: ArrayList<String> = ArrayList()
private var firstIndex = -1
set(value) {
field = value
if (value == -1) {
firstRb.text = "请选择"
} else {
firstRb.text = firstList[value]
}
}
private var secondIndex = -1
set(value) {
field = value
if (value == -1) {
secondRb.text = "请选择"
} else {
secondRb.text = secondList[value]
}
}
private var thirdIndex = -1
set(value) {
field = value
if (value == -1) {
thirdRb.text = "请选择"
} else {
thirdRb.text = thirdList[value]
}
}
我们还需要一个标记来判断当前选中的tab:
private var curTabPosition : Int = 0
接下来我们要对RecyclerView的adapter进行设计,我们需要传入一个List数据源,一个选中位置的标记,还有一个选择item的点击闭包。
由于我们复用了同一个recyclerView,所以当我们选择不同tab的时候,要更改对应的数据源,需要在外部更改数据源、点击事件、和选择item的位置,所以我们用闭包来在外部控制数据。
class ThirdLevelListPopupWindowAdapter(
private val dataSource : () -> List<String>,
val isSelectedBlock: (Int) -> Boolean,
val block: (Int) -> Unit)
: RecyclerView.Adapter<AddressListPopupWindowAdapter.ViewHolder>() {
...
}
其中item的点击事件在onBindViewHolder()中进行设置
holder.itemView.setOnClickListener{
block.invoke(position)
}
在ThirdLevelListPopupWindow中初始化这个adapter:
adapter = ThirdLevelListPopupWindowAdapter({
when (curTabPosition) {
0 -> firstList
1 -> secondList
else -> thirdList
}
}, {
when (curTabPosition) {
0 -> it == firstIndex
1 -> it == secondIndex
else -> it == thirdIndex
}
},{
when (curTabPosition) {
0 -> setFirstTab(it)
1 -> setSceondTab(it)
else -> setThirdTab(it)
}
})
将adapter绑定到RecyclerView之后,为三个tab设置点击事件,
firstRb.setOnClickListener {
firstRb.isChecked = true
curTabPosition = 0
adapter.notifyDataSetChanged()
}
secondRb.setOnClickListener {
secondRb.isChecked = true
curTabPosition = 1
adapter.notifyDataSetChanged()
}
thirdRb.setOnClickListener {
thirdRb.isChecked = true
curTabPosition = 2
adapter.notifyDataSetChanged()
}
每一级的RecyclerView的点击事件
private fun setFirstTab(position: Int) {
firstIndex = position
firstRb.text = firstList[position]
secondRb.visibility = View.VISIBLE
secondRb.text = "请选择"
secondIndex = -1
secondRb.isChecked= true
secondList.clear()
initData(secondList) //这里方法根据自己的实际情况去实现即可
thirdIndex = -1
thirdRb.visibility = View.GONE
curTabPosition = 1
adapter.notifyDataSetChanged()
}
private fun setSecondTab(position: Int) {
curTabPosition = 2
thirdIndex = -1
thirdList.clear()
initData(thirdList)
thirdRb.visibility = View.VISIBLE
thirdRb.isChecked = true
thirdRb.text = "请选择"
secondIndex = position
adapter.notifyDataSetChanged()
}
private fun setSecondTab(position: Int) {
thridIndex = position
commitCallback.invoke(firstList[firstIndex], secondList[secondIndex], thirdList[thirdIndex])
dismiss()
}
网友评论