關于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)
}
}
然后,我們需要先寫一個類似京東地址選擇的xml己单,因為radioGroup可以方便監(jiān)聽選擇狀態(tài)唉窃,而且可以復用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">
<!-- 陰影區(qū) -->
<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>
分析一些三級選擇器的參數(shù)纹笼,我們需要一個標題title纹份,一個數(shù)據(jù)源dataSource,一個選擇完成的回調,注意這里的數(shù)據(jù)源可以根據(jù)實際情況進行修改蔓涧,不一定非要傳三個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) {
...
}
分析一下這個三級列表的屬性,首先元暴,因為是三級列表篷扩,所以一定是每一級都依賴上一級的選擇來進行聯(lián)動,所以需要監(jiān)聽每次RecyclerView的點擊位置茉盏。
同時鉴未,我們要根據(jù)點擊的item來設置頂部tab的文字內容,所以需要在數(shù)據(jù)源中取出item中的數(shù)據(jù)鸠姨,默認賦值為-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數(shù)據(jù)源讶迁,一個選中位置的標記连茧,還有一個選擇item的點擊閉包。
由于我們復用了同一個recyclerView巍糯,所以當我們選擇不同tab的時候梅屉,要更改對應的數(shù)據(jù)源,需要在外部更改數(shù)據(jù)源鳞贷、點擊事件、和選擇item的位置虐唠,所以我們用閉包來在外部控制數(shù)據(jù)搀愧。
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) //這里方法根據(jù)自己的實際情況去實現(xiàn)即可
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()
}