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文件夹,这样的项目是最精简的。

  • 相关阅读:
    strcpy和memcpy的区别(转)
    获得discuz7.2 目录下所有文件,并写到txt
    Lintcode: Majority Number 解题报告
    Lintcode: Fast Power 解题报告
    LeetCode: Pow(x, n) 解题报告
    Lintcode: Minimum Subarray 解题报告
    Lintcode: Subarray Sum 解题报告
    LeetCode: Minimum Depth of Binary Tree 解题报告
    LeetCode: Binary Tree Maximum Path Sum 解题报告
    LeetCode: Binary Tree Postorder Traversal 解题报告
  • 原文地址:https://www.cnblogs.com/smileglaze/p/14470624.html
Copyright © 2011-2022 走看看