我在学机器人的kotlin流。我想基本上即时搜索在我的列表和过滤器,以显示在再浏览。我在谷歌搜索,发现了这个惊人的5~6成熟帖子。这篇文章基本上是从谷歌搜索的。我想要在列表中搜索项目,并在回圈视图中显示。有人能指点我怎么开始这个吗。我正在做更详细的计划
假设我有一个SearchBox和一个Reyclerview,其中一个项目abc 1,abc 2,xyz 1,xyz 2.等.
当所有数据合并时,主图像
场景1
当我开始输入SearchBox并输入small 或大写A时,我只想在回收视图中显示两个匹配项,如下所示
场景2
当我在SearchBox中输入任何错误的文本时,我想基本上显示一个找不到的文本消息,如下所示
任何指导都是很好的。谢谢
我正在添加我的代码
ExploreViewModel.kt
class ExploreViewModel(private var list: ArrayList<Category>) : BaseViewModel() {
val filteredTopics = MutableStateFlow<List<opics>>(emptyList())
var topicSelected: TopicsArea? = TopicsArea.ALL
set(value) {
field = value
handleTopicSelection(field ?: TopicsArea.ALL)
}
private fun handleTopicSelection(value: TopicsArea) {
if (value == TopicsArea.ALL) {
filterAllCategories(true)
} else {
filteredTopics.value = list.firstOrNull { it.topics != null && it.title == value.title }
?.topics?.sortedBy { topic -> topic.title }.orEmpty()
}
}
fun filterAllCategories(isAllCategory: Boolean) {
if (isAllCategory && topicSelected == TopicsArea.ALL && !isFirstItemIsAllCategory()) {
list.add(0, code = TopicsArea.ALL.categoryCode))
} else if (isFirstItemIsAllCategory()) {
list.removeAt(0)
}
filteredTopics.value = list.flatMap { it.topics!! }.distinctBy { topic -> topic.title }.sortedBy { topic -> topic.title }
}
private fun isFirstItemIsAllCategory() = list.firstOrNull()?.code == TopicsArea.ALL
}
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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.SearchView
android:id="@+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
app:closeIcon="@drawable/ic_cancel"
app:layout_constraintBottom_toTopOf="@+id/exploreScroll"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintVertical_chainStyle="packed" />
<HorizontalScrollView
android:id="@+id/exploreScroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/searchView">
<com.google.android.material.chip.ChipGroup
android:id="@+id/exploreChips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipSpacingHorizontal="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:singleLine="true"
app:singleSelection="true" />
</HorizontalScrollView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/exploreList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="20dp"
android:paddingTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_default="wrap"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/exploreScroll" />
</androidx.constraintlayout.widget.ConstraintLayout>
Category.kt
@Parcelize
data class Category(
val id: String? = null,
val title: String? = null,
val code: String? = null,
val topics: List<Topics>? = null,
) : Parcelable
Topics.kt
@Parcelize
data class Topics(
val id: String? = null,
val title: String? = null
) : Parcelable
虚拟数据和来自服务器的
fun categoriesList() = listOf(
Categories("21", "physical", listOf(Topics("1", "Abc one"), Topics("2", "Abc Two"))),
Categories("2211", "mind", listOf(Topics("1", "xyz one"), Topics("2", "xyz two"))),
Categories("22131", "motorized", listOf(Topics("1", "xyz three"), Topics("2", "xyz four"))),
)
在我看来,模型
list
保存在虚拟数据之上。在我的回收视图中,我正在传递整个对象,我正在做flatMap
,将所有数据合并到列表中。确保在回收视图中使用Topic
和title
属性。在图像Abc one
中,Abc two
在Topic
中占有一席之地。谢谢
在@Tenfour04建议之后,我将转到A2建议,因为我已经有了转换成流的数据,并传入了适配器。我也在添加我的活动代码。
ExploreActivity.kt
class ExploreActivity : AppCompatActivity() {
private val binding by lazy { ExploreLayoutBinding.inflate(layoutInflater) }
val viewModel by viewModel<ExploreViewModel> {
val list = intent?.getParcelableArrayListExtra(LIST_KEY) ?: emptyList<Category>()
parametersOf(list)
}
var exploreAdapter = ExploreAdapter { topic -> handleNextActivity(topic) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
setupView()
}
fun setupView() {
setupSearchView()
setupFilteredTopic()
setupExploreAdapter()
}
private fun setupFilteredTopic() {
lifecycleScope.launchWhenCreated {
repeatOnLifecycle(Lifecycle.State.CREATED) {
viewModel.filteredTopics.collect { filteredTopicsList ->
exploreAdapter.submitList(filteredTopicsList)
}
}
}
}
fun setupSearchView() {
binding.searchView.apply {
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?) = false
override fun onQueryTextChange(newText: String?): Boolean {
return true
}
})
}
}
fun setupExploreAdapter() {
with(binding.exploreList) {
adapter = exploreAdapter
}
}
}
更新2
ExploreViewModel.kt
val filteredCategories = query
.debounce(200) // low debounce because we are just filtering local data
.distinctUntilChanged()
.combine(filteredTopics) { queryText, categoriesList ->
val criteria = queryText.lowercase()
if (criteria.isEmpty()) {
return@combine filteredTopics
} else {
categoriesList.filter { category -> category.title?.lowercase()?.let { criteria.contains(it) } == true }
}
}
当我设置适配器时会出错。
固定
filteredTopics.value
发布于 2022-06-12 13:50:50
您所链接的教程有一个由SearchView生成的流。如果希望将搜索功能保留在ViewModel中,可以将MutableStateFlow放入ViewModel中,由SearchView间接更新。可以公开用于更新查询的属性。
这有两种不同的方法,这取决于您(A)是否已经有了要快速查询的完整数据列表,或者(B)每次查询文本更改时都要查询服务器或数据库。
然后,甚至(A)也可以分解为:(A1)您有一个静态的普通旧列表,或者(A2)您的源列表来自一个流,例如不基于查询参数的返回的Room流。
下面的所有代码都在ViewModel类中。
A1:
private val allCategories = categoriesList()
private val query = MutableStateFlow("")
// You should add an OnQueryTextListener on your SearchView that
// sets this property in the ViewModel
var queryText: String
get() = query.value
set(value) { query.value = value }
// This is the flow that should be observed for the updated list that
// can be passed to the RecyclerView.Adapter.
val filteredCategories = query
.debounce(200) // low debounce because we are just filtering local data
.distinctUntilChanged()
.map {
val criteria = it.lowercase()
allCategories.filter { category -> criteria in category.title.lowercase }
}
A2:
在本例中,我为上游服务器查询放置了一个简单的占位符流。这可能是任何流动。
private val allCategories = flow {
categoriesList()
}
private val query = MutableStateFlow("")
// You should add an OnQueryTextListener on your SearchView that
// sets this property in the ViewModel
var queryText: String
get() = query.value
set(value) { query.value = value }
// This is the flow that should be observed for the updated list that
// can be passed to the RecyclerView.Adapter.
val filteredCategories = query
.debounce(200) // low debounce because we are just filtering local data
.distinctUntilChanged()
.combine(allCategories) { queryText, categoriesList ->
val criteria = queryText.lowercase()
categoriesList.filter { category -> criteria in category.title.lowercase }
}
B
private val query = MutableStateFlow("")
// You should add an OnQueryTextListener on your SearchView that
// sets this property in the ViewModel
var queryText: String
get() = query.value
set(value) { query.value = value }
// This is the flow that should be observed for the updated list that
// can be passed to the RecyclerView.Adapter.
val filteredCategories = query
.debounce(500) // maybe bigger to avoid too many queries
.distinctUntilChanged()
.map {
val criteria = it.lowercase()
categoriesList(criteria) // up to you to implement this depending on source
}
https://stackoverflow.com/questions/72588305
复制相似问题