التعامل مع تغييرات الضبط

واجهة المستخدم سريعة الاستجابة والتنقل

لتوفير أفضل تجربة تنقل ممكنة للمستخدمين، يجب عليك توفير واجهة مستخدم للتنقل مصممة خصيصًا للعرض والارتفاع أصغر عرض لجهاز المستخدم. قد ترغب في استخدام شريط التطبيق السفلي، متوفّرة دائمًا أو قابلة للتصغير ودرج التنقل سكة حديدية أو ربما شيئًا جديدًا تمامًا بناءً على مساحة الشاشة المتاحة الفريد للتطبيق.

أمثلة على شريط، وأدراج تنقُّل، وشريط تطبيق سفلي
الشكل 1. أمثلة على سكة حديدية وأدراج التنقّل أسفل شريط التطبيق

التصميم المتعدد الأبعاد دليل بنية المنتج وتوفر سياقًا واعتبارات إضافية لإنشاء واجهة مستخدم سريعة الاستجابة — هو، واجهة مستخدم تتكيّف ديناميكيًا مع التغيرات البيئية. هناك بعض الأمثلة على تشمل التغييرات البيئية تعديلات على العرض والطول والاتجاه تفضيل لغة المستخدم. يتم تجميع هذه الخصائص البيئية معًا باسم تهيئة الجهاز.

عند تغيير خاصية واحدة أو أكثر من هذه الخصائص في وقت التشغيل، يستجيب نظام التشغيل Android في إتلاف أنشطة تطبيقك وأجزائه ثم إعادة إنشائها وبالتالي، فإن أفضل شيء يمكنك فعله لدعم واجهة المستخدم سريعة الاستجابة على Android هو من أنك تستخدم مؤهِّلات إعدادات الموارد حيثما كان ذلك مناسبًا تجنب استخدام أحجام التنسيقات غير الثابتة.

تنفيذ التنقل العام في واجهة مستخدم سريعة الاستجابة

يبدأ تنفيذ التنقل العام كجزء من واجهة المستخدم سريعة الاستجابة النشاط الذي يستضيف الرسم البياني للتنقل. للحصول على مثال عملي، حدد الخروج من الدرس التطبيقي حول ترميز التنقل. يستخدم الدرس التطبيقي حول الترميز NavigationView. لعرض قائمة التنقل، كما هو موضح في الشكل 2. عند التشغيل على جهاز يتم عرضها بحجم لا يقل عن 960 بكسل مستقل الكثافة (dp)، وتكون قيمة NavigationView هذه دائمًا على الشاشة.

درس تطبيقي حول ترميز التنقل يستخدم طريقة عرض تنقل تكون مرئية دائمًا
            عندما يكون عرض الجهاز 960 بكسل مستقل الكثافة على الأقل
الشكل 2. يستخدم درس تطبيقي حول ترميز التنقل NavigationView لعرض قائمة التنقّل.

يتم تبديل أحجام الأجهزة والاتجاهات الأخرى ديناميكيًا بين DrawerLayout أو BottomNavigationView حسب الحاجة.

عرض تنقُّل سفلي وتنسيق درج، يتم استخدامهما للتنقّل
            القائمة حسب الحاجة في تخطيطات جهاز أصغر
الشكل 3. يستخدم الدرس التطبيقي حول ترميز التنقل BottomNavigationView وDrawerLayout لعرض قائمة التنقّل على الأجهزة الأصغر حجمًا

يمكنك تنفيذ هذا السلوك من خلال إنشاء ثلاثة تنسيقات مختلفة، تكون كل منها يحدد عناصر التنقل المطلوبة وعرض التسلسل الهرمي استنادًا إلى من إعدادات الجهاز الحالية.

يتم تحديد الإعدادات التي ينطبق عليها كل تنسيق من خلال الدليل. الهيكل الذي يتم وضع ملف التخطيط فيه. على سبيل المثال، NavigationView ملف التخطيط في الدليل res/layout-w960dp.

<!-- 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>

يمكنك العثور على عرض التنقّل السفلي في دليل res/layout-h470dp:

<!-- 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>

يمكنك العثور على تنسيق الدرج في دليل res/layout. استخدام هذا الدليل في التنسيقات التلقائية التي لا تتضمن أي مؤهلات خاصة بالإعداد:

<!-- 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 ترتيب الأسبقية عند تحديد الموارد التي سيتم تطبيقها. تحديدًا لهذا المثال: -w960dp تكون الأولوية للعرض (أو العرض المتوفّر >= 960 بكسل مستقل الكثافة) على -h470dp (أو متوفّرة). الارتفاع >= 470). إذا لم تتطابق إعدادات الجهاز مع أي من هذين الإعدادين والشروط، ثم مورد التنسيق الافتراضي يتم استخدام (res/layout/navigation_activity.xml).

عند التعامل مع أحداث التنقّل، عليك توصيل الأحداث المتوافقة فقط إلى الأدوات الموجودة حاليًا، كما هو موضح في المثال التالي.

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);
       }

   }
}

في حال تغيير إعدادات الجهاز، ما لم يتم صراحةً تمت تهيئته بطريقة أخرى، يلغي Android النشاط من الإعدادات السابقة إلى جانب الملفات الشخصية المرتبطة بها. ثم تعيد إنشاء النشاط باستخدام الموارد المصممة الإعدادات الجديدة. النشاط الذي يتم إتلافه وإعادة إنشائه، يؤدّي تلقائيًا إلى ربط عناصر التنقّل العمومية المناسبة في onCreate().

تجربة بدائل لتنسيقات العرض المقسّم

كانت تنسيقات العرض المقسّم، أو التنسيقات الرئيسية/التفاصيل، سابقًا طريقة شائعة جدًا وموصى بها للتصميم للأجهزة اللوحية وغيرها من الشاشات الكبيرة الأجهزة.

منذ طرح أجهزة Android اللوحية، نمت المنظومة المتكاملة للأجهزة بسرعة. واعلم أن أحد العوامل التي أثرت بشكل كبير على مساحة التصميم أجهزة الشاشة إلى إدخال أوضاع النوافذ المتعددة، خاصة النوافذ الحرة التي يمكن تغيير حجمها بالكامل، مثل النوافذ على أجهزة ChromeOS وهذا يؤدي إلى تركيز أكبر بكثير على كل شاشة من شاشات تطبيقك سريع الاستجابة، بدلاً من تغيير هيكل التنقل بناءً على الشاشة الحجم.

في حين أنه من الممكن تنفيذ واجهة تخطيط تقسيم العرض باستخدام مكتبة التنقل، فيجب عليك والتفكير في بدائل أخرى.

أسماء الوجهات

في حال تقديم أسماء وجهات في الرسم البياني باستخدام android:label احرص على استخدام قيم الموارد دائمًا حتى يتمكن المحتوى التابع لك من .

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

باستخدام قيم الموارد، تحتوي وجهاتك تلقائيًا على أكثر المواقع ملاءمةً تطبيق الموارد كلما تغيرت الإعدادات.