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

原文地址:https://www.cnblogs.com/smileglaze/p/14470624.html