zoukankan      html  css  js  c++  java
  • Kotlin安卓开发入门-使用SearchView和RecyclerView实现搜索和展示

    Search and Display APP介绍

    • 使用kotlin编写
    • 主要有那些功能?
      • 展示一个100条内容的recyclerview
      • 通过searchview输入关键词,改变recyclerview显示列表
      • 点击列表项会跳转到新的展示Activity用于展示其中的内容

    效果图

     

     

    前置技能点

    本人虽然之前通过别人的项目修改过两个安卓APP,但是都是java语言,而且我没系统学过java,此前也没接触过kotlin。

    Android开发入门http://hukai.me/android-training-course-in-chinese/basics/index.html

    kotlin入门https://www.runoob.com/kotlin/kotlin-basic-syntax.html

    安卓新闻App开发参考视频https://www.bilibili.com/video/BV12p4y1n7JV

    关于Adapter的API参考:https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter

    本项目地址在本人github

    项目结构

    项目最初是使用Android Studio的Scrolling Activity模板创建的,剩下的文件都是通过右键包名创建的,这样应该是最规范的方法。

    Kotlin文件

    从上到下依次为:

    • 点击列表中某个item后进入的新的Activity的程序
    • RecyclerView的自定义Adapter类,主要是规定了如何装载和控制视图内容,包括item的点击事件
    • RecyclerView的自定义ViewHolder类,为每个item中的变量对应的子view起一个对应的成员名称,本例只有一个textView我把他命名为了text,更多的可以参考上面提到的视频
    • 主界面程序,规定了搜索、展示等(创建项目时自动就生成了)

    layout样式文件

    从上到下依次为:

    • 点击列表中某个item后进入的新的Activity的界面布局:通过右键可以很方便地添加居中

    • 主界面上方的彩色区域的布局(创建项目时自动就生成了)
    • 主界面下方自定义区域的布局(创建项目时自动就生成了):
      • 这个很简单,就是个垂直的线性布局,上面是SearchView,下面是RecyclerView。
      • 如果RecyclerView左右设置了margin,这样之后添加的分割线就不会填满屏幕,但是上下滑动到末端时的动画也不会填满屏幕,所以建议margin保持为0,
    • 展示列中每一个item的子布局,单独弄一个xml文件可以很方便地统一规定其布局
      • 每个item布局包括一个TextView和一个分割线,前者居中并加上四周的一个margin
      • 分割线的实现如下,左右设置了margin,这样分割线就不会填满屏幕
    <View
    android:layout_width="match_parent"
    android:layout_height="1px"
    android:layout_marginLeft="20dp"
    android:layout_marginRight="20dp"
    android:background="#BFBFBF" />

    values数据文件

    从上到下依次为:

    • 规定了色彩关键字映射,比如white对应#FFFFFF
    • 规定了几何关键字映射,比如app_bar_height为180dp
    • 规定了字符串变量关键字映射,比如large_text对应“这是一串很长的文字”
    • 规定了主题关键字映射,可以一键修改对应主题样式

    代码说明

    主界面控制ScrollingActivity.kt

    class ScrollingActivity : AppCompatActivity() {
    
        private val list = mutableListOf<String>()
        //private lateinit var myRecycler: RecyclerView
    
        override fun onCreate(savedInstanceState: Bundle?) {
    
            super.onCreate(savedInstanceState)
    
            setContentView(R.layout.activity_scrolling)
            setSupportActionBar(findViewById(R.id.toolbar))
            findViewById<CollapsingToolbarLayout>(R.id.toolbar_layout).title = title
            findViewById<FloatingActionButton>(R.id.fab).setOnClickListener { view ->
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
            }//这个图标被我禁止显示了,所以这个功能并没有什么用
    
            for (i in 1..100) list.add("这里是第 $i 行") //这个是kotlin独特的字符串模板,用$套一个变量,可以引用其值
    
            //添加RecyclerView的样式和数据更新方法
            val myRecycler = findViewById<RecyclerView>(R.id.recyclerView)
            myRecycler.layoutManager = LinearLayoutManager(this)
            myRecycler.adapter = MyAdapter(list)
    
            //规定SearchView的侦听事件
            val searchView = findViewById<SearchView>(R.id.searchView)
            searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
                override fun onQueryTextSubmit(keyWord: String): Boolean {
                    //当提交了输入时的操作
                    return false
                }
    
                override fun onQueryTextChange(keyWord: String): Boolean {
                    // 当修改了输入时的操作,根据关键字过滤列表,让Adapter填入新列表
                    // 如果只是更新部分数据,推荐使用notifyItemRangeChanged()或者notifyItemChanged()
                    // notifyItemChanged(int)
                    // notifyItemInserted(int)
                    // notifyItemRemoved(int)
                    // notifyItemRangeChanged(int, int)
                    // notifyItemRangeInserted(int, int)
                    // notifyItemRangeRemoved(int, int)
                    val filterList = filter(keyWord)
                    myRecycler.adapter = MyAdapter(filterList)
                    return false
                }
            })
    
        }
    
        override fun onCreateOptionsMenu(menu: Menu): Boolean {
            // Inflate the menu; this adds items to the action bar if it is present.
            menuInflater.inflate(R.menu.menu_scrolling, menu)
            return true
        }
    
        override fun onOptionsItemSelected(item: MenuItem): Boolean {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
    
            return when (item.itemId) {
                R.id.action_settings -> true
                else -> super.onOptionsItemSelected(item)
            }
        }
    
        private fun filter(keyWord: String): List<String> {
            // 过滤原本的列表,返回一个新的列表
            val filterList = mutableListOf<String>()
    
            for (l in list) {
                if (l.contains(keyWord)) filterList.add(l)
            }
            return filterList
        }
    }
    

    桥接适配器MyAdapter.kt

    class MyAdapter(private val contentList: List<String>) : RecyclerView.Adapter<MyViewHolder>() {
    
        // 创建一个成员Context变量,否则onBindViewHolder()无法访问主活动的context
        // 如果此类和主活动在同一个kt文件中,直接使用this即可获得context
        private lateinit var mContext: Context
    
        //下面这三个函数是创建时继承了RecyclerView.Adapter类会自动提示你需要实现的
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            mContext = parent.context // 获取整个列表组展示View的context
            // 在列表组展示View中使用item_layout.xml规定的样式进行填充,把整个View撑起来
            val itemView =
                LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
            return MyViewHolder(itemView)
        }
    
        override fun getItemCount(): Int {
            // 获取有多少个item
            return contentList.size
        }
    
        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            // 给每个itemView绑定显示内容,注意要绑定到holder的对应成员中,这个成员是我们指定好的对应view
            val item = contentList[position] // 根据位置获取列表中对应item,这个Int来源是默认的,不用指定
            holder.text.text = item // 修改了TextView中的text属性
            // 给每个holder添加一个点击事件
            holder.itemView.setOnClickListener {
                val intent = Intent(mContext, Display::class.java)
                // 通过Intent传递数据到新的名叫Display的Activity中,"msg"是在Display.kt中指定的成员常量
                intent.putExtra("msg", item)
                mContext.startActivity(intent)
            }
        }
    }
    

      

    自定义快捷View映射: MyViewHolder.kt

    ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。 

    class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
        val text: TextView = itemView.findViewById(R.id.textView)
    }
    

    点击后进入的Activity: Display.kt

    class Display : AppCompatActivity() {
        @RequiresApi(Build.VERSION_CODES.P)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_display)
            // 这里指定了要获取的常量的名字,通过名字传递不同的消息
            val msg=intent.getStringExtra("msg")
            // 修改新活动的TextView,显示msg内容
            findViewById<TextView>(R.id.textDisplay).text =msg
        }
    }
    

    小提示

    如果想要生成的apk尽量小,记得在app的build.gradle中设置这两个关键字为true

    项目在上传的时候记得删除任何build、.gradle、.idea、appuild文件夹,这样的项目是最精简的。

  • 相关阅读:
    1144 The Missing Number (20分)
    1145 Hashing
    1146 Topological Order (25分)
    1147 Heaps (30分)
    1148 Werewolf
    1149 Dangerous Goods Packaging (25分)
    TypeReference
    Supervisor安装与配置()二
    谷粒商城ES调用(十九)
    Found interface org.elasticsearch.common.bytes.BytesReference, but class was expected
  • 原文地址:https://www.cnblogs.com/smileglaze/p/14470624.html
Copyright © 2011-2022 走看看