Search and Display APP介紹
- 使用
kotlin編寫 - 主要有那些功能?
- 展示一個100條內容的
recyclerview - 通過
searchview輸入關鍵詞,改變recyclerview顯示列表 - 點擊列表項會跳轉到新的展示Activity用於展示其中的內容
- 展示一個100條內容的
效果圖



前置技能點
本人雖然之前通過別人的項目修改過兩個安卓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文件夾,這樣的項目是最精簡的。
