Yapılandırma değişikliklerini işleme

Duyarlı kullanıcı arayüzü ve gezinme

Kullanıcılarınıza mümkün olan en iyi gezinme deneyimini sunmak için kullanıcı cihazının genişliğine, yüksekliğine ve en küçük genişliğine göre uyarlanmış bir gezinme kullanıcı arayüzü sağlamanız gerekir. Alt uygulama çubuğu, her zaman var olan veya daraltılabilir bir gezinme çekmecesi, ray veya mevcut ekran alanına ve uygulamanızın benzersiz stiline bağlı olarak tamamen yeni bir şey kullanmak isteyebilirsiniz.

Ray, gezinme çekmecesi ve alt uygulama çubuğu örnekleri
Şekil 1. Ray, gezinme çekmecesi ve alt uygulama çubuğu örnekleri.

Materyal tasarım ürün mimarisi kılavuzu, duyarlı bir kullanıcı arayüzü (çevresel değişikliklere dinamik olarak uyum sağlayan bir kullanıcı arayüzü) oluşturmak için ek bağlam ve dikkat edilmesi gereken noktalar sağlar. Çevresel değişikliklere örnek olarak genişlik, yükseklik, yön ve kullanıcının dil tercihinde yapılan ayarlamalar verilebilir. Bu çevresel özellikleri topluca cihazın yapılandırması olarak adlandırılır.

Çalışma zamanında bu özelliklerden biri veya daha fazlası değiştiğinde Android OS, uygulamanızın etkinliklerini ve parçalarını yok edip yeniden oluşturarak yanıt verir. Bu nedenle, Android'de duyarlı bir kullanıcı arayüzünü desteklemek için yapabileceğiniz en iyi şey, uygun yerlerde kaynak yapılandırma niteleyicilerini kullandığınızdan emin olmak ve sabit kodlu düzen boyutlarını kullanmaktan kaçınmaktır.

Duyarlı bir kullanıcı arayüzünde genel gezinme uygulama

Genel gezinmeyi duyarlı bir kullanıcı arayüzünün parçası olarak uygulamak, gezinme grafiğinizi barındıran etkinlikle başlar. Uygulamalı bir örnek için Navigasyon codelab'e göz atın. Codelab, Şekil 2'de gösterildiği gibi gezinme menüsünü görüntülemek için bir NavigationView kullanır. Bu NavigationView, en az 960 dp genişlikte oluşturulan bir cihazda çalıştırıldığında her zaman ekranda kalır.

Codelab, cihaz genişliği en az 960 dp olduğunda her zaman görünen bir gezinme görünümü kullanır.
Şekil 2. Navigasyon codelab'i, gezinme menüsünü görüntülemek için bir NavigationView kullanır.

Diğer cihaz boyutları ve yönleri, gerektiğinde DrawerLayout veya BottomNavigationView arasında dinamik olarak geçiş yapar.

alt gezinme görünümü ve çekmece düzeni; daha küçük cihaz düzenlerinde gerektiğinde gezinme menüsü için kullanılır
Şekil 3. Navigasyon codelab'i daha küçük cihazlarda gezinme menüsünü görüntülemek için BottomNavigationView ve DrawerLayout öğelerini kullanır.

Bu davranışı, her bir düzenin istenen gezinme öğelerini tanımladığı ve mevcut cihaz yapılandırmasına dayalı olarak hiyerarşiyi görüntülediği üç farklı düzen oluşturarak uygulayabilirsiniz.

Her bir düzenin uygulanacağı yapılandırma, düzen dosyasının yerleştirildiği dizin yapısıyla belirlenir. Örneğin, NavigationView düzen dosyası res/layout-w960dp dizininde bulunur.

