Android 如何实现搜索功能:本地搜索?数据模型如何设计?数据如何展示和保存?

Android 如何实现搜索功能:本地搜索?数据模型如何设计?数据如何展示和保存?其实搜索功能的重点在于数据模型的设计 还有 apdater 布局的设置

大家好,欢迎来到IT知识分享网。

目录

  1. 效果图
  2. 为什么需要搜索功能
  3. 如何设计搜索本地的功能,如何维护呢?
  4. 总结

一、效果图

在这里插入图片描述在这里插入图片描述

二、为什么需要搜索功能

找一个选项,需要花非常多的时间,并且每次都需要指导客户在哪里,现在只要让他们搜索一下就可以。这也是模仿手机里面的设置功能来进行开发的。这些选项我是存储在本地的。参数太多,暂时还没考虑做到后台,当然,即使后面做到后台,也只是替换数据而已。

在这里插入图片描述

三、如何设计搜索本地的功能,如何维护呢?

我们可以看到效果图:

  1. 有开关类的、有输入类的。
  2. 有分类:系统设置、串口设置、功能开启等等。
  3. 有默认值,如:,默认是关的等等。

so,我们需要设计数据模型。

3.1 设计数据模型

大家可以思考一下为什么数据模型要这样设计?有默认值,有key,有nameId

/ * nameId:显示名称,这里存储的是rid,方便后续国际化 * nameS:名称 * category:分类 * drfault:默认值 * type:类型 1 多选项值 2 开关 3 输入类 * mmkvName:保存key */ enum class OtherEnum(var nameId:Int,var nameS:String,var category:String,var drfault:Any,var type:Int,var mmkvName: String) { 
    MDB(R.string.base_two_code,"通讯协议","串口设置","MDB", 2,MMKVName.MDB), CHANGE(R.string.base_nayax,"找零功能","找零设置",false, 1,MMKVName.CHANGE), CONTACT_NUMBER(R.string.leak_canary_test_class_name,"联系方式","系统设置","", 2,MMKVName.CONTACT_NUMBER), } 

3.2 Repo类

这里只是增加了一个要展示的数据,后面如果把数据放在了后端,也就只是替换这一部分就可以。

class OtherFragmentRepo @Inject constructor() : BaseRepository() { 
    var arrayList: MutableList<OtherEnum> = Arrays.asList(//用于列表展示 OtherEnum.MDB, OtherEnum.CHANGE, OtherEnum.CONTACT_NUMBER, ) } 

如果有新增的数据,只需要在这里增加就可以了。这样也非常好维护,所以需要数据模型设置好来。

3.3 VM:主要是提供搜索的功能

  1. search方法其实就是遍历所有的集合元素,找到匹配的内容,存放到一个list里面进行展示,通过_readAllDataSuccess进行数据通知界面刷新。因为数据量较小,不到100个左右,所以这里使用的for循环遍历。
class OtherFragmentVM @Inject constructor(private val mRepo: OtherFragmentRepo) : BaseViewModel() { 
    //搜索功能【通信设置、系统设置、功能开启等等】 //1. 首先我们需要先添加我们的所有设置。【通过一个bean来存储,一个list来存储所有的】 //bean:名称,分类,类型【开关类、输入类、多值类、音量调节】,value //举例:优惠券、功能开启、开关、false //2. 首先把所有的功能项拿到,进行遍历 //3. 具体的数据展示:如何展示呢?navigation+fragment??【搜索的时候展示另外一个fragment,而不搜索的时候展示其中一个。】 //1.拿到所有的通讯设置 var list :ArrayList<OtherEnum> = ArrayList() private var _readAllDataSuccess = MutableLiveData<Int>()//是否读取所有数据成功 val readAllDataSuccess: LiveData<Int> get() = _readAllDataSuccess //2.搜索功能 fun search(searchText: CharSequence) { 
    list.clear() val arrayList = mRepo.arrayList for (otherEnum in arrayList) { 
    val stringRes = UiUtil.getStringRes(otherEnum.nameId).uppercase() if (stringRes.contains(searchText.toString().uppercase())) { 
    list.add(otherEnum) } } _readAllDataSuccess.value = list.size } } 

3.4 Fragment

