Android入門到實戰(八):從發現頁到詳情頁——跳轉、傳值與RecyclerView多類型布局


一. 引言

在上一篇文章里,我們從零開始實現了 App 的?發現頁面,通過網絡請求獲取數據,并使用 RecyclerView 展示了劇集列表。

但光有發現頁還不夠,用戶在點擊一部劇時,自然希望進入到一個更詳細的頁面,去查看它的簡介、標簽以及劇集列表。本篇我們就來實現?發現詳情頁

主要包含以下內容:

  1. 從發現頁跳轉到詳情頁(Activity 跳轉與傳值)
  2. 詳情頁的 UI 布局(背景、Toolbar、RecyclerView)
  3. RecyclerView 多類型布局(頭部 + 劇集列表)
  4. ViewModel + LiveData 數據驅動(自動刷新 UI)

通過這一篇,你將掌握 Android 開發中常見的“跳轉 → 數據傳遞 → 多類型列表 → 數據綁定”的完整流程。

二. 從發現頁跳轉到詳情頁

2.1?發送跳轉

在發現頁的 Adapter 中,我們可以為每一個劇集的 Item 添加點擊事件,然后通過 Intent 啟動?DiscoverDetailActivity,并把?DiscoverDrama?對象傳遞過去:

val intent = Intent(context, DiscoverDetailActivity::class.java)
intent.putExtra("drama", drama) // drama 是 DiscoverDrama 類型
context.startActivity(intent)

這里我們用到了?putExtra,因為?DiscoverDrama?已經實現了?Serializable,所以可以直接傳遞。

2.2 接收參數

在?DiscoverDetailActivity?中,通過?intent.getSerializableExtra?來接收數據:

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun initData() {discoverDrama = intent.getSerializableExtra("drama", DiscoverDrama::class.java)
}

這樣我們就能在詳情頁中拿到用戶點擊的劇集信息,并用于后續的 UI 展示和數據請求。

三. 詳情頁整體布局概覽

在詳情頁,我們主要分為三個部分:

1. 背景與 Toolbar

  • 頁面頂部是一個漸變背景 (View) 和透明的?MaterialToolbar,用于展示標題“劇集詳情”。
  • 使用?enableEdgeToEdge()?和?WindowInsetsCompat?處理狀態欄高度,讓內容貼合屏幕邊緣。

2. RecyclerView

占據主體區域,用于展示兩類內容:

  1. 頭部信息:封面、標題、描述、標簽、詞匯量
  2. 劇集列表:每一集的標題、文件大小、下載狀態等

3. 布局特點

  • RecyclerView 采用?LinearLayoutManager?垂直排列。
  • 頭部視圖與列表項通過 Adapter 的?getItemViewType?區分,實現多類型布局。
  • 數據完全通過?ViewModel + LiveData?綁定到 RecyclerView,無需在 Activity 中手動更新視圖。

這種布局方式簡潔而高效,既能展示劇集的詳細信息,也便于擴展后續功能(例如下載按鈕或播放按鈕)。

四. RecyclerView 多類型布局實現

發現詳情頁中,我們的 RecyclerView 既要展示?頭部信息,又要展示?劇集列表。為此,我們采用?多類型布局的方式,實現兩類 ViewHolder:

4.1?Adapter 設計
class DiscoverDetailAdapter(private val discoverDrama: DiscoverDrama
): RecyclerView.Adapter<RecyclerView.ViewHolder>() {companion object {const val TYPE_HEADER = 0const val TYPE_CONTENT = 1}private var episodes: List<DiscoverEpisode> = emptyList()override fun getItemViewType(position: Int): Int {return if (position == 0) TYPE_HEADER else TYPE_CONTENT}override fun getItemCount(): Int = episodes.size + 1
}

  • 第一個位置 (position == 0) 是?頭部視圖
  • 其余位置為?劇集列表
  • getItemCount()?返回?episodes.size + 1,因為頭部占一行

4.2?ViewHolder 綁定數據

頭部視圖 (HeaderViewHolder)

  • 顯示劇封面、標題、描述、標簽、詞匯量
  • 使用 Glide 加載封面圖片
  • 標簽動態生成 TextView 并添加到 LinearLayout
