【发布时间】:2021-10-22 09:34:30
【问题描述】:
预期的行为是具有互斥的多个下拉菜单。
例如,我有:
- 数组 = [“A”、“B”、“C”、“D”、“E”]
- 菜单1
- 菜单2
- 菜单3
如果我在 menu1 中选择“A”,那么在 menu2 和 menu3 中“A”就不必出现了。
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var scdd1: SingleCheckBoxDropDown
private lateinit var scdd2: SingleCheckBoxDropDown
private lateinit var scdd3: SingleCheckBoxDropDown
private val strArr = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
strArr.add("string 1")
strArr.add("string 2")
strArr.add("string 3")
strArr.add("string 4")
strArr.add("string 5")
/**
* =============
* Single Select
* =============
*/
/*val scdd: SingleCheckBoxDropDown = findViewById(R.id.scdd1)
scdd.setData(strArr)
val tv1: TextView = findViewById(R.id.tv1)
scdd.setOnItemClickListenerWithSingleSelect {
val checked = scdd.getChecked()
if (checked != -1)
tv1.text = strArr[checked]
}*/
/**
* ====================================
* Single Select with Mutual Exclusion
* ====================================
*/
scdd1 = findViewById(R.id.category1)
scdd2 = findViewById(R.id.category2)
scdd3 = findViewById(R.id.category3)
scdd1.setData(strArr)
scdd2.setData(strArr)
scdd3.setData(strArr)
/** 1 */
scdd1.setOnItemClickListenerWithSingleSelect {
val filter1 = scdd1.getCheckedStr()
val filter2 = scdd2.getCheckedStr()
val filter3 = scdd3.getCheckedStr()
scdd1.setAnswer(filter1)
val data2 = strArr.filter { it != filter1 && it != filter3 }
val data3 = strArr.filter { it != filter1 && it != filter2 }
scdd2.setData(data2)
scdd3.setData(data3)
scdd1.setChecked(filter1)
scdd2.setChecked(filter2)
scdd3.setChecked(filter3)
}
/** 2 */
scdd2.setOnItemClickListenerWithSingleSelect {
val filter1 = scdd1.getCheckedStr()
val filter2 = scdd2.getCheckedStr()
val filter3 = scdd3.getCheckedStr()
scdd2.setAnswer(filter2)
val data1 = strArr.filter { it != filter2 && it != filter3 }
val data3 = strArr.filter { it != filter1 && it != filter2 }
scdd1.setData(data1)
scdd3.setData(data3)
scdd1.setChecked(filter1)
scdd2.setChecked(filter2)
scdd3.setChecked(filter3)
}
/** 3 */
scdd3.setOnItemClickListenerWithSingleSelect {
val filter1 = scdd1.getCheckedStr()
val filter2 = scdd2.getCheckedStr()
val filter3 = scdd3.getCheckedStr()
scdd3.setAnswer(filter3)
val data1 = strArr.filter { it != filter2 && it != filter3 }
val data2 = strArr.filter { it != filter1 && it != filter3 }
scdd1.setData(data1)
scdd2.setData(data2)
scdd1.setChecked(filter1)
scdd2.setChecked(filter2)
scdd3.setChecked(filter3)
}
/**
* Bug 1
*
* [x] 1 [ ] 1
* [ ] 4 --> [x] 4
* [ ] 5 [ ] 5
*
* [x] 2 [x] 1
* [ ] 4 [ ] 2
* [ ] 5 [ ] 5
*
* [x] 3 [x] 1
* [ ] 4 [ ] 3
* [ ] 5 [ ] 5
*/
}
}
activity_main.xml
<ScrollView 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"
android:background="#002E2A"
android:gravity="center_horizontal"
android:padding="20dp"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<jk.singlecheckboxdropdown.scdd.SingleCheckBoxDropDown
android:id="@+id/category1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv1"
app:my_string_entries="@array/arr_str"
app:question="Category 1" />
<jk.singlecheckboxdropdown.scdd.SingleCheckBoxDropDown
android:id="@+id/category2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/category1"
app:my_string_entries="@array/arr_str"
app:question="Category 2" />
<jk.singlecheckboxdropdown.scdd.SingleCheckBoxDropDown
android:id="@+id/category3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/category2"
app:my_string_entries="@array/arr_str"
app:question="Category 3" />
</RelativeLayout>
</ScrollView>
SingleCheckBoxDropDown
class SingleCheckBoxDropDown @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
private val scddContainer: RelativeLayout
private val dropdownMenu: RecyclerView
private val questionTV: TextView
private val answerTV: TextView
private var adapter: ScddAdapter
init {
LayoutInflater.from(context)
.inflate(R.layout.scdd, this, true) // true
/** GET CUSTOM ATTRIBUTES */
val typedArr = context.theme.obtainStyledAttributes(
attrs,
R.styleable.SingleCheckBoxDropDown,
defStyleAttr,
0
)
val question = typedArr.getString(R.styleable.SingleCheckBoxDropDown_question)
val charSequenceArr: Array<CharSequence> =
typedArr.getTextArray(R.styleable.SingleCheckBoxDropDown_my_string_entries)
scddContainer = findViewById(R.id.scdd_container)
dropdownMenu = findViewById(R.id.dropdown_menu)
answerTV = findViewById(R.id.answer)
questionTV = findViewById(R.id.question)
questionTV.text = question
scddContainer.setOnClickListener {
if (dropdownMenu.visibility == View.GONE)
dropdownMenu.visibility = View.VISIBLE
else dropdownMenu.visibility = View.GONE
}
adapter = ScddAdapter()
adapter.addAll(charSequenceArr)
dropdownMenu.layoutManager = LinearLayoutManager(context)
dropdownMenu.adapter = adapter
}
fun resetHard(data: List<String>) {
adapter = ScddAdapter()
adapter.addAll(data.toTypedArray())
dropdownMenu.adapter = adapter
}
fun setData(strArr: List<String>) {
/** bug 1 - hide bug */
// dropdownMenu.removeAllViews()
// dropdownMenu.removeAllViewsInLayout()
adapter.setData(strArr as ArrayList<String>)
// RecyclerView won't update view after data change.
Log.i("try", "strArr size: ${strArr.size}")
Log.i("try", "dropdownmenu size: ${dropdownMenu.size}")
}
fun setAnswer(filter: CharSequence) {
answerTV.text = filter
}
fun getCheckedStr(): CharSequence {
return adapter.getCheckedStr()
}
fun getChecked(): Int {
return adapter.getChecked()
}
/**
* Single Select Core
*/
fun setOnItemClickListenerWithSingleSelect(function: () -> Unit) {
adapter.setOnItemClickListener {
for (i in 0 until dropdownMenu.size)
if (i != it)
(dropdownMenu[i] as CheckBox).isChecked = false
function()
}
}
/** bug 1 - fix part 1 */
fun setChecked(filter: CharSequence) {
for (i in 0 until dropdownMenu.size) {
(dropdownMenu[i] as CheckBox).isChecked = false
if ((dropdownMenu[i] as CheckBox).text == filter) {
(dropdownMenu[i] as CheckBox).isChecked = true
// adapter.notifyItemChanged(i)
}
}
}
}
scdd.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/transparent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/scdd_container"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/holo_green_dark"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical">
<TextView
android:id="@+id/question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:textColor="@android:color/white"
android:textSize="12sp"
tools:text="The Question" />
<TextView
android:id="@+id/answer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:gravity="end"
android:textColor="@android:color/white"
tools:text="The Answer" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dropdown_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/scdd_container"
android:background="@android:color/holo_green_light"
android:translationZ="999dp"
android:visibility="visible" />
</RelativeLayout>
ScddAdapter
/** ADAPTER */
class ScddAdapter : RecyclerView.Adapter<ScddAdapter.ScddViewHolder>() {
/** VIEW HOLDER */
class ScddViewHolder(view: View) :
RecyclerView.ViewHolder(view) {
val cb: CheckBox = view.findViewById(R.id.cb)
}
private var callback = { }
private var list = ArrayList<CharSequence>()
private var checked: Int = -1
private var checkedStr = ""
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ScddViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_single_checkbox, parent, false) // false
return ScddViewHolder(view)
}
override fun onBindViewHolder(holder: ScddViewHolder, position: Int) {
holder.cb.text = list[position]
holder.itemView.setOnClickListener {
if(holder.cb.isChecked) {
checkedStr = holder.cb.text as String
checked = holder.layoutPosition
}
else {
checkedStr = ""
checked = -1
}
this.callback()
}
}
override fun getItemCount(): Int {
return list.size
}
fun addAll(charSequenceArr: Array<CharSequence>) {
list.addAll(charSequenceArr)
}
fun setData(datas: ArrayList<String>) {
// for (i in 0 until strArr.size) Log.i("try", strArr[i])
list.clear()
notifyDataSetChanged()
this.list.addAll(datas)
notifyDataSetChanged()
}
fun getChecked(): Int {
return checked
}
fun getCheckedStr(): CharSequence {
return checkedStr
}
fun setOnItemClickListener(function: (holderPosition: Int) -> Unit) {
this.callback = {
function(checked)
}
}
}
item_single_checkbox.xml
<CheckBox
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/spinnerItemStyle"
tools:text="hello"
android:id="@+id/cb"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textColor="@color/white"
android:background="@android:color/background_dark"
android:buttonTint="@color/white"
android:textAlignment="inherit"/>
我注意到的问题是在 SingleCheckBoxDropDown 的 setData() 中:
Log.i("try", "strArr size: ${strArr.size}")
Log.i("try", "dropdownmenu size: ${dropdownMenu.size}")
我的 RecyclerView(下拉菜单)没有返回正确的大小,我知道为什么。
【问题讨论】:
-
你在这里期待什么?
标签: android kotlin android-recyclerview notifydatasetchanged