  1. 搜索功能:先判断是否输入内容为空,如果为空就提示用户。符合条件就调用search进行模糊匹配搜索。搜索到以后,就将默认显示的navigation进行GONE,将搜索结果进行VISIBLE
class OtherFragment : BaseFragment<BackstageFragmentOtherBinding, OtherFragmentVM>() { 
    private val TAG = "OtherFragment" override val mViewModel: OtherFragmentVM by viewModels() override fun createVB() = BackstageFragmentOtherBinding.inflate(layoutInflater) private var otherAdapter: OtherAdapter? = null override fun BackstageFragmentOtherBinding.initView() { 
    Log.d(TAG, "OtherFragment initView: ") ivSearch.setOnClickListener { 
    val searchText = etSearch.text.trim() Log.d(TAG, "searchText: "+searchText) if(""==searchText){ 
    ToastUtil.switchToastStyleToWarn("请输入内容后搜索") return@setOnClickListener } //进行数据的搜索 mViewModel.search(searchText) } with(rvOtherSearch){ 
    //设置布局排列方式,默认垂直排列 val gridLayoutManager: GridLayoutManager = GridLayoutManager(this@OtherFragment.context, 2, androidx.recyclerview.widget.GridLayoutManager.VERTICAL, false) layoutManager = gridLayoutManager mViewModel.list.add(OtherEnum.CHANGE) otherAdapter = OtherAdapter(mViewModel.list) otherAdapter!!.setItemListener(object : AdapterClickListener { 
    override fun onClickListener(view: View?, position: Int, data: String?) { 
    } }) adapter = otherAdapter } } override fun initObserve() { 
    observeLiveData(mViewModel.readAllDataSuccess,::searchResult) } fun searchResult(i: Int) { 
    if (i==0) { 
    ToastUtil.switchToastStyleToWarn("搜索结果为空") mBinding.rvOtherSearch.visibility = View.GONE mBinding.fcvOther.visibility = View.VISIBLE return } mBinding.rvOtherSearch.visibility = View.VISIBLE mBinding.fcvOther.visibility = View.GONE Log.d(TAG, "searchResult: "+mViewModel.list) otherAdapter?.setData(mViewModel.list) otherAdapter?.notifyDataSetChanged() } override fun initRequestData() { 
    } } 

3.5 xml:UI应该如何编写呢?

<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="@drawable/no_nav_bg" android:layout_height="match_parent"> <net.lucode.hackware.magicindicator.MagicIndicator android:id="@+id/magic_other" android:layout_width="match_parent" android:layout_height="88dp" android:background="@drawable/backstage_shape_product_nav" android:paddingLeft="20dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/et_search" android:layout_width="1000dp" android:layout_height="80dp" android:background="@drawable/home_other_rectangle_background" android:paddingLeft="20dp" android:maxLines="1" android:inputType="text" android:layout_marginVertical="10dp" android:hint="@string/backstage_search_hint" android:textColor="#2E80DD" android:textSize="32sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.51" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/magic_other" /> <ImageView android:id="@+id/iv_search" android:layout_width="90dp" android:layout_height="90dp" android:padding="10dp" android:layout_marginLeft="10dp" android:src="@drawable/search" app:layout_constraintBottom_toBottomOf="@+id/et_search" app:layout_constraintStart_toEndOf="@+id/et_search" app:layout_constraintTop_toTopOf="@+id/et_search" /> <androidx.fragment.app.FragmentContainerView android:id="@+id/fcv_other" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_search" app:navGraph="@navigation/backstage_other_nav" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_other_search" android:layout_width="match_parent" android:layout_height="0dp" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_search" /> </androidx.constraintlayout.widget.ConstraintLayout> 