class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {private val cover = itemView.findViewById<ImageView>(R.id.ivCover)private val title = itemView.findViewById<TextView>(R.id.tvTitle)private val desc = itemView.findViewById<TextView>(R.id.tvDesc)private val wordCount = itemView.findViewById<TextView>(R.id.tvVocab)private val tagContainer = itemView.findViewById<LinearLayout>(R.id.tagContainer)fun bindData(drama: DiscoverDrama) {Glide.with(itemView.context).load(drama.realCoverUrl).into(cover)title.text = drama.titledesc.text = drama.descriptionwordCount.text = "詞匯量: ${drama.vocabularyCount ?: 0}"tagContainer.removeAllViews()drama.tags?.split(",")?.forEach { tag ->val tv = TextView(itemView.context).apply {text = tag// 背景、圓角、透明度等樣式}tagContainer.addView(tv)}}
}

劇集列表視圖 (EpisodeViewHolder)

  • 顯示劇集標題、文件大小、下載狀態
  • 預留下載邏輯和進度條
class EpisodeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {private val title: TextView = itemView.findViewById(R.id.episodeTitle)private val size: TextView = itemView.findViewById(R.id.episodeSize)private val statusIcon: ImageView = itemView.findViewById(R.id.statusIcon)private val statusProgress: ProgressBar = itemView.findViewById(R.id.statusProgress)fun bindData(episode: DiscoverEpisode) {title.text = "${episode.index}. ${episode.title}"size.text = episode.fileSize ?: ""// 下載狀態邏輯可在此擴展}
}

4.3?數據更新

  • 通過 ViewModel 獲取劇集列表數據
  • 使用 LiveData 觀察數據變化,并調用 Adapter 的?setEpisodes()?更新 RecyclerView
viewModel.episodes.observe(this) { episodes ->adapter.setEpisodes(episodes)
}

這樣實現了?Activity 不直接操作 RecyclerView?的思想,保證了 UI 與數據的分離。

五. 數據獲取與綁定流程

在詳情頁中,劇集列表的數據來源于網絡請求。為了實現?UI 與數據分離,我們采用?ViewModel + LiveData?的方式管理數據。

5.1?ViewModel 請求數據

DiscoverDetailViewModel?負責請求劇集列表,并將結果通過 LiveData 暴露給 UI:

class DiscoverDetailViewModel : ViewModel() {val episodes = MutableLiveData<List<DiscoverEpisode>>()val isLoading = MutableLiveData<Boolean>()private val discoverDramaRepository by lazy { DiscoverRespository() }fun fetchEpisodes(drama: DiscoverDrama) {viewModelScope.launch {isLoading.value = trueval result = discoverDramaRepository.fetchEpisodes(drama)result.onSuccess {println("獲取劇集 ${drama.title} 的集列表成功: ${it.size} 條數據")episodes.value = it}.onFailure {episodes.value = emptyList()}isLoading.value = false}}
}

  • viewModelScope.launch?在協程中發起網絡請求,保證不會阻塞 UI 線程
  • 成功時,將數據賦值給?episodes?LiveData
  • 失敗時,清空列表,保證 RecyclerView 安全更新

5.2?Activity 觀察數據

在?DiscoverDetailActivity?中,RecyclerView Adapter 不直接請求數據,而是?觀察 LiveData

viewModel.episodes.observe(this) { episodes ->adapter.setEpisodes(episodes)Log.d("DiscoverDetailActivity", "Episodes updated: ${episodes.size} items")
}
  • 當 LiveData 更新時,Adapter 自動刷新 RecyclerView
  • Activity 只負責 UI 初始化和 LiveData 綁定,無需手動刷新列表

5.3?請求與展示流程總結
  1. Activity 啟動后,通過 Intent 獲取?DiscoverDrama?參數
  2. 調用?viewModel.fetchEpisodes(drama)?發起網絡請求
  3. ViewModel 請求成功后,將數據賦值給 LiveData
  4. Activity 觀察 LiveData,并將數據傳遞給 Adapter
  5. Adapter 更新 RecyclerView,實現 UI 自動刷新

六.運行效果與總結

6.1?最終效果展示
  • 用戶在?發現頁面?點擊某部劇集
  • 頁面跳轉到?詳情頁
  • 頁面頂部展示劇的封面、標題、描述、標簽和詞匯量
  • 下方 RecyclerView 展示劇集列表,每一集顯示標題、文件大小和下載狀態(可擴展)
  • UI 完全響應?LiveData?數據更新,無需手動刷新

6.2?本篇收獲

通過這一篇文章,我們掌握了:

Activity 跳轉與參數傳遞

