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、app\build文件夾,這樣的項目是最精簡的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM