各种应用程序中非常常见的功能是允许用户进行搜索。搜索可以从文本,类别或某些信息中完成,以过滤来自应用的数据。
因此,我们改善了用户的经验,这些体验倾向于找到最容易寻求的东西,您同意吗?现在是问题:“我们如何实现JetPack组成过滤器搜索?”
tl; dr
如果您的目标是在不了解动机的情况下检查最终代码,则可以在下面看到:
最重要的是保持过滤停机时间的ViewModel,在这种情况下是过滤产品:
class ProductsListViewModel : ViewModel() {
private val products = MutableStateFlow(emptyList<Product>())
private val _filteredProducts = MutableStateFlow(emptyList<Product>())
val filteredProducts = _filteredProducts.asStateFlow()
fun searchProducts(text: String) {
_filteredProducts.value = if (text.isEmpty()) {
products.value
} else {
products.value.filter {
it.name
.contains(
text,
ignoreCase = true
) || it.description
.contains(
text,
ignoreCase = true
)
}
}
}
init {
products.value = List(10) {
Product(
name = LoremIpsum(Random.nextInt(1, 10)).values.first(),
description = LoremIpsum(Random.nextInt(1, 10)).values.first(),
price = BigDecimal(Random.nextInt(10, 1000))
)
}
_filteredProducts.value = products.value
}
}
我们有屏幕筛选以实现文本字段和产品列表:
val viewModel by viewModels<ProductsListViewModel>()
val products by viewModel.filteredProducts.collectAsState(initial = emptyList())
Column {
var searchText by remember {
mutableStateOf("")
}
OutlinedTextField(
value = searchText,
onValueChange = {
searchText = it
viewModel.searchProducts(searchText)
},
Modifier
.padding(8.dp)
.fillMaxWidth(),
label = {
Text(text = "Buscar")
},
leadingIcon = {
Icon(Icons.Default.Search, "search icon")
},
placeholder = {
Text(text = "O que você procura?")
},
shape = RoundedCornerShape(10.dp)
)
ProductsListScreen(
products = products
)
}
和代表产品列表的组成代码:
@Composable
fun ProductsListScreen(
products: List<Product> = emptyList()
) {
LazyColumn(Modifier.fillMaxSize()) {
items(products) { p ->
Column(
Modifier
.clip(RoundedCornerShape(10.dp))
.padding(8.dp)
.fillMaxWidth()
.border(
1.dp,
Color.Gray.copy(alpha = 0.5f),
RoundedCornerShape(10.dp)
)
.padding(8.dp)
) {
Text(text = p.name, fontWeight = FontWeight.Bold, fontSize = 24.sp)
Text(text = p.description)
Text(
text = p.price.toBrazilianCurrency(),
fontWeight = FontWeight.Bold,
style = TextStyle.Default.copy(color = Color(0xFF4CAF50)),
fontSize = 18.sp
)
}
}
}
}
案例您还想查看货币形成器:
private fun BigDecimal.toBrazilianCurrency(): String =
NumberFormat.getCurrencyInstance(
Locale("pt", "br")
).format(this)
现在,如果您的强度正在理解实现这一目标的步骤,那就是遵循阅读。
示例项目
要举例说明实现,让我们使用一个具有文本字段和产品列表的应用程序:
一个简单的应用程序仅专注于过滤产品的功能。
屏幕代码
如果要复制完全相同的结果,则也可以访问屏幕的屏幕:
Column {
val products by remember {
mutableStateOf(List(10) {
Product(
name = LoremIpsum(Random.nextInt(1, 10)).values.first(),
description = LoremIpsum(Random.nextInt(1, 10)).values.first(),
price = BigDecimal(Random.nextInt(10, 1000))
)
})
}
var searchText by remember {
mutableStateOf("")
}
OutlinedTextField(
value = searchText,
onValueChange = {
searchText = it
},
Modifier
.padding(8.dp)
.fillMaxWidth(),
label = {
Text(text = "Buscar")
},
leadingIcon = {
Icon(Icons.Default.Search, "search icon")
},
placeholder = {
Text(text = "O que você procura?")
},
shape = RoundedCornerShape(10.dp)
)
ProductsListScreen(
products = products
)
}
这是代表产品清单和货币组合人的组合:
@Composable
fun ProductsListScreen(
products: List<Product> = emptyList()
) {
LazyColumn(Modifier.fillMaxSize()) {
items(products) { p ->
Column(
Modifier
.clip(RoundedCornerShape(10.dp))
.padding(8.dp)
.fillMaxWidth()
.border(
1.dp,
Color.Gray.copy(alpha = 0.5f),
RoundedCornerShape(10.dp)
)
.padding(8.dp)
) {
Text(text = p.name, fontWeight = FontWeight.Bold, fontSize = 24.sp)
Text(text = p.description)
Text(
text = p.price.toBrazilianCurrency(),
fontWeight = FontWeight.Bold,
style = TextStyle.Default.copy(color = Color(0xFF4CAF50)),
fontSize = 18.sp
)
}
}
}
}
private fun BigDecimal.toBrazilianCurrency(): String =
NumberFormat.getCurrencyInstance(
Locale("pt", "br")
).format(this)
准备好了!这足以启动过滤器的实现。
查找屏幕信息的ViewModel
我们需要认为的第一件事是,过滤器是数据操纵,也就是说,理想是这种羊毛是屏幕的其他地方。
因此,我们需要创建一个ViewModel来为我们维护这种羊毛,并且可以开始包含代表数据源的产品列表,即屏幕上的所有产品:
class ProductsListViewModel : ViewModel() {
private val products = MutableStateFlow(emptyList<Product>())
init {
products.value = List(10) {
Product(
name = LoremIpsum(Random.nextInt(1, 10)).values.first(),
description = LoremIpsum(Random.nextInt(1, 10)).values.first(),
price = BigDecimal(Random.nextInt(10, 1000))
)
}
}
}
通常,数据源由数据库或通过REST API表示。
从那时起,我们就有开始数据处理所需的一切。
添加数据以表示过滤器
在过滤器的情况下,我们需要另一个列表来表示过滤的产品,毕竟,产品列表代表数据源,不应修改:
class ProductsListViewModel : ViewModel() {
private val products = MutableStateFlow(emptyList<Product>())
private val _filteredProducts = MutableStateFlow(emptyList<Product>())
val filteredProducts = _filteredProducts.asStateFlow()
fun searchProducts(text: String) {
_filteredProducts.value = if (text.isEmpty()) {
products.value
} else {
products.value.filter {
it.name
.contains(
text,
ignoreCase = true
) || it.description
.contains(
text,
ignoreCase = true
)
}
}
}
init {
// ...
_filteredProducts.value = products.value
}
}
如果这种方式看起来很复杂,让我们了解他的所作所为:
-
init
:它初始化了必要的属性:- 将代表无法修改的数据源的产品列表
- 用与源相同的值过滤的产品列表,因为在初始状态(无需搜索文本),它们都会呈现所有产品。
-
searchProducts()
:母亲从文本中进行搜索:- 首先,我们验证文本的值是否为空,如果是空的,则需要指出过滤产品的值与数据源具有相同的值,如果相反,我们应用了过滤器羊毛。li> li>
- 该过滤器是使用Collection
filter()
制成的,该收集允许您添加条件,在这种情况下,仅返回包含通过Parano收到的文本的名称或描述的产品。 - 搜索的来源将始终是数据的来源,因为除了拥有所有产品外,从未更改。
- 属性
filteredProducts
是必须在屏幕上阅读的废话的等级。
现在我们有了ViewModel的视图,它只是连接到屏幕。
从文本更改事件中持有过滤器
在屏幕的屏幕上,我们只需要创建ViewModel,阅读过滤产品并致电产品搜索产品更改事件:
val viewModel by viewModels<ProductsListViewModel>()
val products by viewModel.filteredProducts.collectAsState(initial = emptyList())
Column {
var searchText by remember {
mutableStateOf("")
}
OutlinedTextField(
value = searchText,
onValueChange = {
searchText = it
viewModel.searchProducts(it)
},
// ...
)
ProductsListScreen(
products = products
)
}
准备好了!我们实施了一个代码以在具有JetPack Compiss的应用程序上执行过滤器。值得注意的是,这是一个简单的实现,但根据范围的不同,可能会有更多步骤,因为搜索各种来源,治疗等。
您如何看待此实施?你以不同的方式这样做吗?享受并发表评论ð