  • 使用 Intent 傳遞 Serializable 對象
  • 在目標 Activity 中安全接收數據

RecyclerView 多類型布局

  • 頭部視圖 + 列表視圖
  • Adapter 分類型管理 ViewHolder

ViewModel + LiveData 數據驅動 UI

  • Activity 不直接操作數據
  • RecyclerView 自動響應數據變化

這種模式不僅使代碼清晰、可維護,還符合 Android 架構最佳實踐。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96166.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96166.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96166.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【工具】41K star!網頁一鍵變桌面應用

項目中遇到了一個需要將現有的 web 頁面打包成一個 桌面應用 的需求。 最一開始想到的是 Electron&#xff0c;但是它還需要一些開發工作并且打包后的應用體積比較大&#xff0c;調研后發現了開源工具 Pake。 它能讓你用最輕量的方式&#xff0c;把任何網頁一鍵打包成跨平臺桌…

浪潮CD1000-移動云電腦-RK3528芯片-2+32G-安卓9-2種開啟ADB ROOT刷機教程方法

浪潮CD1000-移動云電腦-RK3528芯片-232G-安卓9-2種開啟ADB ROOT刷機教程方法 往期文章&#xff1a; 浪潮CD1000-移動云電腦-RK3528芯片-232G-安卓9-開啟ADB ROOT破解教程 地址1&#xff1a;浪潮CD1000-移動云電腦-RK3528芯片-232G-開啟ADB ROOT破解教程-CSDN博客 中國移動浪潮…

Day23_【機器學習—聚類算法—K-Means聚類 及評估指標SSE、SC、CH】

一、聚類算法概念屬于無監督學習算法&#xff0c;即有特征無標簽&#xff0c;根據樣本之間的相似性&#xff0c;將樣本劃分到不同的類別中。所謂相似性可以理解為歐氏距離、曼哈頓距離、切比雪夫距離... 。分類按顆粒度分為&#xff1a;粗聚類、細聚類。按實現方法分為&#xf…

android seekbar顯示刻度

SeekBar簡介 SeekBar是Android中的一個可交互UI組件&#xff0c;允許用戶通過拖動滑塊在特定范圍內選擇數值。繼承自ProgressBar&#xff0c;但增加了用戶手動調節功能&#xff0c;常用于音量控制、亮度調節等場景。 核心屬性 android:maxHeight // 背景高度 android:progres…

【高并發內存池】五、頁緩存的設計

文章目錄Ⅰ. page cache頁緩存的結構設計Ⅱ. 完善central cache中的 get_span() 函數Ⅲ. 實現頁緩存獲取span對象的接口Ⅰ. page cache頁緩存的結構設計 ? 首先頁緩存還是一個哈希桶的結構&#xff0c;但是和前兩者不同的是&#xff0c;頁緩存的哈希桶中存放的是一個或者多個…

Elasticsearch(text和keyword)區別分析

text:全文檢索類型,經過分詞處理,支持模糊匹配? keyword:精確匹配類型,適用于聚合、排序和過濾? text 1. 核心屬性 ?analyzer屬性?: 指定用于索引和搜索的分詞器 默認使用標準分析器(Standard Analyzer) 示例:"analyzer": "ik_max_word"(中文…

通過tailscale實現一臺電腦上vscode通過ssh連接另一臺電腦上的VMware Linux 虛擬機

當需要通過一臺windows電腦上的vscode來ssh連接另一臺電腦上的linux虛擬機進行遠程操作&#xff0c;可以通過tailscale來實現。 Linux虛擬機上安裝tailscale 由于掛代理下載仍然很慢&#xff0c;而清華鏡像源又沒有tailscale的軟件包&#xff0c;所以可以通過下載 DEB 包安裝…

[Upscayl圖像增強] docs | 前端 | Electron工具(web->app)

鏈接&#xff1a;https://upscayl.org/docs&#xff1a;Upscayl Upscayl是一款桌面應用程序&#xff0c;允許用戶使用人工智能放大和增強圖像。 提供了一個用戶友好的圖形界面&#xff08;渲染器用戶界面&#xff09;&#xff0c;用戶可以選擇圖像或文件夾&#xff0c;從多種AI…

阿里云通義MoE全局均衡技術:突破專家負載失衡的革新之道

MoE模型的基本原理與核心價值 混合專家模型&#xff08;Mixture of Experts&#xff0c;MoE&#xff09;是當前AI大模型領域最重要的架構創新之一&#xff0c;其核心思想是通過多個“專家”網絡協同處理輸入數據&#xff0c;并由門控網絡動態選擇或組合各個專家的輸出&#xf…

macOS中設置環境變量的各文件及作用域

在 macOS 中&#xff0c;~/.zshrc 和 ~/.bash_profile 是 Shell 的配置文件&#xff0c;用于設置環境變量、命令別名、啟動命令等。它們在你每次打開終端時會被自動加載。文件對應 Shell作用~/.zshrcZsh&#xff08;macOS Catalina 及以后默認&#xff09;每次打開新的終端窗口…

【華為培訓筆記】OptiX OSN 9600 設備保護專題

OptiX OSN 9600 設備保護專題 1、光層保護 定義 方式 應用

Python開篇撬動未來的萬能鑰匙 從入門到架構的全鏈路指南

&#x1f49d;&#x1f49d;&#x1f49d;歡迎蒞臨我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 持續學習&#xff0c;不斷…

LabVIEW 與 PLC 通訊

在工業自動化領域&#xff0c;LabVIEW 與 PLC 的通訊極為關鍵&#xff0c;它能實現設備間高效的數據交互與協同運作。接下來&#xff0c;將從應用場景、軟件架構、功能實現、特點、開發問題及解決方法等層面展開闡述。 應用場景? 智能工廠生產線監控系統中&#xff0c;LabVIE…

11-FreeRTOS任務相關的其他API函數

數據來源地址&#xff1a;gitee.com FreeRTOS任務相關的其他API函數 一、FreeRTOS任務相關的其他API函數介紹 1、FreeRTOS任務相關API函數介紹(部分常用的) 答&#xff1a; 二、任務狀態查詢API函數 1、獲取任務優先級函數 答&#xff1a; UBaseType_t uxTaskPriorityGet…

ECMAScript(2)核心語法課件(Node.js/React 環境)

&#x1f4da; ECMAScript 核心語法課件&#xff08;Node.js/React 環境&#xff09; 1. 變量與作用域 變量聲明方式 var&#xff1a;函數作用域&#xff0c;存在變量提升&#xff08;hoisting&#xff09;console.log(a); // undefined&#xff08;變量提升&#xff09; var a…

Selenium 頁面加載超時pageLoadTimeout與 iframe加載關系解析

引言 在 Web 自動化測試中&#xff0c;處理頁面加載超時是每個 Selenium 使用者都會遇到的挑戰。特別是當頁面包含 iframe 時&#xff0c;加載行為變得更加復雜。許多測試工程師困惑于&#xff1a;pageLoadTimeout 究竟能否控制 iframe 的加載&#xff1f;本文將深入探討這一問…

AI面試將重塑企業招聘流程:從效率到精準度的全面升級

每年校招季&#xff0c;HR團隊總被“面試官不夠用”“簡歷太多看不清”“候選人放鴿子”等問題折磨。傳統招聘流程冗長、成本高昂、標準參差&#xff0c;已難以適應快速變化的用人需求。而AI面試技術的突破&#xff0c;正在從底層邏輯上重塑招聘鏈條——從初篩到終面&#xff0…

IOC為什么交由spring容器管理?

根本原因&#xff1a;在 Spring 框架中&#xff0c;將控制反轉&#xff08;IoC&#xff09; 交由 Spring 容器管理&#xff0c;是為了解決傳統編程模式中 “對象創建與依賴管理耦合度高” 的核心問題&#xff0c;最終實現代碼的低耦合、高可維護性、高可測試性。要理解這一設計…

Java反射與動態代理學習筆記

Java 反射與動態代理學習筆記反射概述反射允許對成員變量、成員方法和構造方法進行編程訪問&#xff0c;提供了在運行時分析類和對象的能力。獲取Class對象的三種方式方式代碼示例說明Class.forName()Class.forName("全類名")通過類的全限定名獲取Class對象對象.getC…

RAG提示詞分解

RAG提示詞分解 System Message # 智能問答助手&#xff08;RAG系統提示&#xff09;## 角色定義 您是"智能問答助手"&#xff0c;專門基于提供的上下文信息回答用戶問題。## 核心規則 1. **嚴格基于上下文**&#xff1a;僅使用用戶提供的<context>中的信息&…