今天來把昨天的搜尋結果給顯示出來,並讓使用者選擇要去哪個看板。顯示的部分我想使用PopupWindow,單純覺得適合且過去比較少用到,順便練習看看。
在看完相關資料後,其實就是把它當作一個用來顯示View的框架。在使用上先自行創建View後利用建構子設進PopupWindow即可。
layout(layout_search_board_result.xml)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/one_grid_unit"
android:background="@color/transparent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/one_grid_unit"
android:background="@color/black" />
<TextView
android:id="@+id/noResultLabel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/one_grid_unit"
android:background="@color/black"
android:gravity="center"
android:text="查無看板"
android:textColor="@color/text_normal"
android:textSize="20sp"
android:textStyle="bold"
android:typeface="monospace"
android:visibility="gone" />
</FrameLayout>
基本上就是一個RecyclerView來顯示解析出來的看板列表,若列表為空的話就改顯示"查無看板"的TextView。
inflate view
@SuppressLint("InflateParams")
private fun showSearchResult(boardList: List<String>) {
val view =
LayoutInflater.from(requireContext())
.inflate(R.layout.layout_search_board_result, null)
// ...
}
接著根據傳入的boardList是否為空來決定要顯示RecyclerView或是TextView
val height = if (boardList.isEmpty()) {
view.noResultLabel.visibility = View.VISIBLE
view.recyclerView.visibility = View.GONE
120f.dpToPx(requireContext())
} else {
val adapter = SearchBoardResultAdapter(boardList)
adapter.onBoardClickListener = { board ->
popupWindow?.dismiss()
searchBoardInput.setText(board)
}
view.recyclerView.setHasFixedSize(true)
view.recyclerView.layoutManager = LinearLayoutManager(requireContext())
view.recyclerView.adapter = adapter
360f.dpToPx(requireContext())
}
RecyclerView的創建跟內容沒啥特別的就不多貼了,這段if/else除了確定要顯示哪個View以外也同時給定的height值,這是在接下來創建popupWindow時會需要帶入的參數。
而在計算height時我是使用擴展函數,將預期的DP值轉為PX:
fun Float.dpToPx(context: Context): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this,
context.resources.displayMetrics
).toInt()
}
onBoardClickListener是我在SearchBoardResultAdapter內宣告的函數變數,用來回傳itemView點擊時所點的看板名稱,點擊回傳後就直接把所選的看板放回EditText(searchBoardInput)。
最後就是創建PopupWindow並顯示,整體的function內容如下
@SuppressLint("InflateParams")
private fun showSearchResult(boardList: List<String>) {
val view =
LayoutInflater.from(requireContext())
.inflate(R.layout.layout_search_board_result, null)
val height = if (boardList.isEmpty()) {
view.noResultLabel.visibility = View.VISIBLE
view.recyclerView.visibility = View.GONE
120f.dpToPx(requireContext())
} else {
val adapter = SearchBoardResultAdapter(boardList)
adapter.onBoardClickListener = { board ->
popupWindow?.dismiss()
searchBoardInput.setText(board)
}
view.recyclerView.setHasFixedSize(true)
view.recyclerView.layoutManager =
LinearLayoutManager(requireContext())
view.recyclerView.adapter = adapter
360f.dpToPx(requireContext())
}
popupWindow = PopupWindow(
view, // view
ViewGroup.LayoutParams.MATCH_PARENT, // width
height, // height
true // focusable
)
popupWindow?.showAsDropDown(searchBoardInput)
}
值得一提的是建構函數最後需帶入focusable的布林值,以我的View來說若focusable為false的話影響只在點擊Window外的其他區域或按back時無法自動關閉Window。
最終操作畫面會像這樣: