Uygulamanızdaki her ekran duyarlı olmalı ve mevcut alana uyum sağlamalıdır.
Duyarlı kullanıcı arayüzüyle
Tek bölmeyi sağlayan ConstraintLayout
pek çok boyuta yaklaşabilir, ancak daha büyük cihazlarda
parçalara bölünebilir.
bölmeyi bölmenize yardımcı olur. Örneğin, ekranda karşınıza bir
öğe listesi.
İlgili içeriği oluşturmak için kullanılan
SlidingPaneLayout
bileşeni, daha büyük cihazlarda iki bölmenin yan yana gösterilmesini destekler ve
aynı anda yalnızca bir bölmeyi gösterecek şekilde otomatik olarak uyarlanırken
daha küçük cihazlarla uyumlu
bir şekilde çalışır.
Cihaza özgü yardım için bkz. ekran uyumluluğuna genel bakış başlıklı makaleyi inceleyin.
Kurulum
SlidingPaneLayout
kullanmak için uygulamanızın
build.gradle
dosyası:
Eski
dependencies { implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0" }
Kotlin
dependencies { implementation("androidx.slidingpanelayout:slidingpanelayout:1.2.0") }
XML düzeni yapılandırması
SlidingPaneLayout
, üstte kullanılmak üzere yatay, iki bölmeli bir düzen sağlar.
bir kullanıcı arayüzü seviyesidir. Bu düzen, ilk bölmeyi içerik listesi veya tarayıcı olarak kullanır.
birincil ayrıntı görünümüne tabidir.
![SlidingPaneLayout örneği gösteren bir resim](https://developer.android.google.cn/static/images/ui/slidingpanelayout-example.png?authuser=8&hl=tr)
SlidingPaneLayout
SlidingPaneLayout
, gösterilip gösterilmeyeceğini belirlemek için iki bölmenin genişliğini kullanır
yan yana görebilirsiniz. Örneğin, liste bölmesinde bir
200 dp boyutunda ve ayrıntı bölmesi için 400 dp gerekir; daha sonra
SlidingPaneLayout
, gösterildiği sürece iki bölmeyi otomatik olarak yan yana gösterir
en az 600 dp genişliğe sahip.
Birleştirilmiş genişlikleri
SlidingPaneLayout
Bu durumda, alt görüntülemeler mevcut
SlidingPaneLayout
genişliğindedir. Kullanıcı, ekranın en üstündeki görünümü
kenarlarından geriye doğru sürükleyerek de şekli oluşturabilirsiniz.
Görünümler çakışmıyorsa SlidingPaneLayout
, düzenin kullanımını destekler
Kalan alanın nasıl bölüneceğini tanımlamak için alt görüntülemelerde layout_weight
parametresi
tamamlanmasından kısa bir süre sonra sunulur. Bu parametre yalnızca genişlikle ilgilidir.
Ekranında her iki görünümü yan yana gösterecek alan bulunan katlanabilir cihazlarda ise
SlidingPaneLayout
iki bölmenin boyutunu otomatik olarak ayarlar.
üst üste binen kat veya menteşenin her iki tarafına yerleştirilmiş olmalıdır. Burada
Bu durumda, ayarlanan genişlikler, her bir yüzeyin her birinde olması gereken minimum genişlik olarak
tarafından yapılır. Bunu sağlamak için yeterli alan yoksa
bir boyut seçerseniz SlidingPaneLayout
, tekrar çakışan görünümlere geçer.
Örnek: SlidingPaneLayout
Bunun nedeni: RecyclerView
ve bir
FragmentContainerView
birincil ayrıntı görünümü olarak görüntüleyin:
<!-- two_pane.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">
<!-- The first child view becomes the left pane. When the combined needed
width, expressed using android:layout_width, doesn't fit on-screen at
once, the right pane is permitted to overlap the left. -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_pane"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
<!-- The second child becomes the right (content) pane. In this example,
android:layout_weight is used to expand this detail pane to consume
leftover available space when the entire window is wide enough to fit
the left and right pane.-->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/detail_container"
android:layout_width="300dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:background="#ff333333"
android:name="com.example.SelectAnItemFragment" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
Bu örnekte, FragmentContainerView
üzerindeki android:name
özelliği
ilk parçayı ayrıntı penceresine ekleyerek,
cihazlar, uygulama ilk kez başlatıldığında boş bir bölme görmüyor.
Ayrıntı bölmesini programatik olarak değiştirme
Yukarıdaki XML örneğinde, RecyclerView
sayfasındaki bir öğeye dokunulduğunda
ayrıntı bölmesinde bir değişikliği tetikler. Parça kullanırken bunun için
FragmentTransaction
öğesini çağırarak
open()
yeni görünür parçaya geçmek için SlidingPaneLayout
üzerinde:
Kotlin
// A method on the Fragment that owns the SlidingPaneLayout,called by the // adapter when an item is selected. fun openDetails(itemId: Int) { childFragmentManager.commit { setReorderingAllowed(true) replace<ItemFragment>(R.id.detail_container, bundleOf("itemId" to itemId)) // If it's already open and the detail pane is visible, crossfade // between the fragments. if (binding.slidingPaneLayout.isOpen) { setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) } } binding.slidingPaneLayout.open() }
Java
// A method on the Fragment that owns the SlidingPaneLayout, called by the // adapter when an item is selected. void openDetails(int itemId) { Bundle arguments = new Bundle(); arguments.putInt("itemId", itemId); FragmentTransaction ft = getChildFragmentManager().beginTransaction() .setReorderingAllowed(true) .replace(R.id.detail_container, ItemFragment.class, arguments); // If it's already open and the detail pane is visible, crossfade // between the fragments. if (binding.getSlidingPaneLayout().isOpen()) { ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); } ft.commit(); binding.getSlidingPaneLayout().open(); }
Bu kod özellikle
addToBackStack()
FragmentTransaction
üzerinde. Bu, ayrıntılarda arka yığın oluşturmaktan kaçınır
bölmesini de kullanabilirsiniz.
Gezinme bileşeni uygulaması
Bu sayfadaki örneklerde doğrudan SlidingPaneLayout
kullanılmıştır ve
parça işlemlerini manuel olarak yönetmenizi sağlar. Ancak
Gezinme bileşeni, varsayılan olarak
iki bölmeli düzende
AbstractListDetailFragment
,
Listenizi yönetmek için arka planda SlidingPaneLayout
kullanan bir API sınıfı
ve ayrıntı bölmelerini genişletin.
Bu, XML düzeni yapılandırmanızı basitleştirmenize olanak tanır. Açıkça belirtmek yerine
bir SlidingPaneLayout
ve her iki bölmenizi de bildirdiğinizde, düzeniniz için yalnızca bir
AbstractListDetailFragment
cihazınızı tutmak için FragmentContainerView
uygulama:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/two_pane_container"
<!-- The name of your AbstractListDetailFragment implementation.-->
android:name="com.example.testapp.TwoPaneFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
<!-- The navigation graph for your detail pane.-->
app:navGraph="@navigation/two_pane_navigation" />
</FrameLayout>
Uygulama
onCreateListPaneView()
ve
onListPaneViewCreated()
kullanarak liste bölmeniz için özel bir görünüm oluşturabilirsiniz. Ayrıntı bölmesi için
AbstractListDetailFragment
, bir
NavHostFragment
Bu, bir navigasyon yönergesi tanımlayabileceğiniz
grafik
hedeflerin sayısını veya listesini görüntüler. Daha sonra,
NavController
ayrıntı bölmesini kullanarak, bağımsız gezinme grafiğindeki hedeflerin arasında
Kotlin
fun openDetails(itemId: Int) { val navController = navHostFragment.navController navController.navigate( // Assume the itemId is the android:id of a destination in the graph. itemId, null, NavOptions.Builder() // Pop all destinations off the back stack. .setPopUpTo(navController.graph.startDestination, true) .apply { // If it's already open and the detail pane is visible, // crossfade between the destinations. if (binding.slidingPaneLayout.isOpen) { setEnterAnim(R.animator.nav_default_enter_anim) setExitAnim(R.animator.nav_default_exit_anim) } } .build() ) binding.slidingPaneLayout.open() }
Java
void openDetails(int itemId) { NavController navController = navHostFragment.getNavController(); NavOptions.Builder builder = new NavOptions.Builder() // Pop all destinations off the back stack. .setPopUpTo(navController.getGraph().getStartDestination(), true); // If it's already open and the detail pane is visible, crossfade between // the destinations. if (binding.getSlidingPaneLayout().isOpen()) { builder.setEnterAnim(R.animator.nav_default_enter_anim) .setExitAnim(R.animator.nav_default_exit_anim); } navController.navigate( // Assume the itemId is the android:id of a destination in the graph. itemId, null, builder.build() ); binding.getSlidingPaneLayout().open(); }
Ayrıntı bölmesinin gezinme grafiğindeki hedefler şu hedeflerde bulunmamalıdır:
uygulama genelindeki herhangi bir gezinme grafiği. Ancak ayrıntılardaki derin bağlantılar
bölmenin gezinme grafiği,
SlidingPaneLayout
Bu, harici derin bağlantıların ilk olarak gezinmesini sağlar
SlidingPaneLayout
hedefine gidip doğru ayrıntıya gidin
bölme hedefini.
Bkz. TwoPaneFragment örneği iki bölmeli düzenin tam olarak uygulanması için Gezinme bileşenini kullanır.
Sistemin geri düğmesiyle entegrasyon
Liste ve ayrıntı bölmelerinin çakıştığı daha küçük cihazlarda, sistemin
geri düğmesi, kullanıcıyı ayrıntı penceresinden liste bölmesine geri götürür. Bunu yap
özel geri ödeme sağlayarak
gezinme ve bir
OnBackPressedCallback
-
SlidingPaneLayout
öğesinin mevcut durumu:
Kotlin
class TwoPaneOnBackPressedCallback( private val slidingPaneLayout: SlidingPaneLayout ) : OnBackPressedCallback( // Set the default 'enabled' state to true only if it is slidable, such as // when the panes overlap, and open, such as when the detail pane is // visible. slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen ), SlidingPaneLayout.PanelSlideListener { init { slidingPaneLayout.addPanelSlideListener(this) } override fun handleOnBackPressed() { // Return to the list pane when the system back button is tapped. slidingPaneLayout.closePane() } override fun onPanelSlide(panel: View, slideOffset: Float) { } override fun onPanelOpened(panel: View) { // Intercept the system back button when the detail pane becomes // visible. isEnabled = true } override fun onPanelClosed(panel: View) { // Disable intercepting the system back button when the user returns to // the list pane. isEnabled = false } }
Java
class TwoPaneOnBackPressedCallback extends OnBackPressedCallback implements SlidingPaneLayout.PanelSlideListener { private final SlidingPaneLayout mSlidingPaneLayout; TwoPaneOnBackPressedCallback(@NonNull SlidingPaneLayout slidingPaneLayout) { // Set the default 'enabled' state to true only if it is slideable, such // as when the panes overlap, and open, such as when the detail pane is // visible. super(slidingPaneLayout.isSlideable() && slidingPaneLayout.isOpen()); mSlidingPaneLayout = slidingPaneLayout; slidingPaneLayout.addPanelSlideListener(this); } @Override public void handleOnBackPressed() { // Return to the list pane when the system back button is tapped. mSlidingPaneLayout.closePane(); } @Override public void onPanelSlide(@NonNull View panel, float slideOffset) { } @Override public void onPanelOpened(@NonNull View panel) { // Intercept the system back button when the detail pane becomes // visible. setEnabled(true); } @Override public void onPanelClosed(@NonNull View panel) { // Disable intercepting the system back button when the user returns to // the list pane. setEnabled(false); } }
Geri çağırmayı
OnBackPressedDispatcher
kullanarak
addCallback()
:
Kotlin
class TwoPaneFragment : Fragment(R.layout.two_pane) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val binding = TwoPaneBinding.bind(view) // Connect the SlidingPaneLayout to the system back button. requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, TwoPaneOnBackPressedCallback(binding.slidingPaneLayout)) // Set up the RecyclerView adapter. } }
Java
class TwoPaneFragment extends Fragment { public TwoPaneFragment() { super(R.layout.two_pane); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TwoPaneBinding binding = TwoPaneBinding.bind(view); // Connect the SlidingPaneLayout to the system back button. requireActivity().getOnBackPressedDispatcher().addCallback( getViewLifecycleOwner(), new TwoPaneOnBackPressedCallback(binding.getSlidingPaneLayout())); // Set up the RecyclerView adapter. } }
Kilit modu
SlidingPaneLayout
her zaman open()
adlı kullanıcıyı manuel olarak aramanızı ve
close()
Bölme, telefonlarda liste ile ayrıntı bölmeleri arasında geçiş yapar. Bu yöntemlerde
görünür olduğunda ve çakışmadığında etkisini gösterir.
Liste ve ayrıntı bölmeleri çakıştığında, kullanıcılar kaydırarak
Varsayılan olarak, hareket kullanılmadığında bile iki bölme arasında serbestçe geçiş yapılabilir.
gezinme başlıklı makaleyi inceleyin. Kaydırma yönünü kontrol edebilirsiniz
SlidingPaneLayout
cihazının kilit modunu ayarlayarak:
Kotlin
binding.slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
Java
binding.getSlidingPaneLayout().setLockMode(SlidingPaneLayout.LOCK_MODE_LOCKED);
Daha fazla bilgi
Farklı form faktörleri için düzenler tasarlama hakkında daha fazla bilgi edinmek üzere şu dokümanları bulabilirsiniz:
Ek kaynaklar
- Uyarlanabilir Düzenler codelab'i
- SlidingPaneLayout örneği bulabilirsiniz.