Codelab นี้เป็นส่วนหนึ่งของหลักสูตรพื้นฐานเกี่ยวกับ Kotlin ใน Android คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals
ข้อมูลเบื้องต้น
ใน Codelab นี้ คุณจะได้เรียนรู้วิธีเพิ่มส่วนหัวที่ครอบคลุมความกว้างของรายการที่แสดงใน RecyclerView
คุณสร้างแอปติดตามการนอนหลับจาก Codelab เวอร์ชันก่อนหน้าได้
สิ่งที่ควรทราบอยู่แล้ว
- วิธีสร้างอินเทอร์เฟซผู้ใช้เบื้องต้นโดยใช้กิจกรรม ส่วนย่อย และการดู
- วิธีไปยังส่วนต่างๆระหว่างส่วนย่อยและวิธีใช้
safeArgs
เพื่อส่งผ่านข้อมูลระหว่างส่วนย่อย - ดูโมเดล ดูโรงงานของโมเดล การเปลี่ยนรูปแบบ และ
LiveData
และการสังเกตการณ์ - วิธีสร้างฐานข้อมูล
Room
, สร้าง DAO และกําหนดเอนทิตี - วิธีใช้โครูทีนสําหรับการโต้ตอบกับฐานข้อมูลและงานอื่นๆ ที่ใช้เวลานาน
- วิธีใช้
RecyclerView
พื้นฐานด้วยAdapter
,ViewHolder
และเลย์เอาต์รายการ - วิธีใช้การเชื่อมโยงข้อมูลกับ
RecyclerView
- วิธีสร้างและใช้อะแดปเตอร์การเชื่อมโยงเพื่อเปลี่ยนรูปแบบข้อมูล
- วิธีใช้
GridLayoutManager
- วิธีการบันทึกและจัดการการคลิกรายการใน
RecyclerView.
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้
ViewHolder
มากกว่า 1 รายการด้วยRecyclerView
เพื่อเพิ่มรายการที่มีเลย์เอาต์อื่น กล่าวอย่างเจาะจงคือ วิธีใช้ViewHolder
รายการที่ 2 เพื่อเพิ่มส่วนหัวเหนือรายการที่แสดงในRecyclerView
สิ่งที่คุณจะทํา
- สร้างจากแอป TrackMySleepคุณภาพ จาก Codelab ก่อนหน้าในชุดนี้
- เพิ่มส่วนหัวที่ครอบคลุมความกว้างของหน้าจอเหนือคืนการนอนหลับที่แสดงใน
RecyclerView
แอปติดตามการนอนหลับที่คุณเริ่มต้นด้วยจะมีหน้าจอ 3 หน้าจอซึ่งแสดงด้วยส่วนย่อยดังที่แสดงในภาพด้านล่าง
หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มสําหรับเริ่มต้นและหยุดติดตาม หน้าจอแสดงข้อมูลการนอนหลับของผู้ใช้บางส่วน ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปรวบรวมให้กับผู้ใช้อย่างถาวร หน้าจอที่ 2 ที่แสดงตรงกลางคือการเลือกคะแนนคุณภาพการนอนหลับ หน้าจอที่ 3 คือมุมมองรายละเอียดที่เปิดขึ้นเมื่อผู้ใช้แตะรายการในตาราง
แอปนี้ใช้สถาปัตยกรรมที่เรียบง่ายด้วยตัวควบคุม UI, โมเดลการดู และ LiveData
และฐานข้อมูล Room
เพื่อรักษาข้อมูลการนอนหลับไว้
ใน Codelab นี้ คุณต้องเพิ่มส่วนหัวลงในตารางรายการที่แสดง หน้าจอหลักขั้นสุดท้ายจะมีลักษณะดังนี้
Codelab นี้จะสอนหลักการทั่วไปในการรวมรายการที่ใช้เลย์เอาต์แบบต่างๆ ใน RecyclerView
ตัวอย่างหนึ่งที่พบบ่อยคือการมีส่วนหัวในรายการหรือตารางกริด รายการอาจมีส่วนหัวเพียงรายการเดียวเพื่ออธิบายเนื้อหารายการ และยังใช้ส่วนหัวหลายรายการในการจัดกลุ่มและแยกรายการต่างๆ ไว้ในรายการเดียวได้ด้วย
RecyclerView
ไม่ทราบรายละเอียดใดๆ เกี่ยวกับข้อมูลของคุณหรือประเภทของเลย์เอาต์แต่ละรายการ LayoutManager
จะจัดเรียงรายการบนหน้าจอ แต่อะแดปเตอร์จะปรับข้อมูลที่จะแสดงและส่งผ่านดูผู้ถือสิทธิ์ไปยัง RecyclerView
ดังนั้นคุณจะเพิ่มโค้ดเพื่อสร้างส่วนหัวในอะแดปเตอร์
การเพิ่มส่วนหัวทําได้ 2 วิธี
ใน RecyclerView
ทุกรายการในรายการจะสอดคล้องกับหมายเลขดัชนีโดยเริ่มจาก 0 เช่น
[ข้อมูลจริง] -> [มุมมองอะแดปเตอร์]
[0: SleepNight] -> [0: SleepNight]
[1: SleepNight] -> [1: การตรวจจับการนอนหลับ]
[2: SleepNight] -> [2: การตรวจจับการนอนหลับ]
วิธีหนึ่งในการเพิ่มส่วนหัวลงในรายการคือการแก้ไขอะแดปเตอร์ให้ใช้ ViewHolder
อื่นด้วยการตรวจสอบดัชนีที่คุณต้องแสดงส่วนหัว Adapter
มีหน้าที่ติดตามส่วนหัว ตัวอย่างเช่น หากต้องการแสดงส่วนหัวที่ด้านบนของตาราง คุณต้องส่งคืน ViewHolder
อื่นสําหรับส่วนหัวขณะวางรายการที่ได้รับการจัดทําดัชนีเป็น 0 จากนั้นรายการอื่นๆ ทั้งหมดจะได้รับการแมปด้วยออฟเซ็ตส่วนหัวดังที่แสดงด้านล่าง
[ข้อมูลจริง] -> [มุมมองอะแดปเตอร์]
[0: ส่วนหัว]
[0: SleepNight] -> [1: การตรวจจับการนอนหลับ]
[1: SleepNight] -> [2: การตรวจจับการนอนหลับ]
[2: SleepNight] -> [3: SleepNight
อีกวิธีหนึ่งในการเพิ่มส่วนหัวคือการแก้ไขชุดข้อมูลสนับสนุนสําหรับตารางกริดข้อมูล เนื่องจากข้อมูลทั้งหมดที่ต้องแสดงจะจัดเก็บอยู่ในรายการ คุณจึงแก้ไขรายการเพื่อรวมรายการเป็นส่วนหัวได้ การทําเช่นนี้เข้าใจได้ง่ายกว่า แต่จะต้องคํานึงถึงวิธีออกแบบออบเจ็กต์ เพื่อให้คุณสามารถรวมรายการประเภทต่างๆ ไว้ในรายการเดียวได้ หากคุณใช้งานด้วยวิธีนี้ อะแดปเตอร์จะแสดงรายการที่ส่งไปยังอะแดปเตอร์ดังกล่าว ดังนั้นรายการที่ตําแหน่ง 0 คือส่วนหัว และรายการที่ตําแหน่ง 1 คือ SleepNight
ซึ่งแมปกับสิ่งที่แสดงบนหน้าจอโดยตรง
[ข้อมูลจริง] -> [มุมมองอะแดปเตอร์]
[0: ส่วนหัว] -> [0: ส่วนหัว]
[1: SleepNight] -> [1: การตรวจจับการนอนหลับ]
[2: SleepNight] -> [2: การตรวจจับการนอนหลับ]
[3: SleepNight] -> [3: การตรวจจับการนอนหลับ]
แต่ละวิธีก็มีข้อดีและข้อเสีย การเปลี่ยนชุดข้อมูลจะไม่ทําให้เกิดการเปลี่ยนแปลงมากนักกับรหัสอะแดปเตอร์อื่นๆ และคุณสามารถเพิ่มตรรกะส่วนหัวด้วยการดัดแปลงรายการข้อมูลได้ด้วย ในทางกลับกัน การใช้ ViewHolder
ที่แตกต่างกันโดยการตรวจสอบดัชนีสําหรับส่วนหัวจะทําให้มีอิสระมากขึ้นในการจัดวางส่วนหัว และยังช่วยให้อะแดปเตอร์จัดการกับวิธีปรับให้เข้ากับข้อมูลพร็อพเพอร์ตี้โดยไม่ต้องแก้ไขข้อมูลสํารอง
ใน Codelab นี้ คุณจะต้องอัปเดต RecyclerView
เพื่อแสดงส่วนหัวที่ส่วนต้นของรายการ ในกรณีนี้ แอปจะใช้ ViewHolder
สําหรับส่วนหัวต่างจากรายการข้อมูล แอปจะตรวจสอบดัชนีของรายการเพื่อพิจารณาว่าจะใช้ ViewHolder
ใด
ขั้นตอนที่ 1: สร้างคลาส DataItem
หากต้องการดูนามธรรมของประเภทและปล่อยให้อะแดปเตอร์จัดการเฉพาะ "items" ให้คุณสร้างคลาสผู้ถือข้อมูลที่แสดงถึง SleepNight
หรือ Header
ชุดข้อมูลจะกลายเป็นรายการผู้ถือข้อมูล
คุณจะดาวน์โหลดแอปเริ่มต้นจาก GitHub หรือใช้แอปการนอนหลับการนอนหลับที่สร้างไปก่อนหน้าใน Codelab ก็ได้
- ดาวน์โหลดโค้ด RecyclerViewHeaders-Starter จาก GitHub ไดเรกทอรี RecyclerViewHeaders-Starter มีแอป StarterpTracker เวอร์ชันเริ่มต้นที่จําเป็นสําหรับ Codelab นี้ คุณสามารถดําเนินการต่อโดยใช้แอปที่ทําเสร็จแล้วได้จาก Codelab ก่อนหน้าหากต้องการ
- เปิด SleepNightAdapter.kt
- ด้านล่างชั้นเรียน
SleepNightListener
ที่ระดับบนสุด ให้กําหนดชั้นเรียนsealed
ที่ชื่อDataItem
ซึ่งแสดงถึงรายการข้อมูล
คลาสsealed
ระบุประเภทที่ปิดไปแล้ว ซึ่งหมายความว่าระบบต้องระบุคลาสย่อยของDataItem
ทั้งหมดในไฟล์นี้ ผลก็คือ คอมไพเลอร์จะระบุจํานวนคลาสย่อย โค้ดส่วนอื่นจะกําหนดDataItem
ประเภทใหม่ที่อาจทําให้อะแดปเตอร์เสียหายไม่ได้
sealed class DataItem {
}
- ภายในส่วนเนื้อหาของชั้นเรียน
DataItem
ให้กําหนดคลาส 2 คลาสที่แสดงถึงรายการข้อมูลประเภทต่างๆ รายการแรกคือSleepNightItem
ซึ่งเป็น Wrapper รอบๆSleepNight
จึงใช้ค่าเดียวที่เรียกว่าsleepNight
หากต้องการเป็นส่วนหนึ่งของชั้นเรียนที่ปิดผนึก ให้ขยายDataItem
data class SleepNightItem(val sleepNight: SleepNight): DataItem()
- คลาสที่ 2 คือ
Header
เพื่อแสดงส่วนหัว เนื่องจากส่วนหัวไม่มีข้อมูลจริง คุณจะประกาศเป็นobject
ได้ ซึ่งหมายความว่าจะมีHeader
เพียงอินสแตนซ์เดียว ให้ขยายDataItem
อีกครั้ง
object Header: DataItem()
- ภายใน
DataItem
ที่ระดับพร็อพเพอร์ตี้ ให้กําหนดพร็อพเพอร์ตี้Long
ของabstract
ชื่อid
เมื่ออะแดปเตอร์ใช้DiffUtil
เพื่อระบุว่าสินค้ามีการเปลี่ยนแปลงหรือไม่และDiffItemCallback
จําเป็นต้องทราบรหัสของสินค้าแต่ละรายการหรือไม่ คุณจะเห็นข้อผิดพลาด เนื่องจากSleepNightItem
และHeader
ต้องลบล้างพร็อพเพอร์ตี้นามธรรมid
abstract val id: Long
- ใน
SleepNightItem
ให้ลบล้างid
เพื่อแสดงผลnightId
override val id = sleepNight.nightId
- ใน
Header
ให้ลบล้างid
เพื่อส่งคืนLong.MIN_VALUE
ซึ่งเป็นตัวเลขที่น้อยมาก (จริงๆ คือ -2 ยกกําลัง 63) สิ่งนี้จะไม่ขัดแย้งกับnightId
ที่มีอยู่
override val id = Long.MIN_VALUE
- โค้ดที่เสร็จแล้วควรจะมีหน้าตาแบบนี้ และแอปควรสร้างขึ้นโดยไม่มีข้อผิดพลาด
sealed class DataItem {
abstract val id: Long
data class SleepNightItem(val sleepNight: SleepNight): DataItem() {
override val id = sleepNight.nightId
}
object Header: DataItem() {
override val id = Long.MIN_VALUE
}
}
ขั้นตอนที่ 2: สร้าง Viewholder สําหรับส่วนหัว
- สร้างเลย์เอาต์สําหรับส่วนหัวในไฟล์ทรัพยากรเลย์เอาต์ใหม่ที่ชื่อ header.xml ซึ่งแสดง
TextView
ไม่มีอะไรน่าตื่นเต้นเกี่ยวกับเรื่องนี้ ต่อไปนี้เป็นรหัส
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Sleep Results"
android:padding="8dp" />
- แตก
"Sleep Results"
เป็นทรัพยากรสตริงและเรียกว่าheader_text
<string name="header_text">Sleep Results</string>
- ใน SleepNightAdapter.kt ภายใน
SleepNightAdapter
เหนือคลาสViewHolder
ให้สร้างคลาสTextViewHolder
ใหม่ คลาสนี้จะเพิ่มเลย์เอาต์ textview.xml ให้สูงขึ้น และจะส่งคืนอินสแตนซ์TextViewHolder
เนื่องจากคุณเคยทําเช่นนี้แล้ว นี่คือโค้ด และคุณจะต้องนําเข้าView
และR
:
class TextViewHolder(view: View): RecyclerView.ViewHolder(view) {
companion object {
fun from(parent: ViewGroup): TextViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.header, parent, false)
return TextViewHolder(view)
}
}
}
ขั้นตอนที่ 3: อัปเดต SleepNightAdapter
ต่อไปคุณต้องอัปเดตการประกาศของ SleepNightAdapter
โดยจะต้องใช้พร็อพเพอร์ตี้ประเภทใดก็ได้แทนการรองรับ ViewHolder
เพียงประเภทเดียว
กําหนดประเภทของรายการ
- ใน
SleepNightAdapter.kt
ที่ระดับบนสุดใต้คําสั่งimport
และมากกว่าSleepNightAdapter
ให้กําหนดค่าคงที่ 2 ประเภทสําหรับประเภทข้อมูลพร็อพเพอร์ตี้RecyclerView
จะต้องแยกประเภทมุมมองของแต่ละรายการเพื่อให้กําหนดผู้ถือครองข้อมูลพร็อพเพอร์ตี้ได้อย่างถูกต้อง
private val ITEM_VIEW_TYPE_HEADER = 0
private val ITEM_VIEW_TYPE_ITEM = 1
- ใน
SleepNightAdapter
ให้สร้างฟังก์ชันเพื่อลบล้างgetItemViewType()
เพื่อแสดงส่วนหัวหรือค่าคงที่ของรายการทางด้านขวา โดยขึ้นอยู่กับประเภทของรายการปัจจุบัน
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is DataItem.Header -> ITEM_VIEW_TYPE_HEADER
is DataItem.SleepNightItem -> ITEM_VIEW_TYPE_ITEM
}
}
อัปเดตคําจํากัดความ SleepNightAdapter
- ในคําจํากัดความของ
SleepNightAdapter
ให้อัปเดตอาร์กิวเมนต์แรกของListAdapter
จากSleepNight
เป็นDataItem
- ในคําจํากัดความของ
SleepNightAdapter
ให้เปลี่ยนอาร์กิวเมนต์ทั่วไปรายการที่ 2 ของListAdapter
จากSleepNightAdapter.ViewHolder
เป็นRecyclerView.ViewHolder
คุณจะเห็นข้อผิดพลาดบางอย่างสําหรับการอัปเดตที่จําเป็น และส่วนหัวของชั้นเรียนควรมีลักษณะดังนี้
class SleepNightAdapter(val clickListener: SleepNightListener):
ListAdapter<DataItem, RecyclerView.ViewHolder>(SleepNightDiffCallback()) {
อัปเดต onCreateViewholder()
- เปลี่ยนลายเซ็นของ
onCreateViewHolder()
เพื่อแสดงผลRecyclerView.ViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder
- ขยายการใช้เมธอด
onCreateViewHolder()
เพื่อทดสอบและแสดงผลผู้ถือมุมมองที่เหมาะสมสําหรับรายการแต่ละประเภท วิธีที่อัปเดตของคุณควรมีลักษณะเป็นโค้ดด้านล่าง
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIEW_TYPE_HEADER -> TextViewHolder.from(parent)
ITEM_VIEW_TYPE_ITEM -> ViewHolder.from(parent)
else -> throw ClassCastException("Unknown viewType ${viewType}")
}
}
อัปเดต onBindViewholder()
- เปลี่ยนประเภทพารามิเตอร์ของ
onBindViewHolder()
จากViewHolder
เป็นRecyclerView.ViewHolder
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int)
- เพิ่มเงื่อนไขเพื่อกําหนดให้ข้อมูลแก่ผู้ถือข้อมูลพร็อพเพอร์ตี้ก็ต่อเมื่อเจ้าของเป็น
ViewHolder
when (holder) {
is ViewHolder -> {...}
- แคสต์ประเภทออบเจ็กต์ที่แสดงผลโดย
getItem()
ไปยังDataItem.SleepNightItem
ฟังก์ชันonBindViewHolder()
ที่สร้างเสร็จแล้วควรมีลักษณะดังนี้
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ViewHolder -> {
val nightItem = getItem(position) as DataItem.SleepNightItem
holder.bind(nightItem.sleepNight, clickListener)
}
}
}
อัปเดตโค้ดเรียกกลับ diffUtil
- เปลี่ยนวิธีใน
SleepNightDiffCallback
เพื่อใช้ชั้นเรียนDataItem
ใหม่แทนSleepNight
ระงับคําเตือนแบบ Lint ดังที่แสดงในโค้ดด้านล่าง
class SleepNightDiffCallback : DiffUtil.ItemCallback<DataItem>() {
override fun areItemsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem.id == newItem.id
}
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: DataItem, newItem: DataItem): Boolean {
return oldItem == newItem
}
}
เพิ่มและส่งส่วนหัว
- ภายใน
SleepNightAdapter
ด้านล่างonCreateViewHolder()
ให้กําหนดฟังก์ชันaddHeaderAndSubmitList()
ดังที่แสดงด้านล่าง ฟังก์ชันนี้จะใช้รายการSleepNight
คุณจะใช้ฟังก์ชันนี้เพื่อเพิ่มส่วนหัวแล้วส่งรายการแทนการใช้submitList()
จากListAdapter
เพื่อส่งรายการ
fun addHeaderAndSubmitList(list: List<SleepNight>?) {}
- ภายใน
addHeaderAndSubmitList()
หากรายการที่ส่งผ่านคือnull
ให้แสดงผลเฉพาะส่วนหัว หรือแนบส่วนหัวกับส่วนหัวของรายการ แล้วส่งรายการ
val items = when (list) {
null -> listOf(DataItem.Header)
else -> listOf(DataItem.Header) + list.map { DataItem.SleepNightItem(it) }
}
submitList(items)
- เปิด SleepTrackerFragment.kt และเปลี่ยนการโทรเป็น
submitList()
เป็นaddHeaderAndSubmitList()
- เรียกใช้แอปและสังเกตวิธีแสดงส่วนหัวเป็นรายการแรกในรายการการนอนหลับ
มี 2 อย่างที่ต้องแก้ไขสําหรับแอปนี้ คือแบบหนึ่งและบางแบบไม่เห็น
- ส่วนหัวจะปรากฏที่มุมซ้ายบนและดูได้ยาก
- ลิสต์ขนาดเล็กที่มีส่วนหัว 1 รายการไม่สําคัญ แต่คุณไม่ควรจัดการใน
addHeaderAndSubmitList()
บนชุดข้อความใน UI ลองนึกถึงรายการที่ประกอบด้วยรายการหลายร้อยรายการ ส่วนหัวหลายรายการ และตรรกะในการตัดสินใจว่าจะแทรกรายการจุดใด งานนี้อยู่ในโครูทีน
เปลี่ยน addHeaderAndSubmitList()
เพื่อใช้ Coroutine:
- ที่ระดับบนสุดภายในชั้นเรียน
SleepNightAdapter
ให้กําหนดCoroutineScope
ด้วยDispatchers.Default
private val adapterScope = CoroutineScope(Dispatchers.Default)
- ใน
addHeaderAndSubmitList()
ให้เปิดคอร์คอร์ทีในadapterScope
เพื่อควบคุมรายการ จากนั้นสลับไปยังบริบทDispatchers.Main
เพื่อส่งรายการตามที่แสดงในโค้ดด้านล่าง
fun addHeaderAndSubmitList(list: List<SleepNight>?) {
adapterScope.launch {
val items = when (list) {
null -> listOf(DataItem.Header)
else -> listOf(DataItem.Header) + list.map { DataItem.SleepNightItem(it) }
}
withContext(Dispatchers.Main) {
submitList(items)
}
}
}
- โค้ดควรสร้างและทํางานได้ และคุณจะไม่เห็นความแตกต่างใดๆ
ปัจจุบันส่วนหัวจะมีความกว้างเท่ากับรายการอื่นๆ ในตารางกริดซึ่งครอบคลุมพื้นที่ 1 ช่วงในแนวนอนและแนวตั้ง ตารางกริดทั้งหมดพอดีกับความกว้าง 3 ช่วงของแนวนอน 1 บรรทัด ดังนั้นส่วนหัวควรใช้ 3 ช่วงในแนวนอน
หากต้องการแก้ไขความกว้างของส่วนหัว คุณต้องบอก GridLayoutManager
ว่าเมื่อใดควรครอบคลุมข้อมูลในคอลัมน์ทั้งหมด ซึ่งทําได้โดยการกําหนดค่า SpanSizeLookup
ใน GridLayoutManager
นี่คือออบเจ็กต์การกําหนดค่าที่ GridLayoutManager
ใช้เพื่อเลือกว่าจะใช้ระยะเวลาเท่าใดกับแต่ละรายการในรายการ
- เปิด SleepTrackerFragment.kt
- ค้นหาโค้ดที่คุณกําหนด
manager
จนถึงonCreateView()
val manager = GridLayoutManager(activity, 3)
- ด้านล่าง
manager
ให้กําหนดmanager.spanSizeLookup
ดังที่แสดง คุณต้องตั้งobject
เนื่องจากsetSpanSizeLookup
ไม่ถือเป็นแลมบ์ดา หากต้องการใช้object
ใน Kotlin ให้พิมพ์object : classname
ในกรณีนี้คือGridLayoutManager.SpanSizeLookup
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
}
- คุณอาจได้รับข้อผิดพลาดคอมไพเลอร์เพื่อเรียกใช้ตัวสร้าง หากเป็นเช่นนั้น ให้เปิดเมนู Intent ที่มี
Option+Enter
(Mac) หรือAlt+Enter
(Windows) เพื่อใช้การเรียกเครื่องมือสร้าง
- จากนั้นพบข้อผิดพลาดใน
object
ซึ่งแจ้งว่าคุณต้องลบล้างเมธอด วางเคอร์เซอร์ที่object
กดOption+Enter
(Mac) หรือAlt+Enter
(Windows) เพื่อเปิดเมนู Intent แล้วลบล้างเมธอดgetSpanSize()
- ในเนื้อหาของ
getSpanSize()
ให้แสดงผลขนาดระยะเวลาที่เหมาะสมสําหรับแต่ละตําแหน่ง ตําแหน่ง 0 มีขนาดระยะเวลาเป็น 3 และตําแหน่งอื่นๆ จะมีช่วงขนาดอยู่ที่ 1 รหัสที่สมบูรณ์ควรมีลักษณะเหมือนโค้ดด้านล่าง
manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int) = when (position) {
0 -> 3
else -> 1
}
}
- หากต้องการปรับปรุงรูปลักษณ์ของส่วนหัว ให้เปิด header.xml และเพิ่มโค้ดนี้ลงในไฟล์เลย์เอาต์ header.xml
android:textColor="@color/white_text_color"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="@color/colorAccent"
- เรียกใช้แอปของคุณ ซึ่งควรมีลักษณะดังนี้ภาพหน้าจอด้านล่าง
ยินดีด้วย คุณดำเนินการเสร็จแล้ว
โปรเจ็กต์ Android Studio: RecyclerViewHeaders
- ส่วนหัวคือรายการที่ครอบคลุมความกว้างของรายการและทําหน้าที่เป็นชื่อหรือตัวคั่น รายการอาจมีส่วนหัวเพียงรายการเดียวเพื่ออธิบายเนื้อหาสินค้าหรือส่วนหัวหลายรายการเพื่อจัดกลุ่มสินค้าและแยกรายการออกจากกัน
RecyclerView
สามารถใช้ผู้ถือข้อมูลพร็อพเพอร์ตี้หลายรายเพื่อรองรับชุดรายการที่แตกต่างกันได้ เช่น ส่วนหัวและรายการ- วิธีหนึ่งในการเพิ่มส่วนหัวคือ การแก้ไขอะแดปเตอร์ให้ใช้
ViewHolder
อื่นด้วยการตรวจสอบดัชนีที่คุณต้องแสดงส่วนหัวAdapter
มีหน้าที่ติดตามส่วนหัว - อีกวิธีหนึ่งในการเพิ่มส่วนหัวคือการแก้ไขชุดข้อมูลสนับสนุน (รายการ) สําหรับตารางกริดข้อมูล ซึ่งเป็นสิ่งที่คุณทําใน Codelab นี้
ขั้นตอนการเพิ่มส่วนหัวมีดังนี้
- ย่อข้อมูลในรายการโดยสร้าง
DataItem
ที่มีส่วนหัวหรือข้อมูลได้ - สร้างผู้ถือมุมมองที่มีเลย์เอาต์สําหรับส่วนหัวในอะแดปเตอร์
- อัปเดตอะแดปเตอร์และวิธีการเพื่อใช้
RecyclerView.ViewHolder
ประเภทใดก็ได้ - ใน
onCreateViewHolder()
ให้แสดงประเภทเจ้าของข้อมูลพร็อพเพอร์ตี้ที่ถูกต้องสําหรับรายการข้อมูล - อัปเดต
SleepNightDiffCallback
ให้ทํางานกับชั้นเรียนDataItem
- สร้างฟังก์ชัน
addHeaderAndSubmitList()
ที่ใช้ Coroutine เพื่อเพิ่มส่วนหัวในชุดข้อมูล จากนั้นเรียกใช้submitList()
- นํา
GridLayoutManager.SpanSizeLookup()
ไปใช้เพื่อให้เฉพาะส่วนหัว 3 ช่องครอบคลุมความกว้างเท่านั้น
หลักสูตร Udacity:
เอกสารประกอบสําหรับนักพัฒนาซอฟต์แวร์ Android
ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน Codelab นี้ซึ่งเป็นส่วนหนึ่งของหลักสูตรที่นําโดยผู้สอน สิ่งที่ผู้สอนต้องทํามีดังนี้
- มอบหมายการบ้านหากจําเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานทําการบ้าน
- ตัดเกรดการบ้าน
ผู้สอนจะใช้คําแนะนําเหล่านี้เท่าใดก็ได้หรือตามที่ต้องการก็ได้ และสามารถกําหนดให้การบ้านอื่นๆ ที่ตนคิดว่าเหมาะสมได้
หากคุณใช้ Codelab ด้วยตัวเอง ก็ให้ใช้การบ้านเพื่อทดสอบความรู้ของคุณได้
ตอบคําถามเหล่านี้
คำถามที่ 1
ข้อความใดเกี่ยวกับ ViewHolder
ที่เป็นจริง
▢ อะแดปเตอร์จะใช้ได้ใน ViewHolder
หลายคลาสเพื่อเก็บส่วนหัวและข้อมูลประเภทต่างๆ
▢ คุณสามารถใช้ผู้ถือข้อมูลพร็อพเพอร์ตี้ได้เพียง 1 ราย และเป็นเจ้าของข้อมูลพร็อพเพอร์ตี้ 1 รายสําหรับส่วนหัวได้
▢ A RecyclerView
รองรับส่วนหัวหลายประเภท แต่ข้อมูลต้องเหมือนกันทุกประการ
▢ เมื่อเพิ่มส่วนหัว คุณมีคลาสย่อย RecyclerView
เพื่อแทรกส่วนหัวในตําแหน่งที่ถูกต้อง
คำถามที่ 2
คุณควรใช้โครูทีนกับ RecyclerView
เมื่อใด เลือกทุกข้อที่เป็นจริง
▢ ไม่เคยเลย RecyclerView
เป็นองค์ประกอบ UI และไม่ควรใช้โครูทีน
▢ โดยใช้โครูทีนสําหรับการทํางานที่ยาวนานซึ่งอาจทําให้ UI ช้าลง
▢ การดัดแปลงรายการอาจใช้เวลานาน และคุณควรดําเนินการโดยใช้โครูทีนเสมอ
▢ โดยใช้ Coroutine กับฟังก์ชันการระงับเพื่อหลีกเลี่ยงการบล็อกชุดข้อความหลัก
คำถามที่ 3
คุณไม่จําเป็นต้องทําสิ่งใดต่อไปนี้เมื่อใช้ ViewHolder
มากกว่า 1 รายการ
▢ ใน ViewHolder
ให้ส่งไฟล์เลย์เอาต์หลายไฟล์ให้สูงเกินจําเป็น
▢ ใน onCreateViewHolder()
แสดงผลประเภทเจ้าของข้อมูลพร็อพเพอร์ตี้ที่ถูกต้องสําหรับรายการข้อมูล
▢ ใน onBindViewHolder()
ให้เชื่อมโยงข้อมูลเฉพาะในกรณีที่ผู้ถือข้อมูลพร็อพเพอร์ตี้เป็นประเภทข้อมูลพร็อพเพอร์ตี้ที่ถูกต้องสําหรับรายการข้อมูล
▢ ลายเซ็นทั่วไปของอะแดปเตอร์อะแดปเตอร์เพื่อยอมรับ RecyclerView.ViewHolder
เริ่มบทเรียนถัดไป:
สําหรับลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ โปรดดูหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals