คอมโพเนนต์การนำทางคือ ที่สามารถจัดการการนำทางที่ซับซ้อน ภาพเคลื่อนไหวการเปลี่ยน การทำ Deep Link และการส่งอาร์กิวเมนต์ที่ตรวจสอบเวลาคอมไพล์ระหว่างหน้าจอในแอปของคุณ
เอกสารนี้ทำหน้าที่เป็นคำแนะนำทั่วไปในการย้ายข้อมูลแอปที่มีอยู่ไปยัง ใช้คอมโพเนนต์การนำทาง
ในระดับสูง การย้ายข้อมูลจะเกี่ยวข้องกับขั้นตอนเหล่านี้
ย้ายตรรกะ UI เฉพาะหน้าจอออกจากกิจกรรม - ย้าย UI ของแอป ออกจากกิจกรรมเพื่อให้แน่ใจว่าแต่ละกิจกรรมเป็นเจ้าของเฉพาะตรรกะของ คอมโพเนนต์ UI การนำทางส่วนกลาง เช่น
Toolbar
ในขณะที่มอบสิทธิ์ การนำแต่ละหน้าจอมาติดตั้งในส่วนย่อยหรือปลายทางที่กำหนดเองผสานรวมคอมโพเนนต์การนำทาง - สำหรับแต่ละกิจกรรม ให้สร้าง กราฟการนำทางซึ่งมีส่วนย่อยอย่างน้อย 1 รายการที่จัดการโดย กิจกรรม แทนที่ธุรกรรมส่วนย่อยด้วยการดำเนินการของคอมโพเนนต์การนำทาง
เพิ่มจุดหมายของกิจกรรม - แทนที่สาย
startActivity()
ด้วย โดยใช้ปลายทางกิจกรรมรวมกิจกรรม - รวมกราฟการนำทางในกรณีที่ กิจกรรมหลายอย่างจะใช้เลย์เอาต์เดียวกัน
สิ่งที่ต้องมีก่อน
คู่มือนี้จะถือว่าคุณได้ย้ายข้อมูลแอปไปใช้แล้ว ไลบรารี AndroidX หากคุณยังไม่ได้ดำเนินการ ย้ายข้อมูลโปรเจ็กต์เพื่อใช้ AndroidX ก่อนวันที่ ต่อไป
ย้ายตรรกะ UI เฉพาะหน้าจอออกจากกิจกรรม
กิจกรรมเป็นคอมโพเนนต์ระดับระบบที่เอื้อให้เกิดการโต้ตอบด้วยกราฟิก ระหว่างแอปของคุณกับ Android กิจกรรมมีการลงทะเบียนในไฟล์ Manifest ของแอป เพื่อให้ Android ทราบว่ามีกิจกรรมใดบ้างที่พร้อมเปิดให้ใช้ กิจกรรม ทำให้แอปของคุณตอบสนองต่อการเปลี่ยนแปลงของ Android ได้เช่นกัน เช่นเมื่อ UI ของแอปกำลังเข้าหรือออกจากเบื้องหน้า หมุน และอื่นๆ กิจกรรมยังสามารถเป็นที่ แชร์สถานะระหว่างหน้าจอ
กิจกรรมควรทำหน้าที่เป็นโฮสต์สำหรับการนำทางในบริบทของแอป และควรมีตรรกะและความรู้เกี่ยวกับวิธีการเปลี่ยนหน้าจอ ส่งข้อมูล และอื่นๆ อย่างไรก็ตาม คุณควรจัดการรายละเอียดของ UI ได้ง่ายกว่า ให้มีขนาดเล็กลงและใช้ซ้ำได้ การติดตั้งใช้งานที่แนะนำสำหรับ รูปแบบคือส่วนย่อย โปรดดู กิจกรรมเดียว: ทำไม เวลา และอย่างไร เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับข้อดีของการใช้ Fragment การนำทางรองรับส่วนย่อยผ่านทรัพยากร Dependency ของ navigation-อื่นๆ การนำทางยังรองรับ ประเภทปลายทางที่กำหนดเอง
หากแอปไม่ได้ใช้ Fragment สิ่งแรกที่คุณต้องทำคือการย้ายข้อมูล แต่ละหน้าจอในแอปเพื่อใช้ Fragment คุณจะไม่ลบกิจกรรมที่ ถึงจุดนี้ คุณกำลังสร้างส่วนย่อยเพื่อแสดงหน้าจอและตัวแบ่ง แยกตรรกะ UI ด้วยความรับผิดชอบ
ขอแนะนำ Fragment
เรามาดูตัวอย่างสำหรับขั้นตอนการแนะนำ Fragment กัน ของแอปพลิเคชันที่ประกอบด้วย 2 หน้าจอ ได้แก่ หน้าจอรายการผลิตภัณฑ์ รายละเอียดผลิตภัณฑ์ เมื่อคลิกผลิตภัณฑ์ในหน้าจอรายการ ผู้ใช้ไปยังหน้าจอรายละเอียดเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับผลิตภัณฑ์
ในตัวอย่างนี้ หน้าจอรายการและหน้าจอรายละเอียดเป็นกิจกรรมที่แยกกันในปัจจุบัน
สร้างเลย์เอาต์ใหม่เพื่อโฮสต์ UI
ในการแนะนำ Fragment ให้เริ่มต้นด้วยการสร้างไฟล์เลย์เอาต์ใหม่สำหรับกิจกรรมเพื่อ จะเป็นโฮสต์ การดำเนินการนี้จะแทนที่เลย์เอาต์มุมมองเนื้อหาปัจจุบันของกิจกรรม
หากต้องการดูมุมมองอย่างง่าย คุณสามารถใช้ FrameLayout
ได้ ดังที่แสดงใน
ตัวอย่าง product_list_host
:
<FrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_content"
android:layout_height="match_parent"
android:layout_width="match_parent" />
แอตทริบิวต์ id
คือส่วนเนื้อหาที่เราจะเพิ่ม
ส่วนย่อย
ถัดไป แก้ไขการอ้างอิงไฟล์เลย์เอาต์ในฟังก์ชัน onCreate()
ของกิจกรรม
ในฟังก์ชัน onCreate ของกิจกรรมให้ชี้ไปยังไฟล์เลย์เอาต์ใหม่นี้
Kotlin
class ProductListActivity : AppCompatActivity() { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Replace setContentView(R.layout.product_list) with the line below setContentView(R.layout.product_list_host) ... } }
Java
public class ProductListActivity extends AppCompatActivity { ... @Override public void onCreate(@Nullable Bundle savedInstanceState) { ... // Replace setContentView(R.layout.product_list); with the line below setContentView(R.layout.product_list_host); ... } }
การออกแบบที่มีอยู่ (ในตัวอย่างนี้คือ product_list
) จะใช้เป็นมุมมองรูท
สำหรับส่วนย่อยที่คุณกำลังจะสร้าง
สร้างส่วนย่อย
สร้างส่วนย่อยใหม่เพื่อจัดการ UI สำหรับหน้าจอของคุณ แนวทางปฏิบัติที่ดีคือ
ให้สอดคล้องกับชื่อโฮสต์กิจกรรมของคุณ ข้อมูลโค้ดด้านล่างใช้
ProductListFragment
เช่น
Kotlin
class ProductListFragment : Fragment() { // Leave empty for now. }
Java
public class ProductListFragment extends Fragment { // Leave empty for now. }
ย้ายตรรกะกิจกรรมไปไว้ในส่วนย่อย
เมื่อกำหนดส่วนย่อยแล้ว ขั้นตอนถัดไปคือการย้ายตรรกะ UI สำหรับ
หน้าจอนี้จากกิจกรรมลงในส่วนย่อยใหม่นี้ หากคุณมาจาก
สถาปัตยกรรมที่อิงตามกิจกรรม คุณอาจมีตรรกะในการสร้างยอดดูจำนวนมาก
เกิดขึ้นในฟังก์ชัน onCreate()
ของกิจกรรม
ต่อไปนี้คือตัวอย่างหน้าจอตามกิจกรรมที่มีตรรกะ UI ที่เราต้องย้าย
Kotlin
class ProductListActivity : AppCompatActivity() { // Views and/or ViewDataBinding references, Adapters... private lateinit var productAdapter: ProductAdapter private lateinit var binding: ProductListActivityBinding ... // ViewModels, System Services, other Dependencies... private val viewModel: ProductListViewModel by viewModels() ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // View initialization logic DataBindingUtil.setContentView(this, R.layout.product_list_activity) // Post view initialization logic // Connect adapters productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener {...} // Subscribe to state viewModel.products.observe(this, Observer { myProducts -> ... }) // ...and so on } ... }
Java
public class ProductListActivity extends AppCompatActivity { // Views and/or ViewDataBinding references, adapters... private ProductAdapter productAdapter; private ProductListActivityBinding binding; ... // ViewModels, system services, other dependencies... private ProductListViewModel viewModel; ... @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // View initialization logic DataBindingUtil.setContentView(this, R.layout.product_list_activity); // Post view initialization logic // Connect adapters productAdapter = new ProductAdapter(productClickCallback); binding.productsList.setAdapter(productAdapter); // Initialize ViewModels and other dependencies ProductListViewModel viewModel = new ViewModelProvider(this).get(ProductListViewModel.java); // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener(v -> { ... }); // Subscribe to state viewModel.getProducts().observe(this, myProducts -> ... ); // ...and so on }
กิจกรรมของคุณอาจกำลังควบคุมเวลาและวิธีที่ผู้ใช้ไปยัง หน้าจอถัดไป ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
// Provided to ProductAdapter in ProductListActivity snippet. private val productClickCallback = ProductClickCallback { product -> show(product) } fun show(product: Product) { val intent = Intent(this, ProductActivity::class.java) intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.id) startActivity(intent) }
Java
// Provided to ProductAdapter in ProductListActivity snippet. private ProductClickCallback productClickCallback = this::show; private void show(Product product) { Intent intent = new Intent(this, ProductActivity.class); intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.getId()); startActivity(intent); }
ภายในส่วนย่อยของคุณ คุณกระจายงานนี้ระหว่าง
onCreateView()
และ
onViewCreated()
,
โดยใช้ตรรกะการนำทางเหลืออยู่ในกิจกรรมเท่านั้น
Kotlin
class ProductListFragment : Fragment() { private lateinit var binding: ProductListFragmentBinding private val viewModel: ProductListViewModel by viewModels() // View initialization logic override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { binding = DataBindingUtil.inflate( inflater, R.layout.product_list, container, false ) return binding.root } // Post view initialization logic override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // Connect adapters productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener {...} // Subscribe to state viewModel.products.observe(this, Observer { myProducts -> ... }) // ...and so on } // Provided to ProductAdapter private val productClickCallback = ProductClickCallback { product -> if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { (requireActivity() as ProductListActivity).show(product) } } ... }
Java
public class ProductListFragment extends Fragment { private ProductAdapter productAdapter; private ProductListFragmentBinding binding; // View initialization logic @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = DataBindingUtil.inflate( inflater, R.layout.product_list_fragment, container, false); return binding.getRoot(); } // Post view initialization logic @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // Connect adapters binding.productsList.setAdapter(productAdapter); // Initialize ViewModels and other dependencies ProductListViewModel viewModel = new ViewModelProvider(this) .get(ProductListViewModel.class); // Initialize view properties, set click listeners, etc. binding.productsSearchBtn.setOnClickListener(...) // Subscribe to state viewModel.getProducts().observe(this, myProducts -> { ... }); // ...and so on // Provided to ProductAdapter private ProductClickCallback productClickCallback = new ProductClickCallback() { @Override public void onClick(Product product) { if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { ((ProductListActivity) requireActivity()).show(product); } } }; ... }
ใน ProductListFragment
สังเกตว่าไม่มีการเรียก
setContentView()
เพื่อขยายและเชื่อมต่อเลย์เอาต์ ในส่วนย่อย onCreateView()
จะเริ่มต้น
มุมมองระดับรูท onCreateView()
อินสแตนซ์ของ
LayoutInflater
ซึ่งสามารถใช้เพื่อ
ขยายมุมมองรูทตามไฟล์ทรัพยากรของเลย์เอาต์ ตัวอย่างนี้ใช้
เลย์เอาต์ product_list
ที่มีอยู่ซึ่งกิจกรรมใช้เนื่องจากไม่มีรายการใด
ก็จำเป็นต้องเปลี่ยนเป็น
เลย์เอาต์นั้นเอง
หากมีตรรกะ UI อยู่ใน onStart()
onResume()
ของกิจกรรม
ฟังก์ชัน onPause()
หรือ onStop()
ที่ไม่เกี่ยวข้องกับการนำทาง คุณสามารถ
ให้ย้ายฟังก์ชันเหล่านั้นไปยังฟังก์ชันที่มีชื่อเดียวกันบนส่วนย่อย
เริ่มต้นส่วนย่อยในกิจกรรมโฮสต์
เมื่อคุณย้ายตรรกะ UI ทั้งหมดลงไปยังส่วนย่อยแล้ว มีเพียงการนำทางเท่านั้น ตรรกะควรยังคงอยู่ในกิจกรรม
Kotlin
class ProductListActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.product_list_host) } fun show(product: Product) { val intent = Intent(this, ProductActivity::class.java) intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.id) startActivity(intent) } }
Java
public class ProductListActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.product_list_host); } public void show(Product product) { Intent intent = new Intent(this, ProductActivity.class); intent.putExtra(ProductActivity.KEY_PRODUCT_ID, product.getId()); startActivity(intent); } }
ขั้นตอนสุดท้ายคือการสร้างอินสแตนซ์ของส่วนย่อยใน onCreate()
จากนั้น
หลังจากตั้งค่ามุมมองเนื้อหา
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.product_list_host) if (savedInstanceState == null) { val fragment = ProductListFragment() supportFragmentManager .beginTransaction() .add(R.id.main_content, fragment) .commit() } }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.product_list_host); if (savedInstanceState == null) { ProductListFragment fragment = new ProductListFragment(); getSupportFragmentManager() .beginTransaction() .add(R.id.main_content, fragment) .commit(); } }
ดังที่แสดงในตัวอย่างนี้ FragmentManager
จะบันทึกและคืนค่าโดยอัตโนมัติ
ส่วนย่อยในการเปลี่ยนแปลงการกำหนดค่า คุณจึงต้องเพิ่มส่วนย่อยก็ต่อเมื่อ
savedInstanceState
เป็นค่าว่าง
ส่งต่อ Intent เพิ่มเติมไปยังส่วนย่อย
หากกิจกรรมได้รับ Extras
ผ่านทาง Intent คุณสามารถส่งรายการเหล่านี้ไปยัง
เป็นอาร์กิวเมนต์โดยตรง
ในตัวอย่างนี้ ProductDetailsFragment
ได้รับอาร์กิวเมนต์โดยตรง
จาก Intent เพิ่มเติมของกิจกรรม
Kotlin
... if (savedInstanceState == null) { val fragment = ProductDetailsFragment() // Intent extras and Fragment Args are both of type android.os.Bundle. fragment.arguments = intent.extras supportFragmentManager .beginTransaction() .add(R.id.main_content, fragment) .commit() } ...
Java
... if (savedInstanceState == null) { ProductDetailsFragment fragment = new ProductDetailsFragment(); // Intent extras and fragment Args are both of type android.os.Bundle. fragment.setArguments(getIntent().getExtras()); getSupportFragmentManager() .beginTransaction() .add(R.id.main_content, fragment) .commit(); } ...
ณ จุดนี้ คุณควรสามารถทดสอบการเรียกใช้แอปด้วยหน้าจอแรกได้แล้ว อัปเดตเพื่อใช้ส่วนย่อยแล้ว ย้ายข้อมูลที่เหลือต่อตามกิจกรรม เพื่อใช้เวลาในการทดสอบหลังจากทำซ้ำแต่ละครั้ง
ผสานรวมคอมโพเนนต์การนำทาง
เมื่อใช้สถาปัตยกรรมที่อิงตามส่วนย่อย คุณก็พร้อมที่จะเริ่มผสานรวมคอมโพเนนต์การนำทางแล้ว
ขั้นแรก ให้เพิ่มทรัพยากร Dependency ของการนำทางล่าสุดลงในโปรเจ็กต์ของคุณ โดยทำตามวิธีต่อไปนี้ วิธีการใน บันทึกประจำรุ่นของไลบรารีการนำทาง
สร้างกราฟการนำทาง
คอมโพเนนต์การนำทางจะแสดงการกำหนดค่าการนำทางของแอปใน ไฟล์แหล่งข้อมูลเป็นกราฟ เช่นเดียวกับการแสดงจำนวนการดูของแอป วิธีนี้ช่วย จัดระเบียบการนำทางของแอปไว้นอกฐานของโค้ด และให้ ให้คุณแก้ไขการนำทางของแอปด้วยภาพได้
หากต้องการสร้างกราฟการนำทาง ให้เริ่มต้นด้วยการสร้างโฟลเดอร์ทรัพยากรใหม่ชื่อ
navigation
ในการเพิ่มกราฟ ให้คลิกขวาที่ไดเรกทอรีนี้ และเลือก
ใหม่ > ไฟล์ทรัพยากรการนำทาง
คอมโพเนนต์การนำทางใช้กิจกรรม
โฮสต์สำหรับการนำทาง
และสลับส่วนย่อยแต่ละรายการเป็นโฮสต์นั้นเมื่อผู้ใช้ของคุณไปยังส่วนต่างๆ
แอปของคุณ ก่อนเริ่มออกแบบการนำทางของแอป
ต้องกำหนดค่า NavHost
ภายในกิจกรรมที่จะโฮสต์รายการนี้
กราฟ เนื่องจากเราใช้ส่วนย่อย เราจึงสามารถใช้คอมโพเนนต์การนำทาง
การใช้งาน NavHost
เริ่มต้น
NavHostFragment
NavHostFragment
ได้รับการกำหนดค่าผ่าน FragmentContainerView
วางไว้ภายในกิจกรรมของโฮสต์ ดังที่แสดงในตัวอย่างต่อไปนี้
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/product_list_graph"
app:defaultNavHost="true"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
แอตทริบิวต์ app:NavGraph
ชี้ไปยังกราฟการนำทางที่เกี่ยวข้องกับ
โฮสต์การนำทาง การตั้งค่าคุณสมบัตินี้จะขยายกราฟการนำทางและตั้งค่ากราฟ
ใน NavHostFragment
แอตทริบิวต์ app:defaultNavHost
จะช่วยให้มั่นใจได้ว่า
ว่า NavHostFragment
ดักจับปุ่ม "ย้อนกลับ" ของระบบ
หากคุณใช้การนำทางระดับบนสุด เช่น DrawerLayout
หรือ
BottomNavigationView
, FragmentContainerView
นี้
จะแทนที่องค์ประกอบมุมมองเนื้อหาหลักของคุณ โปรดดู
อัปเดตคอมโพเนนต์ UI ด้วย NavigationUI
เพื่อดูตัวอย่าง
สำหรับเลย์เอาต์ที่เรียบง่าย คุณสามารถรวม FragmentContainerView
นี้
เป็นองค์ประกอบย่อยของราก ViewGroup
:
<FrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/main_content"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/product_list_graph"
app:defaultNavHost="true"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
หากคุณคลิกแท็บการออกแบบที่ด้านล่าง คุณจะเห็นกราฟ
กับรายการที่แสดงด้านล่าง ที่ด้านซ้ายบนของกราฟ ใต้
ปลายทางคุณสามารถดูการอ้างอิงถึงกิจกรรม NavHost
ได้ในแบบฟอร์ม
จาก layout_name (resource_id)
คลิกปุ่มบวก ใกล้กับด้านบนเพื่อเพิ่มส่วนย่อยลงในกราฟนี้
คอมโพเนนต์การนำทางจะอ้างอิงแต่ละหน้าจอว่าเป็นปลายทาง ปลายทางอาจเป็นส่วนย่อย กิจกรรม หรือปลายทางที่กำหนดเอง คุณสามารถเพิ่ม ปลายทางประเภทใดก็ได้ไปยังกราฟของคุณ แต่โปรดทราบว่าจุดหมายของกิจกรรม ถือเป็นปลายทางเทอร์มินัลเพราะเมื่อคุณไปยังกิจกรรม คุณดำเนินการภายในโฮสต์การนำทางและกราฟที่แยกต่างหาก
คอมโพเนนต์การนำทางหมายถึงวิธีที่ผู้ใช้มาจาก ปลายทางไปยังปลายทางอื่นเป็นการดำเนินการ การดำเนินการยังสามารถอธิบายการเปลี่ยน ภาพเคลื่อนไหวและลักษณะการทำงานของป๊อป
นำธุรกรรมส่วนย่อยออก
และตอนนี้คุณกำลังใช้คอมโพเนนต์การนำทาง ถ้าคุณกำลังไปยังหน้าจอต่างๆ ที่ยึดตามส่วนย่อยภายใต้กิจกรรมเดียวกัน คุณจะสามารถนำออก
FragmentManager
การโต้ตอบ
หากแอปใช้ Fragment หลายรายการในกิจกรรมเดียวกันหรือระดับบนสุด
เช่น เลย์เอาต์ลิ้นชักหรือการนำทางด้านล่าง
โดยใช้ FragmentManager
และ
FragmentTransactions
เพื่อเพิ่มหรือแทนที่ส่วนย่อยในส่วนเนื้อหาหลักของ UI การดำเนินการนี้สามารถ
แทนและทำให้ง่ายขึ้นด้วยคอมโพเนนต์การนำทางโดยแสดงการทำงาน
เพื่อลิงก์ปลายทางภายในกราฟ แล้วนำทางโดยใช้
NavController
ต่อไปนี้คือสถานการณ์ที่คุณอาจพบ พร้อมกับวิธีดำเนินการ สำหรับแต่ละสถานการณ์
กิจกรรมเดียวที่จัดการส่วนย่อยหลายรายการ
หากคุณมีกิจกรรมเดียวที่จัดการส่วนย่อยหลายรายการ กิจกรรมของคุณ โค้ดอาจมีลักษณะเช่นนี้
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Logic to load the starting destination // when the Activity is first created if (savedInstanceState == null) { val fragment = ProductListFragment() supportFragmentManager.beginTransaction() .add(R.id.fragment_container, fragment, ProductListFragment.TAG) .commit() } } // Logic to navigate the user to another destination. // This may include logic to initialize and set arguments on the destination // fragment or even transition animations between the fragments (not shown here). fun navigateToProductDetail(productId: String) { val fragment = new ProductDetailsFragment() val args = Bundle().apply { putInt(KEY_PRODUCT_ID, productId) } fragment.arguments = args supportFragmentManager.beginTransaction() .addToBackStack(ProductDetailsFragment.TAG) .replace(R.id.fragment_container, fragment, ProductDetailsFragment.TAG) .commit() } }
Java
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Logic to load the starting destination when the activity is first created. if (savedInstanceState == null) { val fragment = ProductListFragment() supportFragmentManager.beginTransaction() .add(R.id.fragment_container, fragment, ProductListFragment.TAG) .commit(); } } // Logic to navigate the user to another destination. // This may include logic to initialize and set arguments on the destination // fragment or even transition animations between the fragments (not shown here). public void navigateToProductDetail(String productId) { Fragment fragment = new ProductDetailsFragment(); Bundle args = new Bundle(); args.putInt(KEY_PRODUCT_ID, productId); fragment.setArguments(args); getSupportFragmentManager().beginTransaction() .addToBackStack(ProductDetailsFragment.TAG) .replace(R.id.fragment_container, fragment, ProductDetailsFragment.TAG) .commit(); } }
ภายในปลายทางต้นทาง คุณอาจเรียกใช้ฟังก์ชันการนำทางใน การตอบกลับบางกิจกรรมดังที่แสดงด้านล่าง
Kotlin
class ProductListFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // In this example a callback is passed to respond to an item clicked // in a RecyclerView productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) } ... // The callback makes the call to the activity to make the transition. private val productClickCallback = ProductClickCallback { product -> (requireActivity() as MainActivity).navigateToProductDetail(product.id) } }
Java
public class ProductListFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // In this example a callback is passed to respond to an item clicked in a RecyclerView productAdapter = new ProductAdapter(productClickCallback); binding.productsList.setAdapter(productAdapter); } ... // The callback makes the call to the activity to make the transition. private ProductClickCallback productClickCallback = product -> ( ((MainActivity) requireActivity()).navigateToProductDetail(product.getId()) ); }
ซึ่งสามารถแทนที่โดยการอัปเดตกราฟการนำทางเพื่อกำหนด ปลายทางเริ่มต้นและการดำเนินการเพื่อลิงก์ปลายทางและกำหนด อาร์กิวเมนต์ที่จำเป็น
<navigation 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:id="@+id/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List"
tools:layout="@layout/product_list">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_detail" />
</fragment>
<fragment
android:id="@+id/product_detail"
android:name="com.example.android.persistence.ui.ProductDetailFragment"
android:label="Product Detail"
tools:layout="@layout/product_detail">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
จากนั้นคุณจะอัปเดตกิจกรรมได้โดยทำดังนี้
Kotlin
class MainActivity : AppCompatActivity() { // No need to load the start destination, handled automatically by the Navigation component override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
Java
public class MainActivity extends AppCompatActivity { // No need to load the start destination, handled automatically by the Navigation component @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
กิจกรรมไม่ต้องใช้เมธอด navigateToProductDetail()
แล้ว ในอีก
เราจะอัปเดต ProductListFragment
เพื่อใช้ NavController
ในการนำทาง
ไปยังหน้าจอรายละเอียดผลิตภัณฑ์ถัดไป
ส่งต่ออาร์กิวเมนต์อย่างปลอดภัย
คอมโพเนนต์การนำทางมีปลั๊กอิน Gradle ชื่อ อาร์กิวเมนต์ที่ปลอดภัย ที่สร้างคลาสออบเจ็กต์และเครื่องมือสร้างแบบง่ายๆ สำหรับการเข้าถึงแบบ Type-safe อาร์กิวเมนต์ที่ระบุสำหรับปลายทางและการทำงาน
เมื่อใช้ปลั๊กอินแล้ว อาร์กิวเมนต์ใดก็ตามที่กำหนดไว้ในปลายทางใน
กราฟการนำทางทำให้เฟรมเวิร์กคอมโพเนนต์การนำทางสร้าง
คลาส Arguments
ที่ระบุอาร์กิวเมนต์ที่ปลอดภัยตามประเภทในปลายทางเป้าหมาย
การกำหนดการดำเนินการจะทำให้ปลั๊กอินสร้างการกำหนดค่า Directions
ซึ่งสามารถใช้บอก NavController
เกี่ยวกับวิธีนำทางผู้ใช้ไปยัง
ปลายทาง เมื่อการดำเนินการชี้ไปยังปลายทางที่จำเป็นต้องใช้
อาร์กิวเมนต์ คลาส Directions
ที่สร้างขึ้นจะมี Method ของตัวสร้าง
ซึ่งจำเป็นต้องใช้พารามิเตอร์เหล่านั้น
ภายในส่วนย่อย ให้ใช้ NavController
และคลาส Directions
ที่สร้างขึ้นเพื่อ
จะระบุอาร์กิวเมนต์ type-safe กับปลายทางเป้าหมาย ดังที่ปรากฏใน
ตัวอย่าง:
Kotlin
class ProductListFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // In this example a callback is passed to respond to an item clicked in a RecyclerView productAdapter = ProductAdapter(productClickCallback) binding.productsList.setAdapter(productAdapter) } ... // The callback makes the call to the NavController to make the transition. private val productClickCallback = ProductClickCallback { product -> val directions = ProductListDirections.navigateToProductDetail(product.id) findNavController().navigate(directions) } }
Java
public class ProductListFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { // In this example a callback is passed to respond to an item clicked in a RecyclerView productAdapter = new ProductAdapter(productClickCallback); binding.productsList.setAdapter(productAdapter); } ... // The callback makes the call to the activity to make the transition. private ProductClickCallback productClickCallback = product -> { ProductListDirections.ViewProductDetails directions = ProductListDirections.navigateToProductDetail(product.getId()); NavHostFragment.findNavController(this).navigate(directions); }; }
การนำทางระดับบนสุด
หากแอปใช้ DrawerLayout
คุณอาจมีตรรกะการกำหนดค่าจำนวนมาก
ในกิจกรรมที่จัดการการเปิดและปิดลิ้นชัก และไปยัง
ปลายทางอื่นๆ
กิจกรรมที่เป็นผลลัพธ์อาจมีลักษณะดังนี้
Kotlin
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar: Toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) val navView: NavigationView = findViewById(R.id.nav_view) val toggle = ActionBarDrawerToggle( this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close ) drawerLayout.addDrawerListener(toggle) toggle.syncState() navView.setNavigationItemSelectedListener(this) } override fun onBackPressed() { val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) if (drawerLayout.isDrawerOpen(GravityCompat.START)) { drawerLayout.closeDrawer(GravityCompat.START) } else { super.onBackPressed() } } override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. when (item.itemId) { R.id.home -> { val homeFragment = HomeFragment() show(homeFragment) } R.id.gallery -> { val galleryFragment = GalleryFragment() show(galleryFragment) } R.id.slide_show -> { val slideShowFragment = SlideShowFragment() show(slideShowFragment) } R.id.tools -> { val toolsFragment = ToolsFragment() show(toolsFragment) } } val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout) drawerLayout.closeDrawer(GravityCompat.START) return true } } private fun show(fragment: Fragment) { val drawerLayout = drawer_layout as DrawerLayout val fragmentManager = supportFragmentManager fragmentManager .beginTransaction() .replace(R.id.main_content, fragment) .commit() drawerLayout.closeDrawer(GravityCompat.START) }
Java
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); navigationView.setNavigationItemSelectedListener(this); } @Override public void onBackPressed() { DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); if (id == R.id.home) { Fragment homeFragment = new HomeFragment(); show(homeFragment); } else if (id == R.id.gallery) { Fragment galleryFragment = new GalleryFragment(); show(galleryFragment); } else if (id == R.id.slide_show) { Fragment slideShowFragment = new SlideShowFragment(); show(slideShowFragment); } else if (id == R.id.tools) { Fragment toolsFragment = new ToolsFragment(); show(toolsFragment); } DrawerLayout drawer = findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } private void show(Fragment fragment) { DrawerLayout drawerLayout = findViewById(R.id.drawer_layout); FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager .beginTransaction() .replace(R.id.main_content, fragment) .commit(); drawerLayout.closeDrawer(GravityCompat.START); } }
หลังจากที่คุณเพิ่มคอมโพเนนต์การนำทางในโครงการและสร้าง
กราฟการนำทาง ให้เพิ่มปลายทางเนื้อหาแต่ละแห่งจากกราฟของคุณ (เช่น
หน้าแรก แกลเลอรี สไลด์โชว์ และเครื่องมือจากตัวอย่างด้านบน) ตรวจสอบให้แน่ใจว่า
ว่าค่า id
ของรายการในเมนูตรงกับค่า id
ปลายทางที่เชื่อมโยง
ดังที่แสดงด้านล่าง
<!-- activity_main_drawer.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="@+id/home"
android:icon="@drawable/ic_menu_camera"
android:title="@string/menu_home" />
<item
android:id="@+id/gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="@string/menu_gallery" />
<item
android:id="@+id/slide_show"
android:icon="@drawable/ic_menu_slideshow"
android:title="@string/menu_slideshow" />
<item
android:id="@+id/tools"
android:icon="@drawable/ic_menu_manage"
android:title="@string/menu_tools" />
</group>
</menu>
<!-- activity_main_graph.xml -->
<navigation 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:id="@+id/main_graph"
app:startDestination="@id/home">
<fragment
android:id="@+id/home"
android:name="com.example.HomeFragment"
android:label="Home"
tools:layout="@layout/home" />
<fragment
android:id="@+id/gallery"
android:name="com.example.GalleryFragment"
android:label="Gallery"
tools:layout="@layout/gallery" />
<fragment
android:id="@+id/slide_show"
android:name="com.example.SlideShowFragment"
android:label="Slide Show"
tools:layout="@layout/slide_show" />
<fragment
android:id="@+id/tools"
android:name="com.example.ToolsFragment"
android:label="Tools"
tools:layout="@layout/tools" />
</navigation>
หากคุณตรงกับค่า id
จากเมนูและกราฟ คุณก็สามารถเชื่อมโยง
NavController
สำหรับกิจกรรมนี้เพื่อจัดการการนำทางโดยอัตโนมัติตาม
รายการในเมนู NavController
ยังรองรับการเปิดและปิด
DrawerLayout
และจัดการการทำงานของปุ่มขึ้นและย้อนกลับอย่างเหมาะสม
จากนั้นคุณจะอัปเดต MainActivity
เพื่อโอน NavController
ไปยัง
Toolbar
และ NavigationView
ดูตัวอย่างต่อไปนี้
Kotlin
class MainActivity : AppCompatActivity() { val drawerLayout by lazy { findViewById<DrawerLayout>(R.id.drawer_layout) } val navController by lazy { (supportFragmentManager.findFragmentById(R.id.main_content) as NavHostFragment).navController } val navigationView by lazy { findViewById<NavigationView>(R.id.nav_view) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar = findViewById<Toolbar>(R.id.toolbar) setSupportActionBar(toolbar) // Show and Manage the Drawer and Back Icon setupActionBarWithNavController(navController, drawerLayout) // Handle Navigation item clicks // This works with no further action on your part if the menu and destination id’s match. navigationView.setupWithNavController(navController) } override fun onSupportNavigateUp(): Boolean { // Allows NavigationUI to support proper up navigation or the drawer layout // drawer menu, depending on the situation return navController.navigateUp(drawerLayout) } }
Java
public class MainActivity extends AppCompatActivity { private DrawerLayout drawerLayout; private NavController navController; private NavigationView navigationView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); drawerLayout = findViewById(R.id.drawer_layout); NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.main_content); navController = navHostFragment.getNavController(); navigationView = findViewById(R.id.nav_view); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); // Show and Manage the Drawer and Back Icon NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout); // Handle Navigation item clicks // This works with no further action on your part if the menu and destination id’s match. NavigationUI.setupWithNavController(navigationView, navController); } @Override public boolean onSupportNavigateUp() { // Allows NavigationUI to support proper up navigation or the drawer layout // drawer menu, depending on the situation. return NavigationUI.navigateUp(navController, drawerLayout); } }
คุณสามารถใช้เทคนิคเดียวกันนี้กับทั้งการนำทางตาม BottomnavigationView และการไปยังส่วนต่างๆ ตามเมนู โปรดดู อัปเดตคอมโพเนนต์ UI ด้วย NavigationUI เพื่อดูตัวอย่างเพิ่มเติม
เพิ่มจุดหมายของกิจกรรม
เมื่อเดินสายแต่ละหน้าจอในแอปเพื่อใช้คอมโพเนนต์การนำทางแล้ว และ
คุณไม่ได้ใช้ FragmentTransactions
เพื่อสลับระหว่าง
ปลายทางแบบ Fragment ขั้นตอนต่อไปคือการกำจัด startActivity
ก่อนอื่น ให้ระบุตำแหน่งในแอปที่คุณมีกราฟการนำทาง 2 แบบแยกกัน
และกำลังใช้ startActivity
เพื่อเปลี่ยนรหัส
ตัวอย่างนี้มีกราฟ 2 แบบ (A และ B) และการเรียก startActivity()
ไปยัง
เปลี่ยนจาก A เป็น B
Kotlin
fun navigateToProductDetails(productId: String) { val intent = Intent(this, ProductDetailsActivity::class.java) intent.putExtra(KEY_PRODUCT_ID, productId) startActivity(intent) }
Java
private void navigateToProductDetails(String productId) { Intent intent = new Intent(this, ProductDetailsActivity.class); intent.putExtra(KEY_PRODUCT_ID, productId); startActivity(intent);
จากนั้น แทนที่รายการเหล่านี้ด้วยปลายทางกิจกรรมในกราฟ A ที่แสดง การนำทางไปยังกิจกรรมโฮสต์ของกราฟ B หากคุณมีอาร์กิวเมนต์ที่จะส่งไปยัง ปลายทางเริ่มต้นของกราฟ B คุณกำหนดได้ในปลายทางกิจกรรม ของเรา
ในตัวอย่างต่อไปนี้ กราฟ A จะระบุปลายทางของกิจกรรมที่ต้องใช้
product_id
พร้อมกับการดำเนินการ กราฟ B ไม่มีการเปลี่ยนแปลง
การแสดง XML ของกราฟ A และ B อาจมีลักษณะดังนี้
<!-- Graph A -->
<navigation 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:id="@+id/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List"
tools:layout="@layout/product_list_fragment">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_details_activity" />
</fragment>
<activity
android:id="@+id/product_details_activity"
android:name="com.example.android.persistence.ui.ProductDetailsActivity"
android:label="Product Details"
tools:layout="@layout/product_details_host">
<argument
android:name="product_id"
app:argType="integer" />
</activity>
</navigation>
<!-- Graph B -->
<navigation 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"
app:startDestination="@id/product_details">
<fragment
android:id="@+id/product_details"
android:name="com.example.android.persistence.ui.ProductDetailsFragment"
android:label="Product Details"
tools:layout="@layout/product_details_fragment">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
คุณสามารถไปยังกิจกรรมโฮสต์ของกราฟ B ได้โดยใช้กลไกเดียวกับ ใช้เพื่อนำทางไปยังปลายทางของส่วนย่อย
Kotlin
fun navigateToProductDetails(productId: String) { val directions = ProductListDirections.navigateToProductDetail(productId) findNavController().navigate(directions) }
Java
private void navigateToProductDetails(String productId) { ProductListDirections.NavigateToProductDetail directions = ProductListDirections.navigateToProductDetail(productId); Navigation.findNavController(getView()).navigate(directions);
ส่งผ่านอาร์กิวเมนต์ปลายทางของกิจกรรมไปยังส่วนย่อยของปลายทางเริ่มต้น
หากกิจกรรมปลายทางได้รับส่วนเกิน เช่น ในตัวอย่างก่อนหน้านี้
สามารถส่งผ่านไปยังปลายทางเริ่มต้นโดยตรงเป็นอาร์กิวเมนต์ แต่คุณจะต้อง
ตั้งค่ากราฟการนำทางของโฮสต์ด้วยตนเองภายในแท็ก
onCreate()
เพื่อให้คุณสามารถส่ง Intent เพิ่มเติมเป็นอาร์กิวเมนต์ไปยัง
ดังแสดงด้านล่าง
Kotlin
class ProductDetailsActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.product_details_host) val navHostFragment = supportFragmentManager.findFragmentById(R.id.main_content) as NavHostFragment val navController = navHostFramgent.navController navController .setGraph(R.navigation.product_detail_graph, intent.extras) } }
Java
public class ProductDetailsActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.product_details_host); NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.main_content); NavController navController = navHostFragment.getNavController(); navController .setGraph(R.navigation.product_detail_graph, getIntent().getExtras()); } }
คุณสามารถดึงข้อมูลออกจากอาร์กิวเมนต์แฟรกเมนต์ Bundle
โดยใช้
คลาสอาร์กิวเมนต์ที่สร้างขึ้นดังที่ปรากฏในตัวอย่างต่อไปนี้
Kotlin
class ProductDetailsFragment : Fragment() { val args by navArgs<ProductDetailsArgs>() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val productId = args.productId ... } ...
Java
public class ProductDetailsFragment extends Fragment { ProductDetailsArgs args; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); args = ProductDetailsArgs.fromBundle(requireArguments()); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { int productId = args.getProductId(); ... } ...
รวมกิจกรรม
คุณสามารถรวมกราฟการนำทางในกรณีที่กิจกรรมหลายอย่างใช้
เลย์เอาต์เดียวกัน เช่น FrameLayout
แบบง่ายที่มีส่วนย่อยเดียว ใน
ส่วนใหญ่แล้ว คุณสามารถรวม
องค์ประกอบทั้งหมดจาก
กราฟการนำทางและอัปเดตองค์ประกอบปลายทางของกิจกรรมให้เป็นส่วนย่อย
ปลายทาง
ตัวอย่างต่อไปนี้รวมกราฟ A และ B จากส่วนก่อนหน้าเข้าด้วยกัน
ก่อนผสานรวม
<!-- Graph A -->
<navigation 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:id="@+id/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List Fragment"
tools:layout="@layout/product_list">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_details_activity" />
</fragment>
<activity
android:id="@+id/product_details_activity"
android:name="com.example.android.persistence.ui.ProductDetailsActivity"
android:label="Product Details Host"
tools:layout="@layout/product_details_host">
<argument android:name="product_id"
app:argType="integer" />
</activity>
</navigation>
<!-- Graph B -->
<navigation 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:id="@+id/product_detail_graph"
app:startDestination="@id/product_details">
<fragment
android:id="@+id/product_details"
android:name="com.example.android.persistence.ui.ProductDetailsFragment"
android:label="Product Details"
tools:layout="@layout/product_details">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
หลังจากผสานรวมแล้ว:
<!-- Combined Graph A and B -->
<navigation 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:id="@+id/product_list_graph"
app:startDestination="@id/product_list">
<fragment
android:id="@+id/product_list"
android:name="com.example.android.persistence.ui.ProductListFragment"
android:label="Product List Fragment"
tools:layout="@layout/product_list">
<action
android:id="@+id/navigate_to_product_detail"
app:destination="@id/product_details" />
</fragment>
<fragment
android:id="@+id/product_details"
android:name="com.example.android.persistence.ui.ProductDetailsFragment"
android:label="Product Details"
tools:layout="@layout/product_details">
<argument
android:name="product_id"
app:argType="integer" />
</fragment>
</navigation>
การตั้งชื่อการกระทำให้เหมือนเดิมขณะรวมก็ช่วยให้การดำเนินการนี้เป็นไปอย่างราบรื่น
โดยไม่ต้องเปลี่ยนแปลงฐานของโค้ดที่มีอยู่ ตัวอย่างเช่น
navigateToProductDetail
ยังคงเหมือนเดิมที่นี่ ความแตกต่างเพียงอย่างเดียวคือ
การดำเนินการนี้จะแสดงการนำทางไปยังปลายทางของส่วนย่อยภายใน
NavHost
แทนที่จะเป็นปลายทางของกิจกรรม:
Kotlin
fun navigateToProductDetails(productId: String) { val directions = ProductListDirections.navigateToProductDetail(productId) findNavController().navigate(directions) }
Java
private void navigateToProductDetails(String productId) { ProductListDirections.NavigateToProductDetail directions = ProductListDirections.navigateToProductDetail(productId); Navigation.findNavController(getView()).navigate(directions);
แหล่งข้อมูลเพิ่มเติม
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการนำทาง โปรดดูหัวข้อต่อไปนี้
- อัปเดตคอมโพเนนต์ UI ด้วย NavigationUI - ดูวิธีจัดการการนำทางด้วยแถบแอปด้านบน ลิ้นชักการนำทาง และการนำทางด้านล่าง
- การนำทางทดสอบ - ดูวิธีทดสอบเวิร์กโฟลว์การนำทางสำหรับแอป