ใช้ไลบรารี car-ui-lib เพื่อเปิดระบบสาระบันเทิง (IVI) ในรถยนต์ที่ทำงานอย่างสอดคล้องกัน Codelab นี้จะแนะนำ car-ui-lib และวิธีใช้การวางซ้อนทรัพยากรรันไทม์ (RRO) เพื่อปรับแต่งคอมโพเนนต์ในไลบรารี
สิ่งที่คุณจะได้เรียนรู้
วิธีดำเนินการ
- ใส่คอมโพเนนต์
car-ui-libในแอป Android - ใช้ Gradle เพื่อสร้างแอป Android และ RRO
- ใช้ RRO กับ
car-ui-lib
โค้ดแล็บนี้ไม่ได้อธิบายรายละเอียดเกี่ยวกับวิธีการทำงานของ RRO ดูข้อมูลเพิ่มเติมได้จากหัวข้อเปลี่ยนค่าของทรัพยากรของแอปที่รันไทม์ และแก้ปัญหาการวางซ้อนทรัพยากรรันไทม์
ก่อนจะเริ่มต้น
สิ่งที่ต้องมีก่อน
โปรดตรวจสอบว่าคุณมีสิ่งต่อไปนี้ก่อนที่จะเริ่มต้น
คอมพิวเตอร์ที่มีบรรทัดคำสั่ง (เครื่อง Linux, Mac หรือ Windows ที่มี Windows Subsystem for Linux)
อุปกรณ์ Android หรือโปรแกรมจำลองที่เชื่อมต่อกับเครื่อง ดูหัวข้อดาวน์โหลดซอร์สโค้ด Android และสร้าง Android
ความรู้พื้นฐานเกี่ยวกับ RRO
สร้างแอป Android ใหม่
ระยะเวลา: 15 นาที
ในส่วนนี้ คุณสร้างโปรเจ็กต์ Android Studio ใหม่
สร้างแอปที่มี
EmptyActivityใน Android Studio
รูปที่ 1สร้างกิจกรรมว่าง ตั้งชื่อแอป
CarUiCodelabแล้วเลือกภาษา Java นอกจากนี้ คุณยังเลือกตำแหน่งไฟล์ได้หากต้องการ ยอมรับค่าเริ่มต้นสําหรับการตั้งค่าที่เหลือ
รูปที่ 2 ตั้งชื่อแอป แทนที่
activity_main.xmlด้วยโค้ดบล็อกต่อไปนี้<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sample_text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>บล็อกโค้ดนี้แสดงสตริง
sample_textซึ่งไม่ได้กําหนดเพิ่มสตริงทรัพยากร
sample_textแล้วตั้งค่าเป็น "Hello World!" ในไฟล์strings.xmlหากต้องการเปิดไฟล์นี้ ให้เลือก app > src > main > res > values > strings.xml<?xml version="1.0" encodin>g<="ut>f-8&q<uot;? resources st>ring name=&q<uot;app>_name<"CarUiCodelab/string> string <name=&q>u<ot;sample_>text"Hello World!/string /resourcesหากต้องการสร้างแอป ให้คลิกปุ่มเล่นสีเขียวที่ด้านขวาบน ซึ่งจะติดตั้ง APK ลงในโปรแกรมจำลองหรืออุปกรณ์ Android โดยอัตโนมัติผ่าน Gradle
แอปใหม่ควรเปิดขึ้นโดยอัตโนมัติในโปรแกรมจำลองหรืออุปกรณ์ Android หากไม่ได้เปิดไว้ ให้เปิดแอป CarUiCodelab จากตัวเปิดแอปซึ่งติดตั้งไว้แล้ว
ซึ่งจะปรากฏดังนี้
เพิ่ม car-ui-lib ลงในแอป Android
ระยะเวลา: 15 นาที
วิธีเพิ่ม car-ui-lib ลงในแอป
หากต้องการเพิ่มทรัพยากร Dependency
car-ui-libลงในไฟล์build.gradleของโปรเจ็กต์ ให้เลือกแอป > build.gradle ข้อมูลที่ต้องพึ่งพาควรปรากฏดังนี้dependencies { implementation 'com.android.car.ui:car-ui-lib:2.0.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' }
ใช้คอมโพเนนต์ car-ui-lib ในแอป Android
เมื่อคุณมี car-ui-lib แล้ว ให้เพิ่มแถบเครื่องมือลงในแอป
ในไฟล์
MainActivity.javaให้เขียนทับเมธอดonCreateดังนี้@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the toolbar controller instance. ToolbarController toolbar = CarUi.getToolbar(this); // Set the title on toolbar. toolbar.setTitle(getTitle()); // Set the logo to be shown with the title. toolbar.setLogo(R.mipmap.ic_launcher_round); }โปรดนำเข้า
ToolbarControllerดังนี้import com.android.car.ui.core.CarUi; import com.android.car.ui.toolbar.ToolbarController;หากต้องการใช้ธีม
Theme.CarUi.WithToolbarให้เลือก app > src > main > AndroidManifest.xml แล้วอัปเดตAndroidManifest.xmlให้ปรากฏดังต่อไปนี้<?xml version="1.0" encodin>g<="utf-8"? manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">; <package="com.example.caruicodelab" application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" >android:s<upportsRtl="true" android:theme="@style/Theme.CarUi.WithToolba>r" < tools:targ>etApi="31&qu<ot; activity android:name=&quo>t;.MainActivity&qu<ot; android:exported="true" > intent-fi<lter > ac<tion andr>oid:n<ame="an>dr<oid.inten>t.action.MAIN" / category android:name="android.intent.category.LAUNCHER" / /intent-filter /activity /application /manifestหากต้องการสร้างแอป ให้กดปุ่ม Play สีเขียวเหมือนเช่นเคย
เพิ่ม RRO ลงในแอป
ระยะเวลา: 30 นาที
หากคุณคุ้นเคยกับ RRO ให้ไปที่ส่วนถัดไปซึ่งจะอธิบายเรื่องเพิ่มตัวควบคุมสิทธิ์ลงในแอป หรือหากต้องการดูข้อมูลเบื้องต้นเกี่ยวกับ RRO โปรดดูหัวข้อเปลี่ยนค่าของทรัพยากรของแอปที่รันไทม์
เพิ่มตัวควบคุมสิทธิ์ลงในแอป
หากต้องการควบคุมทรัพยากรที่แพ็กเกจ RRO จะวางซ้อน ให้เพิ่มไฟล์ชื่อ overlayable.xml ลงในโฟลเดอร์ /res ของแอป ไฟล์นี้ทำหน้าที่เป็นเครื่องมือควบคุมสิทธิ์ระหว่างแอปของคุณ (เป้าหมาย) กับแพ็กเกจ RRO (การวางซ้อน)
เพิ่ม
res/values/overlayable.xmlลงในแอป แล้วคัดลอกเนื้อหาต่อไปนี้ลงในไฟล์<?xml version="1.0" encodin>g<="ut>f-8&q<uot;? resources overlayable> name=&qu<ot;CarUiCodelab">; pol<icy type="public" > item ty<pe=&quo>t;str<ing" na>m<e="sa>mple_text"/ /policy /overlayable /resourcesเนื่องจากสตริง
sample_textต้องวางซ้อนได้โดย RRO ให้ใส่ชื่อทรัพยากรใน overlayable.xml ของแอปไฟล์
overlayable.xmlต้องอยู่ในres/values/หากไม่OverlayManagerServiceจะหาตำแหน่งของไฟล์นั้นไม่ได้ดูข้อมูลเพิ่มเติมเกี่ยวกับทรัพยากรที่วางซ้อนได้และวิธีกำหนดค่าได้ที่จํากัดทรัพยากรที่วางซ้อนได้
สร้างแพ็กเกจ RRO
ในส่วนนี้ คุณจะได้สร้างแพ็กเกจ RRO เพื่อเปลี่ยนสตริงที่แสดงด้านบนจาก "Hello World!" เป็น "Hello World RRO"
หากต้องการสร้างโปรเจ็กต์ใหม่ ให้เลือกไฟล์ > ใหม่ > โปรเจ็กต์ใหม่ โปรดตรวจสอบว่าได้เลือกไม่มีกิจกรรมแทนกิจกรรมว่าง เนื่องจากแพ็กเกจ RRO มีเฉพาะทรัพยากร
การกำหนดค่าจะปรากฏคล้ายกับภาพด้านล่าง ตำแหน่งที่บันทึกรายการต่างๆ อาจแตกต่างกันไป ดังนี้
หลังจากสร้างโปรเจ็กต์
CarUiRROใหม่แล้ว ให้ประกาศโปรเจ็กต์เป็น RRO โดยการแก้ไขAndroidManifest.xml<?xml version="1.0" encodin>g<="utf-8"? manifest xmlns:android="http://schemas.android.com/apk/res/android" >packag<e="com.example.caruirro" > app<lication android:hasCode="false" / uses-sdk android:minSdkV>ersion<="29" android:targetSdkVersion="29"/ overlay android:targetPackage="com.example.caruicodelab" android:targetName="CarUiCodelab" > < andro>id:isStatic="false" android:resourcesMap="@xml/sample_overlay" / /manifestการดำเนินการนี้จะทำให้เกิดข้อผิดพลาดกับ
@xml/sample_overlayไฟล์resourcesMapจะแมปชื่อทรัพยากรจากแพ็กเกจเป้าหมายไปยังแพ็กเกจ RRO การตั้งค่า FlaghasCodeเป็นfalseเป็นสิ่งจำเป็นสำหรับแพ็กเกจ RRO นอกจากนี้ แพ็กเกจ RRO ต้องไม่มีไฟล์ DEXคัดลอกบล็อกโค้ดต่อไปนี้ลงใน
…/res/xml/sample_overlay.xml<?xml version="1.0" encodin>g<=">utf-8<"? overlay item target="string/sample_text">;< value=&>quot;@string/sample_text"/ /overlayวิธีเพิ่ม
sample_textลงใน…/res/values/strings.xml<?xml version="1.0" encodin>g<="ut>f-8&q<uot;? resources st>ring nam<e=">;app_<name"CarUiRRO/string> string nam<e=">;<sample_tex>t"Hello World RRO/string /resources
หากต้องการสร้างเป้าหมาย RRO ให้กดปุ่ม Play สีเขียวเพื่อสร้าง Gradle build ของ RRO ในโปรแกรมจำลองหรืออุปกรณ์ Android
หากต้องการยืนยันว่าติดตั้ง RRO อย่างถูกต้อง ให้เรียกใช้คำสั่งต่อไปนี้
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirroคำสั่งนี้จะแสดงข้อมูลที่เป็นประโยชน์เกี่ยวกับสถานะของแพ็กเกจ RRO ในระบบ
[ ]ระบุว่ามีการติดตั้ง RRO แล้วและพร้อมที่จะเปิดใช้งาน---บ่งชี้ว่าติดตั้ง RRO แล้ว แต่มีข้อผิดพลาด[X]หมายความว่ามีการติดตั้งและเปิดใช้งาน RRO แล้ว
หาก RRO มีข้อผิดพลาด โปรดดูแก้ปัญหาการวางซ้อนทรัพยากรรันไทม์ก่อนดำเนินการต่อ
วิธีเปิดใช้ RRO และยืนยันว่าเปิดใช้แล้ว
shell:~$ adb shell cmd overlay enable --user current com.example.caruirro shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [x] com.example.caruirro
แอปของคุณแสดงสตริง "Hello World RRO"
ยินดีด้วย คุณสร้าง RRO รายการแรกแล้ว
เมื่อใช้ RRO คุณอาจต้องใช้ Flag --no-resource-deduping และ --no-resource-removal ของเครื่องมือแพ็กเกจเนื้อหา Android (AAPT2) ที่อธิบายไว้ในตัวเลือกการลิงก์
คุณไม่จำเป็นต้องเพิ่ม Flag ใน Codelab นี้ แต่เราขอแนะนำให้ใช้ Flag ใน RRO เพื่อหลีกเลี่ยงการนำทรัพยากรออก (และปัญหาในการแก้ไขข้อบกพร่อง) คุณสามารถเพิ่มข้อมูลดังกล่าวลงในไฟล์ build.gradle ของ RRO ได้โดยทำดังนี้
android {
…
aaptOptions {
additionalParameters "--no-resource-deduping", "--no-resource-removal"
}
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Flag เหล่านี้ได้ที่หัวข้อสร้างแพ็กเกจและ AAPT2
แก้ไขคอมโพเนนต์ car-ui-lib โดยใช้ RRO ในแอป Android
หน้านี้จะอธิบายวิธีใช้การวางซ้อนทรัพยากรรันไทม์ (RRO) เพื่อแก้ไขคอมโพเนนต์จากไลบรารี car-ui-lib ในแอป Android
ตั้งค่าสีพื้นหลังของแถบเครื่องมือ
ระยะเวลา: 15 นาที
วิธีเปลี่ยนสีพื้นหลังของแถบเครื่องมือ
เพิ่มค่าต่อไปนี้ลงในแอป RRO และตั้งค่าทรัพยากรเป็นสีเขียวสด (
#0F0)<?xml version="1.0" encodin>g<="ut>f-8&q<uot;? resources drawable name="c>ar_u<i_toolbar>_<background>"#0F0/drawable /resourcesคลัง
car-ui-libมีทรัพยากรชื่อcar_ui_toolbar_backgroundเมื่อทรัพยากรนี้อยู่ในการกำหนดค่าของ RRO แถบเครื่องมือจะไม่เปลี่ยนแปลงเนื่องจากมีการกำหนดเป้าหมายค่าที่ไม่ถูกต้องใน
AndroidManifest.xmlของ RRO ให้อัปเดตtargetNameให้ชี้ไปที่car-ui-lib… android:targetName="car-ui-lib" …คุณต้องสร้างแพ็กเกจ RRO ใหม่สำหรับแต่ละแพ็กเกจเป้าหมายที่ต้องการ RRO ตัวอย่างเช่น เมื่อสร้างการวางซ้อนสําหรับเป้าหมาย 2 รายการที่แตกต่างกัน คุณต้องสร้าง Apk การวางซ้อน 2 รายการ
สร้าง ยืนยัน ติดตั้ง และเปิดใช้ RRO ในลักษณะเดียวกับก่อนหน้านี้
แอปของคุณจะปรากฏดังนี้
เลย์เอาต์และสไตล์ RRO
ระยะเวลา: 15 นาที
ในการฝึกนี้ คุณจะได้สร้างแอปใหม่ซึ่งคล้ายกับแอปที่สร้างไว้ก่อนหน้านี้ แอปนี้ช่วยให้วางเลย์เอาต์ซ้อนกันได้ ทำตามขั้นตอนเดิมหรือแก้ไขแอปที่มีอยู่
อย่าลืมเพิ่มบรรทัดต่อไปนี้ลงใน
overlayable.xml<?xml version="1.0" encodin>g<="ut>f-8<"? resources overlayable> name<="CarUiCodelab&>quot; < policy type="public" > item <type="string" name="sampl>e_text&<quot;/ item type="la>yout&<quot; n>ame<="activ>i<ty_main&qu>ot;/ item type="id" name="textView"/ /policy /overlayable /resourcesตรวจสอบว่า
activity_main.xmlปรากฏดังต่อไปนี้<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sample_text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>ในแอป RRO ให้สร้าง
res/layout/activity_main.xmlแล้วเพิ่มข้อมูลต่อไปนี้<?xml version="1.0" encodin>g<="utf-8"? FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" > < android:layout_height="match_parent" TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sample_text" android:textAppearance=">;<@style/TextA>ppearance.CarUi" android:layout_gravity="center_vertical|center_horizontal"/ /FrameLayoutอัปเดต
res/values/styles.xmlเพื่อเพิ่มสไตล์ของเราลงใน RRO โดยทำดังนี้<?xml version="1.0" encodin>g<="ut>f-8&q<uot;? resources style name="TextAppearance.CarUi" parent="an>droid:Tex<tAppearance.DeviceDefault&quo>t; < > item na<me="android:textColor&q>uot;#<0f0/i>tem < > <item name=>"android:textSize"100sp/item /style /resourcesเปลี่ยน
targetNameในAndroidManifest.xmlให้ชี้ไปที่ชื่อแอปใหม่… android:targetName="CarUiCodelab" …เพิ่มทรัพยากรลงในไฟล์
sample_overlay.xmlใน RRO<?xml version="1.0" encodin>g<=">utf-8<"? overlay item target="string/sample_text">; val<ue="@string/sample_text"/ item ta>rget=<"id/textView" value="@id/textView"/ item >t<arget=&q>uot;layout/activity_main" value="@layout/activity_main"/ /overlayสร้างและติดตั้งแอปและ RRO ในลักษณะเดียวกับก่อนหน้านี้ (ปุ่ม Play สีเขียว) อย่าลืมเปิดใช้ RRO
แอปและ RRO จะแสดงผลดังนี้ ข้อความ RRO ของ Hello World เป็นสีเขียวและอยู่ตรงกลางตามที่ระบุไว้ใน RRO ของเลย์เอาต์
เพิ่ม CarUiRecyclerView ลงในแอป
ระยะเวลา: 15 นาที
อินเทอร์เฟซ CarUiRecyclerView มี API ในการเข้าถึง RecyclerView ที่ปรับแต่งผ่านทรัพยากร car-ui-lib ตัวอย่างเช่น CarUiRecyclerView
จะตรวจสอบ Flag ที่รันไทม์เพื่อพิจารณาว่าควรเปิดใช้แถบเลื่อนหรือไม่ และเลือกเลย์เอาต์ที่เกี่ยวข้อง
หากต้องการเพิ่ม
CarUiRecyclerViewให้เพิ่มลงในไฟล์activity_main.xmlและMainActivity.javaคุณสามารถสร้างแอปใหม่ตั้งแต่ต้นหรือแก้ไขแอปที่มีอยู่ก็ได้ หากแก้ไขแอปที่มีอยู่ โปรดอย่าลืมนำทรัพยากรที่ไม่ได้ประกาศออกจากoverlayable.xmlactivity_main.xml<?xml version="1.0" encodin>g<="utf-8"? com.android.car.ui.recyclerview.CarUiRecyclerView android:id="@+id/list" android:layout_width="match_parent" >android:layout_height="match_parent"/ข้อผิดพลาดต่อไปนี้อาจปรากฏขึ้น ซึ่งคุณสามารถละเว้นได้
Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerViewตราบใดที่คลาสสะกดถูกต้องและคุณเพิ่ม
car-ui-libไว้เป็นข้อกำหนด คุณก็สามารถสร้างและคอมไพล์ APK ได้ หากต้องการนำข้อผิดพลาดออก ให้เลือกไฟล์ > ล้างแคช แล้วคลิกล้างและรีสตาร์ทเพิ่มรายการต่อไปนี้ไปยัง
MainActivity.javapackage com.example.caruicodelab; import android.app.Activity; import android.os.Bundle; import com.android.car.ui.core.CarUi; import com.android.car.ui.recyclerview.CarUiContentListItem; import com.android.car.ui.recyclerview.CarUiListItem; import com.android.car.ui.recyclerview.CarUiListItemAdapter; import com.android.car.ui.recyclerview.CarUiRecyclerView; import com.android.car.ui.toolbar.ToolbarController; import java.util.ArrayList; /** Activity with a simple car-ui layout. */ public class MainActivity extends Activity { private final ArrayList<CarUiListItem> mData = new ArrayList<>(); private CarUiListItemAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ToolbarController toolbar = CarUi.getToolbar(this); toolbar.setTitle(getTitle()); toolbar.setLogo(R.mipmap.ic_launcher_round); CarUiRecyclerView recyclerView = findViewById(R.id.list); mAdapter = new CarUiListItemAdapter(generateSampleData()); recyclerView.setAdapter(mAdapter); } private ArrayList<CarUiListItem> generateSampleData() { for (int i = 0; i < 20; i++) { CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.ICON); item.setTitle("Title " + i); item.setPrimaryIconType(CarUiContentListItem.IconType.CONTENT); item.setIcon(getDrawable(R.drawable.ic_launcher_foreground)); item.setBody("body " + i); mData.add(item); }return mData; }สร้างและติดตั้งแอปตามปกติ
ตอนนี้คุณจะเห็น CarUiRecyclerView ดังนี้
ใช้ RRO เพื่อนำแถบเลื่อนออก
ระยะเวลา: 10 นาที
ตัวอย่างนี้แสดงวิธีใช้ RRO เพื่อนำแถบเลื่อนออกจากCarUiRecyclerView
ใน RRO ให้เพิ่มและแก้ไขไฟล์ต่อไปนี้
AndroidManifest.xml<?xml version="1.0" encodin>g<="utf-8"? manifest xmlns:android="http://schemas.android.com/apk/res/android" >packag<e="com.example.caruirro" > app<lication android:hasCode="false" / uses-sdk android:minSdkV>ersion<="29" android:targetSdkVersion="29"/ overlay android:targetPackage="com.example.caruicodelab" android:targetName="car-ui-lib" > < andro>id:isStatic="false" android:resourcesMap="@xml/sample_overlay" / /manifestres/values/bools.xml<?xml version="1.0" encodin>g<="ut>f-8&q<uot;? resources bool name=">;car_<ui_sc>r<ollbar_ena>ble"false/bool /resourcesทรัพยากร
car_ui_scrollbar_enableคือทรัพยากรบูลีนcar-ui-libซึ่งควบคุมว่ามีแถบเลื่อนที่ปรับให้เหมาะกับรถยนต์พร้อมปุ่มขึ้นและลงในCarUiRecyclerViewหรือไม่ เมื่อตั้งค่าเป็นfalseCarUiRecyclerViewจะทํางานเหมือน AndroidXRecyclerViewres/xml/sample_overlay.xml<?xml version="1.0" encodin>g<=">utf-8<"? overlay item target="bool/car_ui_scrollbar_enable" value=&q>u<ot;@bool>/car_ui_scrollbar_enable"/ /overlay
สร้างและติดตั้งแอปตามปกติ ตอนนี้ระบบนำแถบเลื่อนออกจาก CarUiRecyclerView แล้ว
ใช้เลย์เอาต์วางซ้อนแถบเลื่อน CarUiRecyclerView
ระยะเวลา: 15 นาที
ในแบบฝึกหัดนี้ คุณจะแก้ไขเลย์เอาต์แถบเลื่อน CarUiRecyclerView
เพิ่มและแก้ไขไฟล์ต่อไปนี้ในแอป RRO
res/layout/car_ui_recycler_view_scrollbar.xml<?xml version="1.0" encodin>g<="utf-8"? RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="112dp" android:layout_height="match_pa>rent&<quot; android:id="@+id/car_ui_scroll_bar" > !-- <View height is dynamically calculated during layout. -- View android:id="@+id/car_ui_scrollbar_thumb" android:layout_width="6dp" android:layout_height="20dp" android:layout_alignParentTop="true" android:layout>_cent<erHorizontal="true" android:background="@drawable/car_ui_recyclerview_scrollbar_thumb"/ View android:id="@+id/car_ui_scrollbar_track" android:layout_width="10dp" android:layout_height="match_parent">; < android:layout_marginTop="10dp" android:layout_centerHorizontal="true" android:layout_above="@+id/car_ui_scrollbar_page_up"/ View android:layout_width="2dp" android:layout_height="match_parent" android:layout_marginTop="10>dp&qu<ot; android:background="#323232" android:layout_toLeftOf="@+id/car_ui_scrollbar_thumb" android:layout_above="@+id/car_ui_scrollbar_page_up" android:layout_marginRight="5dp"/ View android:layout_width="2dp" android:layout_hei>ght=&<quot;match_parent" android:layout_marginTop="10dp" android:background="#323232" android:layout_toRightOf="@+id/car_ui_scrollbar_thumb" android:layout_above="@+id/car_ui_scrollbar_page_up" android:layout_marginLeft="5dp"/ ImageView android:id="@+id/car_ui_scrollbar_page_up" android:layout_width="75dp" android:layout_height="75dp" android:f>ocusa<ble="false" android:hapticFeedbackEnabled="false" android:src="@drawable/car_ui_recyclerview_ic_up" android:scaleType="centerInside" android:background="?android:attr/selectableItemBackgroundBorderless" android:layout_centerHorizontal="true" android:layout_above="@+id/car_ui_scrollbar_page_down"/ ImageView android:id="@+id/car_ui_scrollbar_page_down&quo>t<; andro>id:layout_width="75dp" android:layout_height="75dp" android:focusable="false" android:hapticFeedbackEnabled="false" android:src="@drawable/car_ui_recyclerview_ic_down" android:scaleType="centerInside" android:background="?android:attr/selectableItemBackgroundBorderless" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true"/ /RelativeLayoutหากต้องการวางซ้อนไฟล์เลย์เอาต์ คุณต้องเพิ่มแอตทริบิวต์รหัสและเนมสเปซทั้งหมดลงใน
overlay.xmlของ RRO โปรดดูไฟล์ด้านล่างres/xml/sample_overlay.xml<?xml version="1.0" encodin>g<=">utf-<8"? overlay item target="drawable/car_ui_recyclerview_ic_down" value="@dra>wabl<e/car_ui_recyclerview_ic_down"/ item target="drawable/car_ui_recyclerview_ic_up&>quot<; value="@drawable/car_ui_recyclerview_ic_up"/ item target="drawable/car_ui_recyclerview_scroll>bar_<thumb" value="@drawable/car_ui_recyclerview_scrollbar_t>humb<"/ item target="id/car_ui_scroll_bar" value="@id/car>_ui_<scroll_bar"/ item target="id/car_ui_scrollbar_thumb" valu>e=&q<uot;@id/car_ui_scrollbar_thumb"/ item target="id/car_ui_scrollbar_>trac<k" value="@id/car_ui_scrollbar_track"/ item target="id/car_u>i_sc<rollbar_page_up" value="@id/car_ui_scrollbar_page_up"/ item target="id/car>_<ui_scrol>lbar_page_down" value="@id/car_ui_scrollbar_page_down"/ item target="layout/car_ui_recyclerview_scrollbar" value="@layout/car_ui_recyclerview_scrollbar"/ /overlayres/drawable/car_ui_recyclerview_ic_up.xml<?xml version="1.0" encodin>g<="utf-8"? vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:view>portW<idth="48.0" android:viewportHeight="48.0" path android:pathData="M14.83,30.83L>2<4,21.66>l9.17,9.17L36,28 24,16 12,28z" android:fillColor="#0000FF"/ /vectorres/drawable/car_ui_recyclerview_ic_down.xml<?xml version="1.0" encodin>g<="utf-8"? vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:view>portW<idth="48.0" android:viewportHeight="48.0" path android:pathData="M14.83,16.42L24,25.5>9<l9.17,->9.17L36,19.25l-12,12 -12,-12z" android:fillColor="#0000FF"/ /vectorres/drawable/car_ui_recyclerview_scrollbar_thumb.xml<?xml version="1.0" encodin>g<="utf-8"? shape xmlns:android="http://schemas.android.com/apk/res/android"> <android:shape="rectangle&q>uot; < solid android:color="#>0<000FF&>quot; / corners android:radius="100dp"/ /shapeเราขอแนะนำให้ตรวจสอบว่าไฟล์เหล่านี้โต้ตอบกันอย่างไร
มิติข้อมูลและสีจะได้รับการเขียนโค้ดไว้ล่วงหน้าเพื่อความสะดวก อย่างไรก็ตาม แนวทางปฏิบัติแนะนำคือการประกาศค่าเหล่านี้ใน
dimens.xmlและcolors.xmlหรือแม้แต่กำหนดเป็นไฟล์สีในโฟลเดอร์res/color/ดูข้อมูลเพิ่มเติมได้ที่รูปแบบโค้ด Java ของ AOSP สําหรับผู้มีส่วนร่วมสร้างและติดตั้งแอปตามปกติ คุณสร้าง
CarUiRecyclerViewที่มีแถบเลื่อนสีน้ำเงินและรางสีเทา
ยินดีด้วย เมื่อลูกศรทั้ง 2 ปรากฏที่ด้านล่างของแถบเลื่อน แสดงว่าคุณใช้ RRO กับไฟล์ทรัพยากรเลย์เอาต์ car-ui-lib โดยใช้ระบบการสร้าง Gradle ผ่าน Android Studio เรียบร้อยแล้ว
รายการใน RRO
ระยะเวลา: 15 นาที
ถึงตอนนี้ คุณได้นํา RRO ไปใช้กับคอมโพเนนต์ car-ui-lib โดยใช้คอมโพเนนต์เฟรมเวิร์ก (ไม่ใช่ AndroidX) หากต้องการใช้คอมโพเนนต์ AndroidX ใน RRO คุณต้องเพิ่มข้อกําหนดของคอมโพเนนต์นั้นลงในทั้งแอปและ RRO build.gradle. นอกจากนี้ ยังต้องเพิ่ม attrs ของคอมโพเนนต์นั้นลงใน overlayable.xml ในแอป รวมถึง sample_overlay.xml ใน RRO ด้วย
ไลบรารีของเรา (car-ui-lib) ใช้ ConstraintLayout ร่วมกับคอมโพเนนต์อื่นๆ ของ AndroidX ดังนั้น overlayable.xml จึงอาจมีลักษณะดังนี้
<?xml version='1.0' encoding=>&<#39;UTF-8>'<?
resources
overlayable n>ame="car-ui-li<b"
…
item type="attr" name=&>quot;layo<ut_constraintBottom_toBottomOf"/
item type=>"att<r" name="layout_constraintBottom_toTop>Of"/<
item type="attr" name="layout>_constrai<ntCircle"/
item type="attr" nam>e="l<ayout_constraintCircleAngle"/
item type=&qu>ot;attr&q<uot; name="layout_constraintCircleRadius"/
> i<tem type="attr" name="layout_constraintD>imensionR<atio"/
item type="attr" name=&>quot;layo<ut_constraintEnd_toEndOf"/
item type=&>quot;attr<" name="layout_constraintEnd_toStartOf"/>
<item type="attr" name="layout_constraintG>uide_begi<n"/
item type="attr" name=&qu>ot;layout<_constraintGuide_end"/
item type=">attr"<; name="layout_constraintGuide_percent"/
> item t<ype="attr" name="layout_constraintHeight_d>efault&qu<ot;/
item type="attr" name="layout_const>raintHeig<ht_max"/
item type="attr" name=">;layout_c<onstraintHeight_min"/
item type="att>r" n<ame="layout_constraintHeight_percent"/
> item ty<pe="attr" name="layout_constraintHorizont>al_bias&q<uot;/
item type="attr" name="lay>out_const<raintHorizontal_chainStyle"/
item type=&quo>t;attr&qu<ot; name="layout_constraintHorizontal_weight"/
> i<tem type="attr" name="layout_constraintL>eft_creat<or"/
item type="attr" name="l>ayout_con<straintLeft_toLeftOf"/
item type>="at<tr" name="layout_constraintLeft_toRightOf&q>uot;/
< item type="attr" name="layout_constr>aintRight<_creator"/
item type="attr" na>me="<layout_constraintRight_toLeftOf"/
item typ>e="a<ttr" name="layout_constraintRight_toRightOf"/
> item ty<pe="att>r<" nam>e="layout_constraintStart_toEndOf"/
item type="attr" name="layout_constraintStart_toStartOf"/
item type="attr" name="layout_constraintTag"/
item type="attr" name="layout_constraintTop_creator"/
item type="attr" name="layout_constraintTop_toBottomOf"/
item type="attr" name="layout_constraintTop_toTopOf"/
item type="attr" name="layout_constraintVertical_bias"/
item type="attr" name="layout_constraintVertical_chainStyle"/
…
/overlayable
/resources
เปลี่ยนเลย์เอาต์ของรายการใน
CarUiRecyclerViewโดยใช้ConstraintLayoutเพิ่มหรือแก้ไขไฟล์ต่อไปนี้ใน RROres/xml/sample_overlay.xml<?xml version="1.0" encodin>g<=">utf-<8"? overlay item target="id/car_ui_list_item_touch_interceptor" value="@id/c>ar_u<i_list_item_touch_interceptor"/ item target="id/car_ui_list_item_reduced_touch_interceptor" value>=&qu<ot;@id/car_ui_list_item_reduced_touch_interceptor"/ item target="id/car_ui_list_it>em_s<tart_guideline" value="@id/car_ui_list_item_start_guideline"/ item target=&>quot<;id/car_ui_list_item_icon_container" value="@id/car_ui_list_ite>m_ic<on_container"/ item target="id/car_ui_list_item_icon" value="@id/c>ar_u<i_list_item_icon"/ item target="id/car_ui_list_item_content_icon" val>ue=&<quot;@id/car_ui_list_item_content_icon"/ item target="id/car_u>i_li<st_item_avatar_icon" value="@id/car_ui_list_item_avatar_icon&qu>ot;/< item target="id/car_ui_list_item_title" value="@id/car_ui_list_item_title"/ item target="id/car_ui_li>st_i<tem_body" value="@id/car_ui_list_item_body"/ item target="id/car_ui_list_i>tem_<action_container_touch_interceptor" value="@id/car_ui_list_item_action_container_to>uch_<interceptor"/ item target="id/car_ui_list_item_action_container" value=&q>uot;<@id/car_ui_list_item_action_container"/ item target="id/car_ui_list_item_action_di>vide<r" value="@id/car_ui_list_item_action_divider"/ item target="id/car_ui_list_item>_swi<tch_widget" value="@id/car_ui_list_item_switch_widget"/ item target="id/car_>ui_l<ist_item_checkbox_widget" value="@id/car_ui_list_item_checkbox_widget"/ i>tem <target="id/car_ui_list_item_radio_button_widget" value="@id/car_ui_list_item_radio_butto>n_wi<dget"/ item target="id/car_ui_list_item_supplemental_icon" value="@id/car_>ui_l<ist_item_supplemental_icon"/ item target="id/car_ui_list_item_end_guideline&qu>ot; <value="@id/car_ui_list_item_end_guideline"/ item target="attr/layout_constrai>ntBo<ttom_toBottomOf" value="@attr/layout_constraintBottom_toBottomOf"/ item t>arge<t="attr/layout_constraintBottom_toTopOf" value="@attr/layout_constraintB>otto<m_toTopOf"/ item target="attr/layout_constraintEnd_toEndOf" value="@attr/lay>out_<constraintEnd_toEndOf"/ item target="attr/layout_constraintEnd_toStartOf" val>ue=&<quot;@attr/layout_constraintEnd_toStartOf"/ item target="attr/layout_constraintGuide>_beg<in" value="@attr/layout_constraintGuide_begin"/ item target="attr/layout_c>onst<raintGuide_end" value="@attr/layout_constraintGuide_end"/ item target="attr/>layo<ut_constraintHorizontal_bias" value="@attr/layout_constraintHorizontal_bias"/ > ite<m target="attr/layout_constraintLeft_toLeftOf" value="@attr/layout_constraintLeft_to>Left<Of"/ item target="attr/layout_constraintLeft_toRightOf" value="@attr/layou>t_co<nstraintLeft_toRightOf"/ item target="attr/layout_constraintRight_toLeftOf&quo>t; v<alue="@attr/layout_constraintRight_toLeftOf"/ item target="attr>/lay<out_constraintRight_toRightOf" value="@attr/layout_constraintRigh>t_to<RightOf"/ item target="attr/layout_constraintStart_toEndOf"> val<ue="@attr/layout_constraintStart_toEndOf"/ item target="attr/>layo<ut_constraintStart_toStartOf" value="@attr/layout_constraintStart_toS>tart<Of"/ item target="attr/layout_constraintTop_toBottomOf" v>alue<="@attr/layout_constraintTop_toBottomOf"/ item target="attr/layout_constraintTop_toTopOf&>quot<; value="@attr/layout_constraintTop_toTopOf"/ item target=>&<quot;att>r/layout_goneMarginBottom" value="@attr/layout_goneMarginBottom"/ item target="attr/layout_goneMarginEnd" value="@attr/layout_goneMarginEnd"/ item target="attr/layout_goneMarginLeft" value="@attr/layout_goneMarginLeft"/ item target="attr/layout_goneMarginRight" value="@attr/layout_goneMarginRight"/ item target="attr/layout_goneMarginStart" value="@attr/layout_goneMarginStart"/ item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/ item target="attr/layout_constraintVertical_chainStyle" value="@attr/layout_constraintVertical_chainStyle"/ item target="layout/car_ui_list_item" value="@layout/car_ui_list_item"/ /overlayres/layout/car_ui_list_item.xml<?xml version="1.0" encodin>g<="utf-8"? androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="carU>iListI<tem" android:minHeight="@dimen/car_ui_list_item_height" !-- The following touch interceptor views are sized to encompass the specific sub-sections of th>e lis<t item view to easily control the bounds of a background ripple effects. -- com.android.car.ui.SecureView android:id="@+id/car_ui_list_item_touch_interceptor" android:layout_width="0dp" android:layout_height="0dp" android:background="@drawable/car_ui_list_item_background" app:layout_constraintBottom_toBottomOf="parent" app:layout_constr>aintEn<d_toEndOf="parent" app:layout_constraintStart_toS>tartO<f="parent" app:layout_constraintTop_toTopOf="parent" / !-- This touch interceptor does not include the action container -- com.android.car.ui.SecureView android:id="@+id/car_ui_list_item_reduced_touch_interceptor" android:layout_width="0dp" android:layout_height="0dp" android:background="@drawable/car_ui_list_item_background" android:visibility="gone" app:layout_constraintBotto>m_toBo<ttomOf="parent" app:layout_constraintEnd_toStartOf="@id/car_ui_list_item_action_container" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" / androidx.constraintlayout.widget.Guideline android:i>d=&quo<t;@+id/car_ui_list_item_start_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_begin="@dimen/car_ui_list_item_start_inset" / FrameLayout android:id="@+id/car_ui_list_item_icon_containe>r" < android:layout_width="@dimen/car_ui_list_item_icon_container_width" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@+id/car_ui_list_item_start_guideline" app:layout_constraintTop_to>TopOf=&quo<t;parent" ImageView android:id="@+id/car_ui_list_item_icon" android:layout_width="@dimen/car_ui_list_item_icon_size" android:layout_height="@dimen/car_ui_list_item_icon_size" android:layout_gravity="center" android:visibility="gone&qu>ot; < android:scaleType="fitCenter" / ImageView android:id="@+id/car_ui_list_item_content_icon" android:layout_width="@dimen/car_ui_list_item_content_icon_width" android:layout_height="@dimen/car_ui_list_item_content_icon_height" android:layout_gravity="center" android:visibility="gone" a>ndroi<d:scaleType=>"<fitCenter" / ImageView android:id="@+id/car_ui_list_item_avatar_icon" android:background="@drawable/car_ui_list_item_avatar_icon_outline" android:layout_width="@dimen/car_ui_list_item_avatar_icon_width" android:layout_height="@dimen/car_ui_list_item_avatar_icon_height" android:layout_gravity="center" android:visibility="gone" android:scaleType="fitCenter" / /FrameLayout CarUiTextView android:id="@+id/car_ui_list_item_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin" android:singleLine="@bool/car_ui_list_item_single_line_title" android:>textA<ppearance="@style/TextAppearance.CarUi.ListItem" android:layout_gravity="right" android:gravity="right" android:textAlignment="viewEnd" app:layout_constraintBottom_toTopOf="@+id/car_ui_list_item_body" app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container" app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" / CarUiTextView android:id="@+id/car_ui_list_item_body" android:lay>out_wi<dth="0dp" android:layout_height="wrap_content" androi>d:lay<out_marginStart="@dimen/car_ui_list_item_text_start_margin" android:textAppearance="@style/TextAppearance.CarUi.ListItem.Body" android:layout_gravity="right" android:gravity="right" android:textAlignment="viewEnd" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container" app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container" app:layout_constraintTop_toBottomOf="@+id/car_ui_list_>item_t<itle" app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" / !-- This touch interceptor is sized and positioned to encompass the action container -- com.android.car.ui.SecureView android:id="@+id/car_ui_list_item_action_container_touch_interceptor" android:layout_width="0dp" android:layout_height=">0dp" < android:background="@drawable/car_ui_list_item_background" android:visibility="gone" app:layout_constraintBottom_toBottomOf="@id/car_ui_list_item_action_container" app:layout_constraintEnd_toEndOf="@id/car_ui_list_item_action_container" app:layout_constraintStart_toStartOf=&qu>ot;@id/car<_ui_list_item_action_container" app:layout_constraintTop_toTopOf="@id/car_ui_list_item_action_container" / FrameLayout android:id="@+id/car_ui_list_item_action_container" android:layout_width="wrap_content" android>:minWidth=<"@dimen/car_ui_list_item_icon_container_width" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/car_ui_list_item_end_guideline" app:layout_constraintTop>_toTopOf=&<quot;parent" View android:id="@+id/car_ui_list_item_action_divider" android:layout_width="@dimen/car_ui_list_item_action_divider_width" android:layout_height="@dimen/car_ui_list_item_action_divider_height" > android:l<ayout_gravity="start|center_vertical" android:background="@drawable/car_ui_list_item_divider" / Switch android:id="@+id/car_ui_list_item_switch_widget" android:layout_width="wrap_content" android:layout_height="wrap_content&q>uot; < >androi<d:layout_gravity="center" android:clickable="false" android:focusable="false" / CheckBox android:id="@+id/car_ui_list_item_checkbox_widget" android:layout_width="wrap_content" android:l>ay<out_height="wrap_content" an>droid:layout_gravity="center" android:clickable="false" android:focusable="false" / RadioButton android:id="@+id/car_ui_list_item_radio_button_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:clickable="false" android:focusable="false" / ImageView android:id="@+id/car_ui_list_item_supplemental_icon" android:layout_width="@dimen/car_ui_list_item_supplemental_icon_size" android:layout_height="@dimen/car_ui_list_item_supplemental_icon_size" android:layout_gravity="center" android:scaleType="fitCenter" / /FrameLayout androidx.constraintlayout.widget.Guideline android:id="@+id/car_ui_list_item_end_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_end="@dimen/car_ui_list_item_end_inset" / /androidx.constraintlayout.widget.ConstraintLayoutcar_ui_list_item.xmlอ้างอิงคอมโพเนนต์/แหล่งข้อมูลหลายรายการที่ไม่ได้รวมอยู่ในรายการที่ต้องพึ่งพาของแอป นั่นคือทรัพยากรcar-ui-libคุณสามารถแก้ไขปัญหานี้ได้โดยเพิ่มcar-ui-libเป็นส่วนที่ต้องพึ่งพาในแอป RRO ในapp/build.gradledependencies { implementation 'com.android.car.ui:car-ui-lib:2.0.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.4.0' }
ตอนนี้ชื่อและเนื้อหาจะจัดชิดขวาแทนการจัดชิดซ้าย
เราจะใช้ RRO กับ car-ui-lib โดยใช้คอมโพเนนต์ AndroidX (ConstraintLayout) เฉพาะในกรณีที่แอตทริบิวต์ของ car-ui-lib อยู่ในไฟล์ชื่อ overlayable.xml และ RRO sample_overlay.xml คุณสามารถทำสิ่งคล้ายกันในแอปของคุณเองได้ เพียงเพิ่มattrsที่เกี่ยวข้องทั้งหมดลงในoverlayable.xmlของแอป คล้ายกับcar-ui-lib
อย่างไรก็ตาม คุณจะไม่สามารถ RRO แอปที่ใช้คอมโพเนนต์ AndroidX ได้เมื่อแอปมี car-ui-lib เป็น Dependency ใน build.gradle (เมื่อแอปใช้คอมโพเนนต์ car-ui-lib) เนื่องจากมีการกําหนดการแมปแอตทริบิวต์ใน overlayable.xml ของไลบรารี car-ui-lib อยู่แล้ว การเพิ่มการแมปแอตทริบิวต์ลงใน overlayable.xml ของแอปโดยให้ car-ui-lib เป็นข้อกําหนดจะทําให้มีข้อผิดพลาด mergeDebugResources ดังที่แสดงด้านล่าง เนื่องจากแอตทริบิวต์เหล่านี้มีอยู่หลายไฟล์ใน overlayable.xml
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'