我使用SearchView
和RecyclerView
制作应用。要更新结果,请使用DiffUtil
。更新数据时,某些项目会更改其高度,但如果我关闭软键盘,则它们将是正常大小。如果我使用notifyDataSetChanged()
它们不会改变它们的高度,但我需要一个动画。
这是我的my_item.xml
:
<carbon.widget.RelativeLayout 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"
style="@style/carbon_CardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:layout_margin="0dp"
android:padding="0dp"
app:carbon_elevation="4dp"
app:carbon_rippleColor="@color/dust"
app:carbon_rippleStyle="over">
<ImageView
android:id="@+id/my_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true" />
<carbon.widget.RelativeLayout
android:id="@+id/my_info_wrapper"
android:layout_below="@+id/my_image"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/snow"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="8dp"
android:paddingStart="16dp"
android:paddingEnd="8dp"
android:paddingTop="8dp"
android:layout_margin="0dp">
<carbon.widget.ImageView
android:id="@+id/my_second_image"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="0dp" />
<carbon.widget.TextView
android:id="@+id/my_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/my_second_image"
android:layout_toStartOf="@id/my_second_image"
android:gravity="start"
android:singleLine="true"
android:textColor="@color/stone_dark"
android:textSize="14sp"
android:layout_margin="0dp"
app:carbon_fontPath="Roboto-Medium.ttf" />
<carbon.widget.TextView
android:id="@+id/my_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/my_title"
android:layout_toLeftOf="@id/my_second_image"
android:layout_toStartOf="@id/my_second_image"
android:gravity="start"
android:singleLine="true"
android:textColor="@color/stone_normal"
android:textSize="12sp"
android:layout_margin="0dp"
app:carbon_fontPath="Roboto-Regular.ttf" />
</carbon.widget.RelativeLayout>
</carbon.widget.RelativeLayout>
MyAdapter.kt
:
class MyAdapter (private val clickListener: (Int) -> Unit) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
var items: List<MyListItem> = listOf()
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
holder.bind(items[position], clickListener)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.my_item, parent, false))
}
class RockViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: RockListItem, clickListener: (Int) -> Unit) {
itemView.setOnClickListener {
clickListener.invoke(item.id)
}
itemView.my_title.text = item.title
Picasso.with(itemView.context)
.load(item.second_image)
.into(itemView.my_second_image)
val identifier = itemView.context.resources
.getIdentifier(item.picName, "drawable", itemView.context.packageName)
Picasso.with(itemView.context)
.load(identifier)
.fit()
.into(itemView.my_image)
itemView.my_subtitle.text = ""
}
}
}
这是MyFragment.kt
:
class RockListFragment : Fragment() {
private lateinit var listViewModel: MyViewModel
private val adapter: RockListAdapter = MyAdapter({ itemId ->
openDetail(itemId)
})
private var itemDecoration: GridSpacingItemDecoration? = null
private lateinit var search: SearchView
override fun onAttach(context: Context?) {
super.onAttach(context)
listViewModel = getViewModel()
listViewModel.setItems("")
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
val layoutManager = GridLayoutManager(activity, resources.getInteger(R.integer.grid_columns))
recycler.layoutManager = layoutManager
recycler.adapter = adapter
recycler.setHasFixedSize(true)
itemDecoration = GridSpacingItemDecoration(resources.getInteger(R.integer.grid_columns),
resources.getDimensionPixelSize(R.dimen.list_spacing))
recycler.addItemDecoration(itemDecoration)
listViewModel.rocks.observe(this, Observer { items ->
if (items != null) {
val diffUtilCallback = RockDiffUtilCallback(adapter.items, items)
val diffResult = DiffUtil.calculateDiff(diffUtilCallback, false)
adapter.items = items
diffResult.dispatchUpdatesTo(adapter)
search_empty_state.visibleOrGone = items.isEmpty()
recycler.visibility = View.VISIBLE
}
})
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.menu_search_activity, menu)
search = menu?.findItem(R.id.action_search)?.actionView as SearchView
addToCompositeDisposable(
RxSearchView.queryTextChanges(search)
.debounce(250, TimeUnit.MILLISECONDS)
.subscribe { p0 ->
listViewModel.setItems(p0.toString())
})
}
}
}
最后MyViewModel.kt
:
class MyViewModel : BaseViewModel() {
val rocks: MutableLiveData<List<MyListItem>> = MutableLiveData()
@Inject lateinit var useCase: MyUseCase
fun setRocks(search: String) {
addToCompositeDisposable(useCase.getRocksList(search)
.flatMap { list ->
return@flatMap Observable.fromIterable(list)
.map(MyListItemMapper())
.toList()
}
.subscribe({ list ->
items.value = list
}))
}
}