Gezinme bileşeni; karmaşık gezinmeyi, geçiş animasyonunu, derin bağlantıları ve uygulamanızdaki ekranlar arasında geçiş yapan, derleme zamanı kontrol edilmiş bağımsız değişkeni yönetebilen bir kitaplıktır.
Bu doküman, mevcut bir uygulamayı Gezinme bileşenini kullanacak şekilde taşımak için genel amaçlı bir kılavuz işlevi görür.
Genel olarak taşıma işlemi aşağıdaki adımları içerir:
Ekrana özgü kullanıcı arayüzü mantığını etkinliklerin dışına taşıyın - Uygulamanızın kullanıcı arayüzü mantığını etkinliklerin dışına taşıyın. Her etkinliğin yalnızca
Toolbar
gibi genel gezinme arayüzü bileşenlerinin mantığına sahip olmasını sağlayın ve her bir ekranın uygulanması için yetkiyi bir parçaya veya özel hedefe verin.Gezinme bileşenini entegre etme - Her etkinlik için, söz konusu etkinlik tarafından yönetilen bir veya daha fazla parçayı içeren bir gezinme grafiği oluşturun. Parça işlemlerini Gezinme bileşeni işlemleriyle değiştirin.
Etkinlik hedefleri ekleme - Etkinlik hedeflerini kullanarak
startActivity()
çağrılarını işlemlerle değiştirin.Aktiviteleri birleştirme: Birden fazla etkinliğin ortak bir düzeni paylaştığı durumlarda gezinme grafiklerini birleştirin.
Ön koşullar
Bu kılavuzda, AndroidX kitaplıklarını kullanmak için uygulamanızı önceden taşıdığınız varsayılmaktadır. Henüz yapmadıysanız devam etmeden önce AndroidX'i kullanmak için projenizi taşıyın.
Ekrana özgü kullanıcı arayüzü mantığını etkinliklerin dışına taşı
Etkinlikler, uygulamanız ile Android arasında grafiksel etkileşimi kolaylaştıran sistem düzeyindeki bileşenlerdir. Etkinlikler, uygulamanızın manifest dosyasına kaydedilir. Böylece Android, hangi etkinliklerin başlatılabileceğini bilir. Etkinlik sınıfı, uygulamanızın kullanıcı arayüzünün ön plana girmesi veya ön plandan ayrılması, döndürme gibi Android değişikliklerine de tepki vermesini sağlar. Etkinlik, ekranlar arasında durum paylaşımı için de bir yer işlevi görebilir.
Uygulamanız bağlamında etkinlikler, gezinme için bir ana makine görevi görmeli ve ekranlar arasında geçiş yapma, verileri iletme vb. mantığı ve bilgiyi içermelidir. Ancak, kullanıcı arayüzünüzün ayrıntılarını yönetmek için kullanıcı arayüzünüzün daha küçük ve yeniden kullanılabilir bir bölümü olması daha iyidir. Bu kalıp için önerilen uygulama parçalar şeklindedir. Parça kullanmanın avantajları hakkında daha fazla bilgi edinmek için Tek Etkinlik: Neden, Ne Zaman ve Nasıl bölümüne bakın. Gezinme, navigation-parça bağımlılığı aracılığıyla parçaları destekler. Navigasyon, özel hedef türlerini de destekler.
Uygulamanız parçalar kullanmıyorsa yapmanız gereken ilk şey, uygulamanızdaki her ekranı bir parça kullanacak şekilde taşımaktır. Bu noktada etkinliği kaldırmazsınız. Bunun yerine, ekranı temsil eden ve kullanıcı arayüzü mantığınızı sorumluluğa göre ayıran bir parça oluşturursunuz.
Parçalarla tanışın
Parçaları kullanıma sunma sürecini göstermek için, iki ekrandan oluşan bir uygulama örneğinle başlayalım: ürün listesi ekranı ve ürün ayrıntıları ekranı. Liste ekranında bir ürünü tıklayan kullanıcılar, ürün hakkında daha fazla bilgi edinebilecekleri bir ayrıntılar ekranına yönlendirilir.
Bu örnekte, liste ve ayrıntılar ekranları şu anda ayrı etkinliklerdir.
Kullanıcı Arayüzünü Barındırmak için Yeni Bir Düzen Oluşturma
Bir parçayı yerleştirmek için işlemin parçayı barındırması amacıyla yeni bir düzen dosyası oluşturarak başlayın. Bu işlem, etkinliğin mevcut içerik görünümü düzeninin yerini alır.
Basit bir görünüm için aşağıdaki product_list_host
örnekte gösterildiği gibi bir FrameLayout
kullanabilirsiniz:
<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
özelliği, daha sonra parçayı eklediğimiz içerik bölümünü ifade eder.
Ardından, etkinliğinizin onCreate()
işlevinde, etkinliğinizin onCreate işlevindeki düzen dosyası referansını bu yeni düzen dosyasına işaret edecek şekilde değiştirin:
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); ... } }
Mevcut düzen (bu örnekte product_list
), oluşturmak üzere olduğunuz parça için kök görünüm olarak kullanılır.
Parça oluşturma
Ekranınızın kullanıcı arayüzünü yönetmek için yeni bir parça oluşturun. Etkinlik ana makine adınızla tutarlı
olmanız iyi bir uygulamadır. Aşağıdaki snippet'te ProductListFragment
kullanılmıştır. Örneğin:
Kotlin
class ProductListFragment : Fragment() { // Leave empty for now. }
Java
public class ProductListFragment extends Fragment { // Leave empty for now. }
Etkinlik mantığını bir parçaya taşıma
Parça tanımı uygulandıktan sonraki adım, bu ekranla ilgili kullanıcı arayüzü mantığını etkinlikten bu yeni parçaya taşımaktır. Etkinliğe dayalı bir mimariden geliyorsanız etkinliğinizin onCreate()
işlevinde büyük olasılıkla çok sayıda görüntüleme oluşturma mantığınız vardır.
Taşımamız gereken kullanıcı arayüzü mantığına sahip etkinliğe dayalı bir ekran örneği aşağıda verilmiştir:
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 }
Etkinliğiniz, aşağıdaki örnekte gösterildiği gibi, kullanıcının sonraki ekrana ne zaman ve nasıl geçeceğini de kontrol ediyor olabilir:
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); }
Parçanızın içinde, bu çalışmayı onCreateView()
ile onViewCreated()
arasında dağıtırsınız, ancak etkinlikte yalnızca gezinme mantığı kalır:
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
ürününde, düzeni genişletmek ve bağlamak için setContentView()
çağrısı yapılmadığına dikkat edin. Bir parçada onCreateView()
, kök görünümü başlatır. onCreateView()
, düzen kaynak dosyasına göre kök görünümü genişletmek için kullanılabilecek bir LayoutInflater
örneğini alır. Bu örnekte, düzenin kendisinde değişiklik yapılması gerekmediği için etkinlik tarafından kullanılan mevcut product_list
düzeni yeniden kullanılır.
Etkinliğinizin onStart()
, onResume()
, onPause()
veya onStop()
işlevlerinde gezinmeyle ilgili olmayan kullanıcı arayüzü mantığınız varsa bunları parça üzerinde aynı ada sahip karşılık gelen işlevlere taşıyabilirsiniz.
Ana makine etkinliğinde parçayı başlatın
Tüm kullanıcı arayüzü mantığını parçaya taşıdıktan sonra, etkinlikte yalnızca gezinme mantığı kalır.
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); } }
Son adım, içerik görünümünü ayarladıktan hemen sonra onCreate()
içinde parçanın bir örneğini oluşturmaktır:
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(); } }
Bu örnekte gösterildiği gibi FragmentManager
, yapılandırma değişikliklerinin üzerine parçaları otomatik olarak kaydeder ve geri yükler. Bu nedenle, yalnızca savedInstanceState
null ise parçayı eklemeniz gerekir.
Amaç ekstralarını parçaya iletme
Etkinliğiniz bir amaç aracılığıyla Extras
alıyorsa bunları doğrudan bağımsız değişkenler olarak parçaya aktarabilirsiniz.
Bu örnekte, ProductDetailsFragment
bağımsız değişkenlerini doğrudan etkinliğin intent ekstralarından alır:
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(); } ...
Bu noktada, ilk ekranı bir parça kullanacak şekilde güncellenmiş olarak uygulamanızı çalıştırmayı test edebilmeniz gerekir. Etkinliğe dayalı ekranlarınızın geri kalanını taşımaya devam edin ve her iterasyondan sonra test yapın.
Gezinme bileşenini entegre etme
Parça tabanlı bir mimari kullanmaya başladığınızda Gezinme bileşenini entegre etmeye hazırsınız demektir.
Öncelikle, Gezinme kitaplığı sürüm notlarındaki talimatları uygulayarak projenize en yeni Gezinme bağımlılıklarını ekleyin.
Gezinme grafiği oluşturma
Gezinme bileşeni, uygulamanızın görünümlerinin temsil edilmesi gibi, uygulamanızın kaynak dosyasındaki gezinme yapılandırmasını grafik olarak temsil eder. Bu, uygulamanızın gezinme yapısını kod tabanınızın dışında düzenli tutmaya yardımcı olur ve uygulamanızda gezinmeyi görsel olarak düzenlemenizi sağlar.
Gezinme grafiği oluşturmak için navigation
adında yeni bir kaynak klasörü oluşturarak başlayın. Grafiği eklemek için bu dizini sağ tıklayın ve Yeni > Gezinme kaynak dosyası'nı seçin.
Gezinme bileşeni, gezinme için ana makine olarak bir etkinlik kullanır ve kullanıcılarınız uygulamanızda gezinirken bağımsız parçaları bu ana makineyle değiştirir. Uygulamanızın gezinme menüsünü görsel olarak düzenlemeye başlamadan önce, etkinliğin içinde bu grafiği barındıracak bir NavHost
yapılandırmanız gerekir. Parçalar kullandığımız için Gezinme bileşeninin varsayılan NavHost
uygulaması olan NavHostFragment
'ı kullanabiliriz.
NavHostFragment
, aşağıdaki örnekte gösterildiği gibi bir ana makine etkinliğinin içine yerleştirilen bir FragmentContainerView
aracılığıyla yapılandırılır:
<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
özelliği, bu gezinme ana makinesiyle ilişkilendirilmiş gezinme grafiğine işaret eder. Bu özelliğin ayarlanması gezinme grafiğini genişletir ve NavHostFragment
üzerindeki grafik özelliğini ayarlar. app:defaultNavHost
özelliği, NavHostFragment
öğenizin sistemdeki Geri düğmesine müdahale etmesini sağlar.
DrawerLayout
veya BottomNavigationView
gibi üst düzey gezinme kullanıyorsanız bu FragmentContainerView
ana içerik görüntüleme öğenizin yerini alır. Örnekler için NavigationUI ile kullanıcı arayüzü bileşenlerini güncelleme bölümüne bakın.
Basit bir düzen için bu FragmentContainerView
öğesini, kök ViewGroup
öğesinin alt öğesi olarak ekleyebilirsiniz:
<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>
Alttaki Tasarım sekmesini tıklarsanız aşağıda gösterilene benzer bir grafik görürsünüz. Grafiğin sol üst kısmındaki Hedefler bölümünün altında, NavHost
etkinliğine layout_name (resource_id)
biçiminde bir referans görebilirsiniz.
Parçalarınızı bu grafiğe eklemek için üst kısımdaki artı düğmesini tıklayın.
Gezinme bileşeni, bağımsız ekranları hedefler olarak ifade eder. Hedefler parçalar, etkinlikler veya özel hedefler olabilir. Grafiğinize herhangi bir türde hedef ekleyebilirsiniz ancak bir etkinlik hedefine gittiğinizde ayrı bir gezinme ana makinesi ve grafiği içinde çalıştığınız için etkinlik hedeflerinin terminal hedefler olarak kabul edildiğini unutmayın.
Gezinme bileşeni, kullanıcıların bir varış noktasından diğerine eylemler olarak ulaşma yöntemidir. İşlemler de geçiş animasyonlarını ve pop davranışını açıklayabilir.
Parça kaldırma işlemleri
Artık Gezinme bileşenini kullandığınıza göre, aynı etkinlik altındaki parçaya dayalı ekranlar arasında geziniyorsanız FragmentManager
etkileşimlerini kaldırabilirsiniz.
Uygulamanız aynı etkinlik veya çekmece düzeni ya da alt gezinme gibi üst düzey gezinme altında birden fazla parça kullanıyorsa kullanıcı arayüzünüzün ana içerik bölümündeki parçaları eklemek veya değiştirmek için muhtemelen FragmentManager
ve FragmentTransactions
kullanıyorsunuzdur. Grafiğinizdeki hedefleri bağlamak için işlemler sağlayıp NavController
kullanarak gezinme olanağı sağlayarak bu artık Gezinme bileşeni ile değiştirilebilir ve basitleştirilebilir.
Karşılaşabileceğiniz birkaç senaryoyu ve her senaryo için taşıma yaklaşımını nasıl uygulayabileceğinizi burada bulabilirsiniz.
Birden fazla parçayı yöneten tek bir etkinlik
Birden çok parçayı yöneten tek bir etkinliğiniz varsa etkinlik kodunuz aşağıdaki gibi görünebilir:
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(); } }
Aşağıda gösterildiği gibi, kaynak hedefin içinde bir etkinliğe yanıt olarak bir gezinme işlevi çağırıyor olabilirsiniz:
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()) ); }
Bunun yerine, başlangıç hedefini ve hedeflerinizi bağlamak üzere işlemleri belirlemek ve gerektiğinde bağımsız değişkenler tanımlamak için gezinme grafiğinizi güncelleyebilirsiniz:
<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>
Ardından, etkinliğinizi güncelleyebilirsiniz:
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); } }
Etkinlik için artık bir navigateToProductDetail()
yöntemi gerekmiyor. Bir sonraki bölümde, bir sonraki ürün ayrıntıları ekranına gitmek için NavController
değerini kullanacak şekilde ProductListFragment
uygulamasını güncelliyoruz.
Bağımsız değişkenleri güvenli bir şekilde iletme
Gezinme bileşeni, hedefler ve işlemler için belirtilen bağımsız değişkenlere tür güvenli erişim için basit nesne ve oluşturucu sınıfları oluşturan Safe Args adlı bir Gradle eklentisine sahiptir.
Eklenti uygulandıktan sonra, gezinme grafiğinizdeki bir hedefte tanımlanan bağımsız değişkenler, Gezinme bileşeni çerçevesinin hedef hedefe tür güvenli bağımsız değişkenler sağlayan bir Arguments
sınıfı oluşturmasına neden olur.
Bir işlem tanımlanması, eklentinin bir Directions
yapılandırma sınıfı oluşturmasına neden olur. Bu sınıf, NavController
öğesine kullanıcıyı hedef hedefe nasıl yönlendireceğini bildirmek için kullanılabilir. Bir işlem, bağımsız değişken gerektiren bir hedefe işaret ettiğinde oluşturulan Directions
sınıfı, bu parametreleri gerektiren oluşturucu yöntemleri içerir.
Aşağıdaki örnekte gösterildiği gibi, parçanın içinde NavController
ve oluşturulan Directions
sınıfını kullanarak hedef hedefe tür güvenli bağımsız değişkenler sağlayın:
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); }; }
Üst Düzey Gezinme
Uygulamanız DrawerLayout
kullanıyorsa etkinliğinizde çekmeceyi açıp kapatmayı ve diğer hedeflere gitmeyi yöneten birçok yapılandırma mantığınız olabilir.
Sonuçta elde edilen etkinlik aşağıdaki gibi görünebilir:
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); } }
Projenize Gezinme bileşenini ekledikten ve bir gezinme grafiği oluşturduktan sonra, grafiğinizdeki içerik hedeflerinin her birini (yukarıdaki örnekte bulunan Ana Sayfa, Galeri, Slayt Gösterisi ve Araçlar gibi) ekleyin. Menü öğesi id
değerlerinizin, aşağıda gösterildiği gibi ilişkili hedef id
değerleriyle eşleştiğinden emin olun:
<!-- 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>
Menünüzdeki ve grafiğinizdeki id
değerlerini eşleştirirseniz bu etkinlik için, gezinmeyi menü öğesine göre otomatik olarak işlemek için NavController
parametresini bağlayabilirsiniz. NavController
ayrıca DrawerLayout
öğesinin açılıp kapatılmasını, Yukarı ve Geri düğmesinin davranışını uygun şekilde ele alır.
Ardından MainActivity
cihazınız, NavController
cihazını Toolbar
ve NavigationView
'e bağlamak için güncellenebilir.
Örnek için aşağıdaki snippet'i inceleyin:
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); } }
Bu tekniği hem Bottom NavigationView tabanlı gezinme hem de Menü tabanlı gezinme için kullanabilirsiniz. Daha fazla örnek için NavigationUI ile kullanıcı arayüzü bileşenlerini güncelleme bölümüne bakın.
Aktivite hedefleri ekleyin
Uygulamanızdaki her ekran Gezinme bileşenini kullanacak şekilde bağlandıktan ve parça tabanlı hedefler arasında geçiş için artık FragmentTransactions
uygulamasını kullanmadığınızda, bir sonraki adım startActivity
çağrılarını ortadan kaldırmaktır.
Öncelikle, uygulamanızda iki ayrı gezinme grafiğinizin olduğu ve bunlar arasında geçiş yapmak için startActivity
kullandığınız yerleri belirleyin.
Bu örnekte, iki grafik (A ve B) ve A'dan B'ye geçiş için bir startActivity()
çağrısı bulunmaktadır.
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);
Daha sonra, bunları Grafik A'da Grafik B'nin ana makine etkinliğine gitmeyi temsil eden bir etkinlik hedefiyle değiştirin. Grafik B'nin başlangıç hedefine aktarılacak bağımsız değişkenleriniz varsa bunları etkinlik hedefi tanımında belirtebilirsiniz.
Aşağıdaki örnekte Grafik A, işlemle birlikte product_id
bağımsız değişkenini alan bir etkinlik hedefi tanımlar. B grafiği değişiklik içermiyor.
A ve B Grafiklerinin XML gösterimi aşağıdaki gibi görünebilir:
<!-- 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>
Parça hedeflerine gitmek için kullandığınız mekanizmaları kullanarak Grafik B'nin ana makine etkinliğine gidebilirsiniz:
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);
Etkinlik hedefi bağımsız değişkenlerini bir başlangıç hedef parçasına geçirme
Önceki örnekte olduğu gibi hedef etkinliği ekstralar alırsa bunları doğrudan başlangıç hedefine bağımsız değişken olarak aktarabilirsiniz, ancak ana makine etkinliğinin onCreate()
yöntemi içinde ana makinenizin gezinme grafiğini manuel olarak ayarlamanız gerekir. Böylece, niyet ekstralarını parçaya aşağıda gösterildiği gibi bağımsız değişkenler olarak aktarabilirsiniz:
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()); } }
Veriler, aşağıdaki örnekte gösterildiği gibi, oluşturulan bağımsız değişken sınıfı kullanılarak Bundle
parça bağımsız değişkenlerinden alınabilir:
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(); ... } ...
Etkinlikleri birleştir
Birden fazla etkinliğin aynı düzeni paylaştığı durumlarda (ör. tek bir parça içeren basit bir FrameLayout
öğesi) gezinme grafiklerini birleştirebilirsiniz. Bu durumların çoğunda, her bir gezinme grafiğindeki tüm öğeleri birleştirebilir ve etkinlik hedefi öğelerini parçalı hedeflere güncelleyebilirsiniz.
Aşağıdaki örnekte, önceki bölümde bulunan A ve B Grafikleri birleştirilmektedir:
Birleştirmeden önce:
<!-- 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>
Birleştirdikten sonra:
<!-- 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>
Birleştirme sırasında işlem adlarınızı aynı tutmak, mevcut kod tabanınızda değişiklik gerektirmeden sorunsuz bir işlem yapılmasını sağlayabilir. Örneğin, navigateToProductDetail
burada değişmeden kalır. Tek fark, bu işlemin artık bir etkinlik hedefi yerine aynı NavHost
içindeki parça hedefe gitmeyi temsil etmesidir:
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);
Ek Kaynaklar
Gezinmeyle ilgili daha fazla bilgi için aşağıdaki konulara bakın:
- NavigasyonUI ile kullanıcı arayüzü bileşenlerini güncelleme - Üst uygulama çubuğu, gezinme çekmecesi ve alt gezinmeyle gezinmeyi nasıl yöneteceğinizi öğrenin
- Gezinmeyi Test Et - Uygulamanız için gezinme iş akışlarını nasıl test edeceğinizi öğrenin