iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Mobile Development

花30天做個Android小專案系列 第 16

Day16 - 進入和退出文章

是的,總算要切換到下一頁了...

PreviewFragment

目前先使用預設建立的畫面,一個FrameLayout跟TextView,將目前的畫面印出來而已。

class PreviewFragment : Fragment() {

    private val mTag = "PreviewFragment"

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_preview, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // ...
        tmp.text = PttClient.getInstance().getScreen()
    }
}

nav_main.xml

目前流程的預覽如下
https://ithelp.ithome.com.tw/upload/images/20210930/20124602YUPgkvgMQC.png

進入文章

接著先回到搜尋頁面,為文章列表加上點擊事件。

SearchArticleResultAdapter

class SearchArticleResultAdapter : RecyclerView.Adapter<SearchArticleResultAdapter.ViewHolder>() {
    private val articleList = mutableListOf<Article>()
    var onArticleClickListener: ((article: Article) -> Unit)? = null
    // ...

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        init {
            itemView.setOnClickListener {
                onArticleClickListener?.invoke(articleList[adapterPosition])
            }
        }
        // ...
    }
}

宣告一個onArticleClickListener callback,並在ViewHolder創建時為itemView加上click事件的呼叫。

onArticleClickListener

articleAdapter.onArticleClickListener = { article ->
    (requireActivity() as MainActivity).showLoading("")
    viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
        val ret = withContext(Dispatchers.IO) {
            PttClient.getInstance().send("${article.number}\r\nr")
            delay(200L)
            PttClient.getInstance()
                .expect(arrayOf("瀏覽[\\s\\S]*第[\\s\\S]*頁[\\s\\S]*目前顯示[\\s\\S]*第[\\s\\S]*行[\\s\\S]*離開"))
        }

        if (ret == 0) {
            NavHostFragment.findNavController(this@SearchArticleFragment)
                .navigate(R.id.action_searchArticleFragment_to_previewFragment)
        }
        (requireActivity() as MainActivity).dismissLoading()
    }
}

Ptt進入文章的除了一般操作的上下左右外,也可以直接輸入文章編號+(enter or r),也就是我此處send的內容。接著就是判斷是否有成功進入文章內了,使用的Pattern也就是我們在閱讀文章時最下面會顯示的內容:
https://ithelp.ithome.com.tw/upload/images/20210930/20124602KrOt3lS0Od.png
確認進入文章後就使用Navigation導到下一頁並顯示內容來做確認了,接下來幾天會再來做解析推文的部分。

離開文章

因為我PreviewFragment的畫面還沒設定,因此目前是先處理點擊back鍵的退出流程。

onBackPressedDispatcher

在Fragment內取得Activity的onBackPressedDispatcher並addCallback。

requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner,
    object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            (requireActivity() as MainActivity).showLoading("")
            viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
                val ret = withContext(Dispatchers.IO) {
                    PttClient.getInstance().send("q")
                    delay(200L)
                    PttClient.getInstance().expect(arrayOf("文章選讀"))
                }
                (requireActivity() as MainActivity).dismissLoading()
                if (ret == 0) {
                    PttClient.getInstance().printScreen()
                    NavHostFragment.findNavController(this@PreviewFragment).popBackStack()
                } else {
                    AlertDialog.Builder(requireContext())
                        .setTitle("Error")
                        .setMessage("Something wrong.")
                        .setPositiveButton(android.R.string.ok) { _, _ ->
                            requireActivity().finish()
                        }
                        .setCancelable(false)
                        .show()
                }
            }
        }
    })

離開文章基本上就是用"q",並判斷是否有正確回到文章列表,有的話就可以呼叫NavController的popBackStack回到上一頁了。

消失的Chip

做完退出功能後開心的測試,突然發現有點不對勁...我剛剛的搜尋條件Chip消失了。
https://ithelp.ithome.com.tw/upload/images/20210930/20124602Q6i1OA0czz.png

應該是因為我的Chip是動態加入的關係,使用Navigation切換到下一頁&回來會經歷DestroyView和CreateView的過程,動態加入的元件不在layout中自然也就消失了。解決的方法也很簡單,因為Fragment本身沒被銷毀,全域變數的值還保留著,在onViewCreated中判斷searchTitleSetsearchAuthorSet是否有內容,有的話就重新加回來:

//...
if ((searchAuthorSet.isNotEmpty() || searchTitleSet.isNotEmpty())) {
    searchAuthorSet.forEach { addAuthorChip(it) }
    searchTitleSet.forEach { addTitleChip(it) }
}
//...

addAuthorChipaddTitleChip都是Day13的內容,就不重複貼了。

目前畫面

https://i.imgur.com/juvYxbB.gif


上一篇
Day15 - Ptt換頁及新增文章列表項目
下一篇
Day17 - 解析推文
系列文
花30天做個Android小專案30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言