Gezinme, kullanıcıların içerik hedeflerine erişmek için bir uygulamanın kullanıcı arayüzüyle etkileşimidir. Android'in gezinme ilkeleri, tutarlı ve sezgisel bir uygulama gezinme deneyimi oluşturmanıza yardımcı olacak yönergeler sağlar.
Duyarlı/uyarlanabilir kullanıcı arayüzleri, duyarlı içerik hedefleri sağlar ve genellikle ekran boyutu değişikliklerine yanıt olarak farklı türde gezinme öğeleri içerir (ör. küçük ekranlarda alt gezinme çubuğu, orta boy ekranlarda gezinme çubuğu veya büyük ekranlarda kalıcı gezinme çekmecesi). Ancak duyarlı/uyarlanabilir kullanıcı arayüzleri, gezinme ilkelerine uymaya devam etmelidir.
Jetpack Gezinme bileşeni, gezinme ilkelerini uygular ve duyarlı/uyarlanabilir kullanıcı arayüzlerine sahip uygulamaların geliştirilmesini kolaylaştırır.
Duyarlı kullanıcı arayüzü gezinme
Bir uygulamanın kapladığı ekran penceresinin boyutu, ergonomiyi ve kullanılabilirliği etkiler. Pencere boyutu sınıfları, uygun gezinme öğelerini (ör. gezinme çubukları, raylar veya çekmeceler) belirlemenizi ve bunları kullanıcının en kolay erişebileceği yere yerleştirmenizi sağlar. Materyal Tasarım düzenleme kurallarına göre gezinme öğeleri, ekranın ön kenarında kalıcı bir alan kaplar ve uygulamanın genişliği kompakt olduğunda alt kenara taşınabilir. Gezinme öğesi seçiminiz büyük ölçüde uygulama penceresinin boyutuna ve öğenin barındırması gereken öğe sayısına bağlıdır.
Pencere boyutu sınıfı | Az sayıda öğe | Çok sayıda öğe |
---|---|---|
kompakt genişlik | alt gezinme çubuğu | gezinme çekmecesi (ön kenar veya alt kısım) |
orta genişlik | gezinme çubuğu | gezinme çekmecesi (ön kenar) |
genişletilmiş genişlik | gezinme çubuğu | kalıcı gezinme çekmecesi (ön kenar) |
Düzen kaynak dosyaları, farklı görüntü boyutları için farklı gezinme öğeleri kullanmak üzere pencere boyutu sınıfı kesme noktalarına göre tanımlanabilir.
<!-- res/layout/main_activity.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
... />
<!-- Content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- res/layout-w600dp/main_activity.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.navigationrail.NavigationRailView
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
... />
<!-- Content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- res/layout-w1240dp/main_activity.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.navigation.NavigationView
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
... />
<!-- Content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>
Uyumlu içerik hedefleri
Duyarlı kullanıcı arayüzünde her içerik hedefine ait düzen, pencere boyutundaki değişikliklere uyum sağlar. Uygulamanız, düzen aralığını ayarlayabilir, öğeleri yeniden konumlandırabilir, içerik ekleyebilir veya kaldırabilir ya da gezinme öğeleri dahil olmak üzere kullanıcı arayüzü öğelerini değiştirebilir.
Her hedef, yeniden boyutlandırma etkinliklerini işlediğinde değişiklikler kullanıcı arayüzünde izole edilir. Navigasyon da dahil olmak üzere uygulama durumunun geri kalanı bu durumdan etkilenmez.
Gezinme, pencere boyutu değişikliklerinin bir yan etkisi olarak gerçekleşmemelidir. Yalnızca farklı pencere boyutlarına uyum sağlamak için içerik hedefleri oluşturmayın. Örneğin, katlanabilir bir cihazın farklı ekranları için farklı içerik hedefleri oluşturmayın.
Pencere boyutu değişikliklerinin bir yan etkisi olarak içerik hedeflerine gitmek aşağıdaki sorunlara neden olur:
- Yeni hedefe gitmeden önce eski hedef (önceki pencere boyutu için) kısa bir süre görünür olabilir
- Geri döndürülebilirliği korumak için (ör. bir cihaz katlandığında ve açıldığında) her pencere boyutu için gezinme gerekir.
- Gezinme, arka yığının açılması üzerine durumu bozabileceğinden, hedefler arasında uygulama durumunu korumak zor olabilir.
Ayrıca, pencere boyutu değiştiğinde uygulamanız ön planda bile olmayabilir. Uygulamanızın düzeni, ön plan uygulamasından daha fazla alan gerektirebilir. Kullanıcı uygulamanıza geri döndüğünde yön ve pencere boyutu değişmiş olabilir.
Uygulamanız, pencere boyutuna göre benzersiz içerik hedefleri gerektiriyorsa ilgili hedefleri alternatif, uyarlanabilir düzenler içeren tek bir hedefte birleştirebilirsiniz.
Alternatif düzenlere sahip içerik hedefleri
Duyarlı/uyarlanabilir tasarımın bir parçası olarak tek bir gezinme hedefi, uygulama penceresi boyutuna bağlı olarak alternatif düzenlere sahip olabilir. Her düzen pencerenin tamamını kaplar ancak farklı pencere boyutları için farklı düzenler sunulur (uyarlanabilir tasarım).
Liste-ayrıntı görünümü, bu tür bir görünüme örnek olarak verilebilir. Kompakt pencere boyutlarında uygulamanız, liste için bir içerik düzeni ve ayrıntılar için bir içerik düzeni gösterir. Liste ayrıntıları görünümüne gittiğinizde başlangıçta yalnızca liste düzeni gösterilir. Bir liste öğesi seçildiğinde uygulamanız, listenin yerini alarak ayrıntı düzenini gösterir. Geri kontrolü seçildiğinde ayrıntının yerine liste düzeni gösterilir. Ancak genişletilmiş pencere boyutlarında liste ve ayrıntı düzenleri yan yana gösterilir.
SlidingPaneLayout
, büyük ekranlarda iki içerik bölmesini yan yana, geleneksel telefonlar gibi küçük ekranlarda ise aynı anda yalnızca bir bölmeyi gösteren tek bir gezinme hedefi oluşturmanıza olanak tanır.
<!-- Single destination for list and detail. -->
<navigation ...>
<!-- Fragment that implements SlidingPaneLayout. -->
<fragment
android:id="@+id/article_two_pane"
android:name="com.example.app.ListDetailTwoPaneFragment" />
<!-- Other destinations... -->
</navigation>
SlidingPaneLayout
kullanarak liste-ayrıntı düzeni uygulamayla ilgili ayrıntılar için İki bölmeli düzen oluşturma başlıklı makaleyi inceleyin.
Bir gezinme grafiği
Herhangi bir cihazda veya pencere boyutunda tutarlı bir kullanıcı deneyimi sunmak için her içerik hedefine ait düzenin duyarlı olduğu tek bir gezinme grafiği kullanın.
Her pencere boyutu sınıfı için farklı bir gezinme grafiği kullanıyorsanız uygulama bir boyut sınıfından diğerine geçtiğinde kullanıcının diğer grafiklerdeki mevcut hedefini belirlemeniz, geri yığın oluşturmanız ve grafikler arasında farklı olan durum bilgilerini uyumlu hale getirmeniz gerekir.
İç içe yerleştirilmiş gezinme ana makinesi
Uygulamanız, kendi içerik hedeflerine sahip bir içerik hedefi içerebilir. Örneğin, liste ayrıntıları düzeninde öğe ayrıntıları bölmesi, öğe ayrıntısının yerini alan içeriğe giden kullanıcı arayüzü öğeleri içerebilir.
Bu tür bir alt gezinmeyi uygulamak için ayrıntı bölmesini, ayrıntı bölmesinden erişilen hedefleri belirten kendi gezinme grafiğine sahip iç içe yerleştirilmiş bir gezinme ana makinesi haline getirin:
<!-- layout/two_pane_fragment.xml -->
<androidx.slidingpanelayout.widget.SlidingPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sliding_pane_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_pane"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
<!-- Detail pane is a nested navigation host. Its graph is not connected
to the main graph that contains the two_pane_fragment destination. -->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/detail_pane"
android:layout_width="300dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/detail_pane_nav_graph" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
İç içe yerleştirilmiş NavHost
öğesinin gezinme grafiği ana gezinme grafiğine bağlı olmadığı için bu, iç içe yerleştirilmiş gezinme grafiğinden farklıdır. Yani bir grafikteki hedeflerden doğrudan diğer grafikteki hedeflere gidemezsiniz.
Daha fazla bilgi için İç içe yerleştirilmiş gezinme grafikleri başlıklı makaleyi inceleyin.
Korunmuş durum
Uygulamanızın, cihaz döndürüldüğünde, katlandığında veya uygulama penceresi yeniden boyutlandırıldığında durumunu koruması gerekir. Varsayılan olarak bu tür yapılandırma değişiklikleri, uygulamanın etkinliklerini, parçalarını ve görüntüleme hiyerarşisini yeniden oluşturur. Kullanıcı arayüzü durumunu kaydetmenin önerilen yolu, yapılandırma değişikliklerinde korunan bir ViewModel
kullanmaktır. (Kullanıcı arayüzü durumlarını kaydetme başlıklı makaleyi inceleyin.)
Boyut değişiklikleri geri alınabilir olmalıdır. Örneğin, kullanıcı cihazı döndürüp tekrar döndürdüğünde.
Duyarlı/uyarlanabilir düzenler farklı pencere boyutlarında farklı içerikler gösterebilir. Bu nedenle, duyarlı düzenler genellikle mevcut pencere boyutu için geçerli olmasa bile içerikle ilgili ek durum bilgisi kaydetmelidir. Örneğin, bir düzende yalnızca daha geniş pencere genişliklerinde ek bir kaydırılabilir widget gösterilecek alan olabilir. Bir yeniden boyutlandırma etkinliği, pencere genişliğinin çok küçük olmasına neden olursa widget gizlenir. Uygulama önceki boyutlarına yeniden ayarlandığında kaydırma widget'ı tekrar görünür hale gelir ve orijinal kaydırma konumu geri yüklenir.
ViewModel kapsamları
Gezinme bileşenine taşıma geliştirici kılavuzunda, hedeflerin parça olarak uygulandığı ve veri modellerinin ViewModel
kullanılarak uygulandığı tek etkinlikli bir mimari önerilmektedir.
ViewModel
her zaman bir yaşam döngüsü kapsamına alınır ve bu yaşam döngüsü kalıcı olarak sona erdiğinde ViewModel
temizlenir ve atılabilir. ViewModel
'ün kapsamına dahil edildiği yaşam döngüsü (ve dolayısıyla ViewModel
'ün ne kadar geniş kapsamlı olarak paylaşılabileceği) ViewModel
'ü almak için kullanılan mülk temsilcisine bağlıdır.
En basit durumda, her gezinme hedefi tamamen izole bir kullanıcı arayüzü durumuna sahip tek bir parçadır. Bu nedenle, her parça, ilgili parçaya özel bir ViewModel
elde etmek için viewModels()
mülk temsilcisini kullanabilir.
Kullanıcı arayüzü durumunu parçalar arasında paylaşmak için parçalarda activityViewModels()
'i çağırarak ViewModel
'ü etkinliğe göre kapsamlandırın (Activity
için eşdeğeri yalnızca viewModels()
'tir). Bu, etkinliğin ve kendisine eklenen tüm parçaların ViewModel
örneğini paylaşmasına olanak tanır.
Ancak tek etkinlikli bir mimaride bu ViewModel
kapsamı, uygulama kadar etkili bir şekilde sürer. Bu nedenle, hiçbir parça kullanmasa bile ViewModel
bellekte kalır.
Gezinme grafiğinizin, ödeme akışını temsil eden bir dizi parça hedefi olduğunu ve ödeme deneyiminin tamamının mevcut durumunun, parçalar arasında paylaşılan bir ViewModel
içinde olduğunu varsayalım. ViewModel
etkinliğine yönelik kapsamın çok geniş olması yalnızca çok geniş olmakla kalmaz, aynı zamanda başka bir sorunu da ortaya çıkarır: Kullanıcı bir sipariş için ödeme akışında ilerler ve ardından ikinci bir sipariş için bu akışı tekrar kullanırsa her iki sipariş de ödeme ViewModel
etkinliğinin aynı örneğini kullanır. İkinci siparişin ödemesini yapmadan önce ilk siparişteki verileri manuel olarak temizlemeniz gerekir. Hatalar kullanıcı için maliyetli olabilir.
Bunun yerine, ViewModel
'ü mevcut NavController
içindeki bir gezinme grafiğiyle sınırlandırın. Ödeme akışının bir parçası olan hedefleri kapsayacak şekilde iç içe yerleştirilmiş bir gezinme grafiği oluşturun. Ardından, bu parça hedeflerin her birinde navGraphViewModels()
mülk temsilcisini kullanın ve paylaşılan ViewModel
'ı almak için gezinme grafiğinin kimliğini iletin. Bu sayede, kullanıcı ödeme akışından çıktığında ve iç içe yerleştirilmiş gezinme grafiği kapsam dışında kaldığında, ViewModel
öğesinin ilgili örneği atılır ve sonraki ödeme için kullanılmaz.
Kapsam | Mülk temsilcisi | ViewModel şu kullanıcılarla paylaşılabilir: |
---|---|---|
Parça | Fragment.viewModels() |
Yalnızca parça |
Etkinlik | Activity.viewModels() veya Fragment.activityViewModels() |
Etkinlik ve ona bağlı tüm parçalar |
Gezinme grafiği | Fragment.navGraphViewModels() |
Aynı gezinme grafiğindeki tüm parçalar |
İç içe yerleştirilmiş bir gezinme ana makinesi kullanıyorsanız (İç içe yerleştirilmiş gezinme ana makinesi bölümüne bakın) grafikler bağlı olmadığından, bu ana makinedeki hedeflerin navGraphViewModels()
kullanılırken ViewModel
örneklerini ana makinenin dışındaki hedeflerle paylaşamayacağını unutmayın. Bu durumda bunun yerine etkinlik kapsamını kullanabilirsiniz.