<!-- res/layout-w960dp/navigation_activity.xml -->
<RelativeLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.example.android.codelabs.navigation.MainActivity">

   <com.google.android.material.navigation.NavigationView
       android:id="@+id/nav_view"
       android:layout_width="wrap_content"
       android:layout_height="match_parent"
       android:layout_alignParentStart="true"
       app:elevation="0dp"
       app:headerLayout="@layout/nav_view_header"
       app:menu="@menu/nav_drawer_menu" />

   <View
       android:layout_width="1dp"
       android:layout_height="match_parent"
       android:layout_toEndOf="@id/nav_view"
       android:background="?android:attr/listDivider" />

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/toolbar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentTop="true"
       android:layout_toEndOf="@id/nav_view"
       android:background="@color/colorPrimary"
       android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />

   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/my_nav_host_fragment"
       android:name="androidx.navigation.fragment.NavHostFragment"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_below="@id/toolbar"
       android:layout_toEndOf="@id/nav_view"
       app:defaultNavHost="true"
       app:navGraph="@navigation/mobile_navigation" />
</RelativeLayout>

Alt gezinme görünümü res/layout-h470dp dizininde bulunur:

<!-- res/layout-h470dp/navigation_activity.xml -->
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   tools:context="com.example.android.codelabs.navigation.MainActivity">

   <androidx.appcompat.widget.Toolbar
       android:id="@+id/toolbar"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:background="@color/colorPrimary"
       android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />

   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/my_nav_host_fragment"
       android:name="androidx.navigation.fragment.NavHostFragment"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"
       app:defaultNavHost="true"
       app:navGraph="@navigation/mobile_navigation" />

   <com.google.android.material.bottomnavigation.BottomNavigationView
       android:id="@+id/bottom_nav_view"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:menu="@menu/bottom_nav_menu" />
</LinearLayout>

Çekmece düzeni res/layout dizininde bulunur. Yapılandırmaya özel niteleyici içermeyen varsayılan düzenler için bu dizini kullanın:

<!-- res/layout/navigation_activity.xml -->
<androidx.drawerlayout.widget.DrawerLayout
   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/drawer_layout"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context="com.example.android.codelabs.navigation.MainActivity">

   <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">

       <androidx.appcompat.widget.Toolbar
           android:id="@+id/toolbar"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:background="@color/colorPrimary"
           android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar" />

       <androidx.fragment.app.FragmentContainerView
           android:id="@+id/my_nav_host_fragment"
           android:name="androidx.navigation.fragment.NavHostFragment"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           app:defaultNavHost="true"
           app:navGraph="@navigation/mobile_navigation" />
   </LinearLayout>

   <com.google.android.material.navigation.NavigationView
       android:id="@+id/nav_view"
       android:layout_width="wrap_content"
       android:layout_height="match_parent"
       android:layout_gravity="start"
       app:menu="@menu/nav_drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>

Android, hangi kaynakları uygulayacağını belirlerken bir öncelik sırası izler. Bu örneğe özel olarak, -w960dp (veya kullanılabilir genişlik >= 960 dp), -h470dp (veya kullanılabilir yükseklik >= 470) değerine göre önceliklidir. Cihaz yapılandırması bu koşullardan herhangi biriyle eşleşmezse varsayılan düzen kaynağı (res/layout/navigation_activity.xml) kullanılır.

Gezinme etkinliklerini işlerken, aşağıdaki örnekte gösterildiği gibi yalnızca mevcut widget'lara karşılık gelen etkinlikleri bağlamanız gerekir.

Kotlin

class MainActivity : AppCompatActivity() {

   private lateinit var appBarConfiguration : AppBarConfiguration

   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.navigation_activity)
      val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
      appBarConfiguration = AppBarConfiguration(
                  setOf(R.id.home_dest, R.id.deeplink_dest),
                  drawerLayout)

      ...

      // Initialize the app bar with the navigation drawer if present.
      // If the drawerLayout is not null here, a Navigation button will be added
      // to the app bar whenever the user is on a top-level destination.
      setupActionBarWithNavController(navController, appBarConfig)

      // Initialize the NavigationView if it is present,
      // so that clicking an item takes
      // the user to the appropriate destination.
      val sideNavView = findViewById<NavigationView>(R.id.nav_view)
      sideNavView?.setupWithNavController(navController)

      // Initialize the BottomNavigationView if it is present,
      // so that clicking an item takes
      // the user to the appropriate destination.
      val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
      bottomNav?.setupWithNavController(navController)

      ...
    }

    ...
}