3.6 Adapter:这里我们需要思考子项不一样应该如何设计,保存也数据逻辑也不一样!

  1. 子项不一样,我们应该如何处理呢?我们可以看到otherEnum里面有一个type属性,就是用于定义不同的布局的,如下:
  2. 那么开关类的保存,输入类的保存有应该如何呢?只需要使用不同的布局进行不同的逻辑进行处理就可以。如下:
 class OtherAdapter(var productList: MutableList<OtherEnum>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { 
    private val TAG = "HomeProductAdapter" var SWITCH_TYPE = 1 var INPUT_TYPE = 2 fun setItemListener(itemListener: AdapterClickListener?) { 
    this.itemListener = itemListener } private var itemListener: AdapterClickListener? = null private var generalParamData: MutableList<String>? = null //开关类布局 inner class MyViewHolder(binding: BackstageItemSystemSettingsBinding) : ViewHolder(binding.root) { 
    private val mBinding = binding fun bind(otherEnum: OtherEnum) { 
    mBinding.run { 
    Log.d(TAG, "MyViewHolder bind: " + otherEnum) tvName.text = UiUtil.getStringRes(productList[layoutPosition].nameId) //开关类的数据保存 rgSwitch.setOnCheckedChangeListener { 
    group, checkedId -> when (checkedId) { 
    R.id.rb_close -> { 
    SpUtils.putBoolean(otherEnum.mmkvName,false) } R.id.rb_open -> { 
    SpUtils.putBoolean(otherEnum.mmkvName,true) } else -> { 
   } } } var flag = SpUtils.getBoolean(otherEnum.mmkvName,otherEnum.drfault as Boolean) if(flag == true){ 
    rbOpen.isChecked = true }else{ 
    rbClose.isChecked = true } } } } //输入类的布局 inner class InputViewHolder(binding: BackstageItemInputBinding) : ViewHolder(binding.root) { 
    private val mBinding = binding fun bind(otherEnum: OtherEnum) { 
    mBinding.run { 
    Log.d(TAG, "InputViewHolder bind: " +otherEnum.mmkvName+":"+ SpUtils.contains(otherEnum.mmkvName)) tvName.text = UiUtil.getStringRes(productList[layoutPosition].nameId) var defaultValue = SpUtils.getString(otherEnum.mmkvName,otherEnum.drfault as String) etValue.setText(defaultValue) //输入类的数据保存 btnUpdate.setOnClickListener { 
    val value = etValue.text.trim().toString() if(value==""){ 
    ToastUtil.switchToastStyleToWarn("输入为空") return@setOnClickListener } SpUtils.putString(otherEnum.mmkvName,value) ToastUtil.switchToastStyleToSuccess("更新成功:"+otherEnum.mmkvName) } } } } override fun getItemViewType(position: Int): Int { 
    //不同的类型,使用不同的布局 return productList[position].type } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 
    when (viewType) { 
    SWITCH_TYPE -> { 
    return MyViewHolder( BackstageItemSystemSettingsBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) } INPUT_TYPE -> { 
    Log.d(TAG, "onCreateViewHolder: InputViewHolder:"+viewType) return InputViewHolder( BackstageItemInputBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) } else -> { 
    } } return MyViewHolder( BackstageItemSystemSettingsBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) } override fun getItemCount(): Int { 
    return productList.size } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 
    if (holder is MyViewHolder) { 
    holder.bind(productList.get(position)) } else if (holder is InputViewHolder) { 
    holder.bind(productList.get(position)) } itemListener?.onClickListener(holder.itemView, position, null) } fun setData(productList: MutableList<OtherEnum>) { 
    this.productList = productList } } 

四、总结:

其实搜索功能的重点在于数据模型的设计,还有apdater布局的设置。以前都是一个一个控件的增加,数据也可以直接就增加,所以维护很模仿,现在换成了recycleview,所以我们需要思考每一个item,他的数据应该如何展示,默认值是如何,在哪个分类,如何保存数据。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/120044.html

(0)
上一篇 2025-11-01 11:20
下一篇 2025-11-01 11:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信