Java

public class MainActivity extends AppCompatActivity {

   private AppBarConfiguration appBarConfiguration;

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.navigation_activity);
       NavHostFragment host = (NavHostFragment) getSupportFragmentManager()
               .findFragmentById(R.id.my_nav_host_fragment);
       NavController navController = host.getNavController();

       DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
       appBarConfiguration = new AppBarConfiguration.Builder(
               R.id.home_dest, R.id.deeplink_dest)
               .setDrawerLayout(drawerLayout)
               .build();

       // Initialize the app bar with the navigation drawer if present.
       // If the drawerLayout is not null here, a Navigation button will be added to
       // the app bar whenever the user is on a top-level destination.
       NavigationUI.setupActionBarWithNavController(
               this, navController, appBarConfiguration);


       // Initialize the NavigationView if it is present,
       // so that clicking an item takes
       // the user to the appropriate destination.
       NavigationView sideNavView = findViewById(R.id.nav_view);
       if(sideNavView != null) {
           NavigationUI.setupWithNavController(sideNavView, navController);
       }

       // Initialize the BottomNavigationView if it is present,
       // so that clicking an item takes
       // the user to the appropriate destination.
       BottomNavigationView bottomNav = findViewById(R.id.bottom_nav_view);
       if(bottomNav != null) {
           NavigationUI.setupWithNavController(bottomNav, navController);
       }

   }
}

Cihaz yapılandırması değişirse, başka bir şekilde yapılandırılmadığı sürece Android, önceki yapılandırmadaki etkinliği ilişkili görünümleriyle birlikte kaldırır. Ardından, yeni yapılandırma için tasarlanan kaynaklarla etkinliği yeniden oluşturur. Yıkılıp yeniden oluşturulan etkinlik, onCreate() içindeki uygun genel gezinme öğelerini otomatik olarak bağlar.

Bölünmüş görünüm düzenlerinin alternatiflerini değerlendirin

Bölünmüş görünüm düzenleri veya ana/ayrıntılı düzenler, bir zamanlar tabletler ve diğer büyük ekranlı cihazlar için tasarım yapmanın çok popüler ve önerilen bir yoluydu.

Android tabletlerin piyasaya sürüldüğünden beri cihaz ekosistemi hızla büyüdü. Büyük ekranlı cihazların tasarım alanını önemli ölçüde etkileyen faktörlerden biri de çok pencereli modların, özellikle de ChromeOS cihazlardakiler gibi tamamen yeniden boyutlandırılabilir olan serbest biçimli pencerelerdir. Bu yaklaşım, gezinme yapınızı ekran boyutuna göre değiştirmek yerine uygulamanızın her ekranının duyarlı olmasına çok daha fazla önem verir.

Gezinme kitaplığını kullanarak bölünmüş görünümlü düzen arayüzü uygulamak mümkün olsa da diğer alternatifleri de değerlendirmeniz gerekir.

Hedef adları

Grafiğinizde android:label özelliğini kullanarak hedef adları sağlarsanız içeriğinizin yine de yerelleştirilebilmesi için her zaman kaynak değerleri kullandığınızdan emin olun.

<navigation ...>
    <fragment
        android:id="@+id/my_dest"
        android:name="com.example.MyFragment"
        android:label="@string/my_dest_label"
        tools:layout="@layout/my_fragment" />
    ...

Kaynak değerleriyle, yapılandırmanız her değiştiğinde hedeflerinize otomatik olarak en uygun kaynaklar uygulanır.