الشظايا

الإعلانات

الشظايا

 

تمثل الشظايا سلوكاً أو جزءاً من واجهة المستخدم، في “أنشطة الشظايا” FragmentActivity. يمكنك دمج عدة شظايا في نشاط واحد..

لإنشاء واجهة مستخدم متعددة الأجزاء، وإعادة إستخدام الشظيه في عدة أنشطة. يمكنك التفكير في الشظيه كقسم نموذجي من النشاط..

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

(يعتبر نوعاً ما “نشاط فرعي” يمكنك إعادة إستخدامه في أنشطة مختلفة).

يجب دائماً إستضافة الشظيه بداخل النشاط، وتتأثر دورة حياة الشظيه مباشرة، بدورة حياة النشاط المضيف.

مثال، عندما يكون النشاط متوقف مؤقتاً، فسوف تتوقف جميع الشظايا، الموجودة بداخله مؤقتاً أيضاً، وعندما يتم تدمير النشاط..

سوف يتم تدمير جميع الشظايا أيضاً. ومع ذلك، حينما يتم تشغيل أحد الأنشطة (وهو في حالة الإستئناف من حالة دورة الحياة)..

يمكنك التعامل مع كل شظية بشكلٍ مستقل، مثل إضافتها أو إزالتها.

عند تنفيذك لمعاملات شظايا مماثله، يمكنك أيضاً إضافتها إلى الكومة الخلفيه والتي تتم إدارتها بواسطة النشاط –

كل إدخال للكومه في النشاط، عبارة عن سجل لمعاملة الشظيه التي حدثت.

تسمح الكومة الخلفية للمستخدم بعكس معاملة الشظية (التنقل إلى الخلف)، عن طريق الضغط على الزر “رجوع”.

عند إضافتك لشظيه كجزء من مخطط نشاطك، فإنه يقبع في ViewGroup بداخل التسلسل الهرمي لطريقة عرض النشاط..

وتحدد الشظيه مخطط العرض “المعاينه” الخاص بها. يمكنك إدراج شظيه في مخطط نشاطك عن طريق، الإعلان عن الشظيه في ملف مخطط النشاط..

كعنصر <fragment>، أو من خلال كود التطبيق عن طريق إضافتها إلى ViewGroup موجود.

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

مشاركة الأحداث، مع النشاط والشظايا الأخرى في النشاط، المساهمة في شريط التطبيق الخاص بالنشاط، والمزيد.

للحصول على معلومات حول التعامل مع دورة الحياة، بما في ذلك الإرشادات حول أفضل الممارسات، راجع المصادر التالية:

 

 

 

 

 

فلسفة التصميم


قدم الأندرويد الشظايا، في الإصدار 3.0 (مستوى API 11)، بشكلٍ أساسي، لدعم تصميمات واجهة المستخدم..

الأكثر حيوية ومرونة على الشاشات الكبيرة، مثل الأجهزة اللوحية. لأن شاشة الجهاز اللوحي أكبر بكثير من شاشة الهاتف..

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

لإدارة التغييرات المعقدة لطرق تسلسل العرض. من خلال تقسيم مخطط النشاط إلى شظايا، ستصبح قادراً على..

تعديل المظهر الخارجي للنشاط، أثناء التشغيل، والحفاظ على تلك التغييرات، في الكومة الخلفيه، التي تتم إدارتها بواسطة النشاط.

وهي متوفرة الآن على نطاق واسع من خلال مكتبة دعم الشظايا.

 

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

وشظية أخرى لعرض المقالة على اليمين – تظهر كلتا الشظايا في نشاط واحد جنباً إلى جنب، وتحتوي كل شظيه على مجموعة دورة الحياة الخاصة بها.

و دوال الإستدعاء، ومعالجة أحداث إدخال المستخدم الخاصة بها. وبالتالي، بدلاً من إستخدام نشاط لتحديد مقالة، ونشاط آخر لقراءة المقالة..

يمكن للمستخدم تحديد مقال وقراءته، وكل هذا في نفس النشاط، كما هو موضح في مخطط الجهاز اللوحي في الشكل 1.

 

يجب عليك تصميم كل شظية كمكون نشاط نموذجي وقابل لإعادة الإستخدام. وهذا لأن كل شظيه تحدد مخططها الخاص، وسلوكها الخاص..

مع عمليات الإستدعاء في دورة حياتها الخاصة، يمكنك تضمين شظيه واحدة في عدة أنشطة، لذا يجب عليك تصميمها بشكلٍ مناسب..

لإعادة الإستخدام وتجنب التعامل مباشرة مع شظية، من خلال شظية أخرى. يعد هذا أمراً مهماً بشكلٍ خاص، لأن الشظية النموذجية تسمح لك..

بتغيير تركيبات الشظايا الخاصة بك، لتناسب أحجام مختلفة من الشاشة. عند تصميمك لتطبيق يدعم كلٍ من الأجهزة اللوحية والهواتف..

يمكنك إعادة إستخدام الشظايا، في تكوينات مخطط مختلفة، لتحسين تجربة المستخدم بناءً على مساحة الشاشة المتاحة.

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

 

على سبيل المثال – للإستمرار مع مثال تطبيق الأخبار – عند التشغيل على جهاز بحجم الجهاز اللوحي- يمكن للتطبيق أن يقوم بتضمين شظيتين في النشاط أ.

ومع ذلك، عند التشغيل على شاشة بحجم الهاتف، لن تكون هناك مساحة كافية لكلا الشظيتين..

 

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

 

 

لذا يتضمن النشاط أ فقط على الشظيه الخاصه بقائمة المقالات، وعندما يختار المستخدم مقالة، فإنه يقوم ببدأ النشاط ب ..

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

عن طريق إعادة إستخدام الشظايا في تراكيب مختلفة، كما هو موضح في الشكل 1.

لمزيد من المعلومات حول تصميم التطبيق، مع تراكيب شظايا مختلفة، لتكوينات شاشة مختلفة، راجع نظرة عامة على توافق الشاشة.

 

 

 

 

 

 

 

إنشاء الشظايا


لإنشاء شظيه، يجب عليك إنشاء فئة فرعية من الشظيه (أو فئة فرعية موجودة منها). تحتوي فئة الشظيه Fragment على كود يشبه النشاط إلى حدٍ كبير.

فهو يحتوي على دوال إستدعاء مشابهة لدوال النشاط، مثل:

()onCreate()  ، onStart()  ،onPause ، و ()onStop .

في الواقع، إذا كنت تقوم بتحويل تطبيق أندرويد حالي، لكي يستخدم الشظايا، فيمكنك ببساطة نقل الكود من..

دوال الإستدعاء الخاصة بالنشاط إلى دوال الإستدعاء الخاصة بالشظايا.

عادة، يجب عليك تنفيذ دوال دورة الحياة التالية على الأقل: 

()OnCreate

يستدعي النظام هذه الدالة عند إنشاء الشظيه. ضمن عملية التنفيذ، يجب عليك تهيئة المكونات الأساسية للشظيه..

والتي تريد الإحتفاظ بها عند إيقاف الشظية مؤقتاً أو إيقافها كلياً، ثم إستئنافها.

 

 

الشكل 2. دورة حياة شظيه (أثناء تشغيل نشاطها).

()onCreateView

يقوم النظام بإستدعاء هذه الدالة عندما يحين وقت قيام الشظيه برسم واجهة المستخدم الخاصة بها لأول مرة.

لرسم واجهة مستخدم لشظيتك، يجب عليك إرجاع عرض “معاينه” من هذه الداله التي تعد أساس مخطط شظيتك.

يمكنك إرجاع “فارغ” إذا كانت الشظيه لا توفر واجهة مستخدم.

 

()onPause

يقوم النظام بإستدعاء هذه الداله، كأول علامة على أن المستخدم يغادر الشظيه (على الرغم من أن هذا لا يعني دائماً أن الشظيه قد تم تدميرها).

عادةً ما يكون هذا هو المكان، حيث يجب أن تلزم فيه بأي تغييرات، يجب أن تستمر بعد جلسة المستخدم الحالية (لأن المستخدم قد لا يعود).

 

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

والتي يجب إستخدامها أيضاً، للتعامل مع المراحل المختلفة من دورة حياة الشظايا. تتم مناقشة جميع دوال الإستدعاء..

الخاصة بدورة الحياة بمزيد من التفصيل في القسم الذي يتحدث عن التعامل مع دورة حياة الشظيه.

 

 

لاحظ أنه يجب وضع الكود، الذي يقوم بتنفيذ إجراءات دورة الحياة للمكون التابع، في المكون نفسه، بدلاً من وضعه مباشرة في عمليات تنفيذ إستدعاء الشظيه.

اقرأ التعامل مع دورات الحياة، بإستخدام مكونات مدركة لدورة الحياة – لمعرفة كيفية جعل مكوناتك التابعة مدركة لدورة الحياة.

 

هناك أيضاً بعض الفئات الفرعية التي قد ترغب في توسيعها، بدلاً من فئة الشظايا الأساسية:

 

DialogFragment

تقوم بعرض مربع حوار عائم. يعد إستخدام هذه الفئة لإنشاء مربع حوار بديلٍ، جيد لإستخدام دوال مساعد مربع الحوار في فئة النشاط..

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

 

ListFragment

تقوم بعرض قائمة من العناصر التي يتم إدارتها بواسطة محول (مثل محول SimpleCursorAdapter)، بشكلٍ مشابه لـ ListActivity.

يوفر العديد من الدوال لإدارة عرض القائمة، مثل إستدعاء ()onListItemClick لمعالجة أحداث النقر.

(لاحظ أن الدالة المفضلة لعرض القائمة هي إستخدام RecyclerView بدلاً من ListView. في هذه الحالة..

ستحتاج إلى إنشاء شظية تتضمن RecyclerView في مخططها. اقرأ إنشاء قائمة بإستخدام RecyclerView للتعرف على كيفية فعل ذلك.)

 

PreferenceFragmentCompat

تقوم بعرض تسلسل هرمي لكائنات التفضيل كقائمة، تستخدم لإنشاء شاشة الإعدادات لتطبيقك.

 

 

 

 

إضافة واجهة مستخدم

عادة ما تستخدم الشظيه، كجزء من واجهة مستخدم النشاط، وتشارك مخططها الخاص مع النشاط.

لتوفير مخطط لشظية، يجب عليك تنفيذ إستدعاء الدالة ()onCreateView ، والتي يستدعيها نظام الأندرويد عندما يحين وقت قيام الشظيه برسم مخططها.

تنفيذك لهذه الداله، يجب أن يقوم بإرجاع عرض “معاينه” يمثل أساس مخطط الشظيه الخاصه بك.

ملاحظة: إذا كانت الشظيه الخاصة بك عبارة عن فئة فرعية من “قائمة الشظايا” ListFragment، سيقوم التنفيذ الإفتراضي..

بإرجاع ListView من ()onCreateView، بحيث لا تحتاج إلى تنفيذها.

 

 

لإرجاع مخطط من ()onCreateView ، يمكنك تضخيمه من مصدر المخطط المحدد في ملف XML.

لمساعدتك على القيام بذلك، توفر ()onCreateView كائن تضخيم المخطط LayoutInflater.

مثال، في ما يلي فئة فرعية من الشظيه Fragment تقوم بتحميل مخطط من الملف example_fragment.xml:

KOTLIN

class ExampleFragment : Fragment() {

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false)
    }
}

JAVA

public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

 

ملاحظة: في المثال السابق، R.layout.example_fragment عبارة عن مرجع لمصدر مخطط بأسم example_fragment.xml تم حفظه في مصادر التطبيق.

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

 

معامل “باراميتر” الحاويه الذي تم تمريره إلى ()onCreateView هو ViewGroup الأصل (من مخطط النشاط) والذي يتم فيه إدراج مخطط الشظيه الخاص بك.

المعامل saveInstanceState عبارة عن حزمة توفر بيانات عن المثيل السابق للشظيه، عندما تكون الشظيه في حالة إستئناف..

(تتم مناقشة حالة الإستعادة بشكلٍ أكبر في القسم الذي يتحدث عن، التعامل مع دورة حياة الشظية).

 

 

دالة التضخيم ()inflate تأخذ ثلاثة معطيات:

– معرف المصدر للمخطط الذي ترغب في تضخيمه.

 

– يجب أن تكون مجموعة ViewGroup هي الأصل للمخطط المضخم. يعد تمرير الحاوية مهماً لكي يتمكن النظام..

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

 

– قيمة منطقيه تشير إلى ما إذا كان يجب إرفاق المخطط المضخم بـ ViewGroup (المعامل الثاني) أثناء التضخيم.

(في هذه الحالة، تأخذ القيمة “خطأ” لأن النظام يقوم بالفعل بإدراج المخطط الذي تم تضخيمه إلى الحاوية

يؤدي تمرير القيمة “صحيح” إلى إنشاء مجموعة عرض زائدة في المخطط النهائي.)

 

لقد رأيت الآن كيفية إنشاء شظيه توفر مخطط. تالياً، ستحتاج إلى إضافة الشظيه إلى نشاطك.

 

 

إضافة شظيه إلى نشاط

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

هناك طريقتان يمكنك من خلالهما إضافة شظيه إلى مخطط النشاط:

 

  •  الإعلان عن الشظيه بداخل ملف مخطط النشاط.

في هذه الحالة، يمكنك تحديد خصائص المخطط للشظيه، كما لو كانت عرض. على سبيل المثال، إليك ملف المخطط لنشاط به جزأين “شظيتين”:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment android:name="com.example.news.ArticleListFragment"
            android:id="@+id/list"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
    <fragment android:name="com.example.news.ArticleReaderFragment"
            android:id="@+id/viewer"
            android:layout_weight="2"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
</LinearLayout>

 

 

تعيّن سمة الأسم android:name في <fragment> فئة الشظايا Fragment لتكوين مثيل في المخطط.

عندما يقوم النظام بإنشاء مخطط النشاط هذا، فإنه يقوم بتمثيل كل شظيه محدده في المخطط ويقوم بإستدعاء دالة ()onCreateView لكلٍ منها..

لإسترداد مخطط كل شظية. يقوم النظام بإدراج طريقة العرض التي تم إرجاعها بواسطة الشظيه مباشرة بدلاً من عنصر <fragment>.

 

ملاحظة: تتطلب كل شظيه معرفاً فريداً يمكن للنظام إستخدامه لإستعادة الشظيه في حالة إعادة تشغيل النشاط..

(والذي يمكنك إستخدامه لإلتقاط الشظيه لتنفيذ المعاملات، مثل إزالتها). هناك طريقتان لتوفير معرف للشظيه:

  •  تزويد سمة android:id بمعرّف فريد.
  •  تزويد سمة android:tag بسلسلة فريدة.

 

 

  •  أو بإضافة الشظيه برمجياً إلى ViewGroup موجودة.

في أي وقت أثناء تشغيل نشاطك، يمكنك إضافة شظايا إلى مخطط نشاطك. تحتاج ببساطة إلى تحديد ViewGroup حيث يمكنك وضع الشظيه.

لجعل معاملات الشظيه في نشاطك (مثل إضافة شظيه أو إزالتها أو إستبدالها)، يجب عليك إستخدام..

واجهات برمجة التطبيقات من FragmentTransaction. يمكنك الحصول على مثيل FragmentTransaction من FragmentActivity الخاص بك هكذا:

KOTLIN

val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()

JAVA

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

 

يمكنك بعد ذلك إضافة شظيه بإستخدام دالة الإضافة ()add ، مع تحديد الشظيه المراد إضافتها وطريقة العرض التي سيتم إدراجها بها. مثال:

KOTLIN

val fragment = ExampleFragment()
fragmentTransaction.add(R.id.fragment_container, fragment)
fragmentTransaction.commit()

JAVA

ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

 

المعطى الأول الذي تم تمريره إلى ()add هي ViewGroup حيث يجب وضع الشظيه، محدده بواسطة معرف المصدر، والمعامل الثاني هو الشظيه المراد إضافتها.

بمجرد إجرائك التغييرات بإستخدام FragmentTransaction، يجب عليك إستدعاء ()commit لتصبح التغييرات سارية المفعول.

 

 

 

 

إدارة الشظايا


لإدارة الشظايا في نشاطك، تحتاج إلى إستخدام FragmentManager. للحصول عليها، قم بإستدعاء ()getSupportFragmentManager من نشاطك.

بعض الأشياء التي يمكنك إجراؤها بإستخدام FragmentManager تتضمن:

– الحصول على الشظايا الموجودة في النشاط، بإستخدام ()findFragmentById (للشظايا التي توفر واجهة مستخدم في مخطط النشاط)..

أو ()findFragmentByTag (للشظايا التي توفر أو لا توفر واجهة مستخدم).

– إخراج الشظايا من الكومة الخلفية، بإستخدام ()popBackStack (محاكاة أمر الرجوع بواسطة المستخدم).

– تسجيل مستمع للتغييرات على الكومة الخلفية بإستخدام ()addOnBackStackChangedListener .

 

لمزيد من المعلومات حول هذه الدوال وغيرها، راجع وثائق فئة FragmentManager.

كما هو موضح في القسم السابق، يمكنك أيضاً إستخدام FragmentManager لفتح FragmentTransaction..

والتي تسمح لك بإجراء المعاملات، مثل إضافة و إزالة الشظايا.

 

 

 

 

 

تنفيذ معاملات الشظايا


من الميزات الرائعة لإستخدام الشظايا في نشاطك هو القدرة على إضافة وإزالة و إستبدال وتنفيذ إجراءات أخرى معهم..

وذلك إستجابة لتفاعل المستخدم. تسمى كل مجموعة من التغييرات التي تلتزم بها في النشاط بـ”معاملة”..

يمكنك تنفيذ واحدة منها “معامله” بإستخدام واجهات برمجة التطبيقات في FragmentTransaction.

يمكنك أيضاً حفظ كل معاملة إلى الكومة الخلفيه، التي يديرها النشاط، مما يسمح للمستخدم بالإنتقال إلى الخلف..

من خلال تغييرات الشظيه (بشكلٍ مماثل للإنتقال إلى الخلف خلال الأنشطة).

يمكنك الحصول على مثيل من FragmentTransaction من FragmentManager هكذا:

KOTLIN

val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()

JAVA

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

 

كل معاملة عبارة عن مجموعة من التغييرات التي تريد تنفيذها في نفس الوقت. يمكنك إعداد جميع التغييرات..

التي تريد تنفيذها لمعاملة معينة بإستخدام دوال مثل دالة الإضافة ()add , دالة الإزالة ()remove، و دالة الإستبدال ()replace .

ثم، لتطبيق المعاملة على النشاط، يجب عليك إستدعاء دالة الإلتزام ()commit .

 

مثال، قبل إستدعاء دالة الإلتزام ()commit ، قد ترغب في إستدعاء ()addToBackStack ، من أجل إضافة المعاملة إلى الكومة الخلفية من معاملات الشظايا.

تتم إدارة هذه الكومة الخلفيه، بواسطة النشاط و تسمح للمستخدم بالرجوع إلى الحالة السابقة للشظيه، عن طريق الضغط على زر “الرجوع”.

مثال، إليك كيفية إستبدال شظيه بشظية أخرى، والحفاظ على الحالة السابقة في الكومة الخلفية: 

KOTLIN

val newFragment = ExampleFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, newFragment)
transaction.addToBackStack(null)
transaction.commit()

JAVA

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

 

 

في هذا المثال، تحل newFragment محل أي شظيه (إن وجدت)، موجودة حالياً في حاوية المخطط المحددة بواسطة..

معرف R.id.fragment_container. من خلال إستدعاء ()addToBackStack ، يتم حفظ المعاملة الإستبداليه في الكومة الخلفية..

حتى يمكن للمستخدم عكس العملية وإعادة الشظية السابقه بالضغط على زر “الرجوع”.

تقوم FragmentActivity تلقائياً بعد ذلك بإسترداد الشظايا من الكومة الخلفيه عبر ()onBackPressed .

إذا قمت بإضافة عدة تغييرات إلى المعاملة – مثل إضافة دالة أخرى من ()add  أو ()remove – و إستدعاء ()addToBackStack ،..

عندها تتم إضافة كافة التغييرات المطبقة قبل إستدعاء ()commit إلى الكومة الخلفيه كمعاملة واحدة ويقوم زر “الرجوع” بعكسهم جميعاً معاً.

ترتيب إضافة التغييرات إلى FragmentTransaction غير مهم، بإستثناء:

 

– يجب عليك إستدعاء ()commit في الأخير.

– إذا كنت تضيف عدة شظايا إلى نفس الحاوية، فإن الترتيب الذي تضيفهم به يحدد ترتيب ظهورهم في التسلسل الهرمي لطريقة العرض.

 

 إذا لم تقم بإستدعاء ()addToBackStack عند إجراء معاملة تقوم بإزالة شظيه، فإن تلك الشظيه يتم تدميرها عند إلزام المعاملة..

ولا يمكن للمستخدم الإنتقال للرجوع إليها. في حين أنه، إذا قمت بإستدعاء ()addToBackStack عند إزالة شظية..

فسيتم إيقاف الشظيه ثم تستأنف لاحقاً إذا أنتقل المستخدم للخلف.

 

نصيحة: لكل معاملة شظيه، يمكنك تطبيق حركة إنتقال، عن طريق إستدعاء ()setTransition  قبل قيامك بالإلتزام.

 

لا يؤدي إستدعاء الإلتزام ()commit إلى إجراء المعاملة فوراً. بدلاً من ذلك، فإنه يجدولها لكي يتم تشغيلها على تسلسل..

واجهة المستخدم الخاص بالنشاط (التسلسل “الرئيسي”) بمجرد أن يتمكن التسلسل من القيام بذلك.

إذا لزم الأمر، يمكنك إستدعاء ()executePendingTransactions من تسلسل واجهة المستخدم لتنفيذ المعاملات التي..

تم إرسالها بواسطة ()commit مباشرة. عادةً لا يكون القيام بذلك ضرورياً ما لم تكن المعاملة معتمدة على وظائف في سلاسل أخرى.

تحذير: يمكنك فرض “إلزام” معاملة، بإستخدام ()commit فقط قبل قيام النشاط بحفظ حالته (عندما يغادر المستخدم النشاط).

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

بالنسبة للحالات التي لا بأس فيها أن تفقد الإلزام ، إستخدم ()commitAllowingStateLoss.

 

 

 

 

 

 

التواصل مع النشاط


على الرغم من أنه يتم تنفيذ الشظيه ككائن مستقل عن FragmentActivity ويمكن إستخدامها بداخل أنشطة متعددة، فإن مثيل معين من الشظية يرتبط مباشرة بالنشاط الذي يستضيفه.

على وجه التحديد، يمكن للشظيه الوصول إلى مثيل FragmentActivity بإستخدام ()getActivity ..

وتنفيذ المهام بسهولة مثل العثور على عرض “معاينه” في مخطط النشاط: 

KOTLIN

val listView: View? = activity?.findViewById(R.id.list)

JAVA

View listView = getActivity().findViewById(R.id.list);

 

 

وبالمثل، يمكن لنشاطك إستدعاء دوال في الشظيه، من خلال الحصول على مرجع للشظيه من FragmentManager،..

بإستخدام ()findFragmentById  أو ()findFragmentByTag . مثال:

KOTLIN

val fragment = supportFragmentManager.findFragmentById(R.id.example_fragment) as ExampleFragment

JAVA

ExampleFragment fragment = (ExampleFragment) getSupportFragmentManager().findFragmentById(R.id.example_fragment);

 

 

 

 

 

 

 

 

 

إنشاء إستدعاءات حدث للنشاط

في بعض الحالات، قد تحتاج إلى شظيه لمشاركة الأحداث أو البيانات مع النشاط و / أو الشظايا الأخرى التي يستضيفها النشاط.

لمشاركة البيانات، قم بإنشاء ViewModel مشترك، كما هو موضح في قسم مشاركة البيانات بين الشظايا في دليل ViewModel.

إذا كنت بحاجة إلى بث الأحداث التي لا يمكن التعامل معها بإستخدام ViewModel، فيمكنك بدلاً من ذلك تعريف واجهة إستدعاء..

بداخل الشظيه وتطلب أن يقوم نشاط المضيف بتطبيقها. عندما يتلقى النشاط إستدعاء من خلال الواجهة..

يمكنه مشاركة المعلومات مع الشظايا الأخرى في المخطط حسب الضرورة.

 

مثال، إذا كان تطبيق الأخبار يحتوي على شظيتين في نشاط ما – أحدهما تقوم بعرض قائمة بالمقالات (الشظيه أ) ..

وأخرى تقوم بعرض المقال (الشظيه ب) – فإن الشظيه أ يجب أن تخبر النشاط عندما يتم تحديد عنصر قائمة حتى يمكنه أن يخبر الشظيه ب بأن تعرض المقالة.

في هذه الحالة، يتم الإعلان عن واجهة OnArticleSelectedListener بداخل الشظيه أ:

KOTLIN

public class FragmentA : ListFragment() {
    ...
    // Container Activity must implement this interface
    interface OnArticleSelectedListener {
        fun onArticleSelected(articleUri: Uri)
    }
    ...
}

JAVA

public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

 

ثم يقوم النشاط الذي يستضيف الشظيه، بتنفيذ واجهة OnArticleSelectedListener ويتجاوز ()onArticleSelected..

لإبلاغ الشظيه ب بالحدث القادم من الشظيه أ. للتأكد من أن النشاط المستضيف يقوم بتطبيق هذه الواجهة..

دالة إستدعاء ()onAttach للشظيه أ (والتي يستدعيها النظام عند إضافة الشظيه إلى النشاط) تقوم بتمثيل مثيل OnArticleSelectedListener..

عن طريق توزيع النشاط الذي تم تمريره في ()onAttach :

KOTLIN

public class FragmentA : ListFragment() {

    var listener: OnArticleSelectedListener? = null
    ...
    override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as? OnArticleSelectedListener
        if (listener == null) {
            throw ClassCastException("$context must implement OnArticleSelectedListener")
        }

    }
    ...
}

JAVA

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener listener;
    ...
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            listener = (OnArticleSelectedListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

 

إذا لم يقم النشاط بتنفيذ الواجهة، فإن الشظيه تطرح ClassCastException. عند النجاح، يحتفظ عضو mListener بمرجع لتنفيذ النشاط..

لـ OnArticleSelectedListener، بحيث يمكن للشظيه أ مشاركة الأحداث مع النشاط عن طريق إستدعاء الدوال المحددة..

بواسطة واجهة OnArticleSelectedListener. مثال، إذا كانت الشظيه أ عبارة عن إمتداد لـ ListFragment..

ففي كل مرة يقوم المستخدم بالنقر فوق عنصر القائمة، يقوم النظام بإستدعاء ()OnListItemClick في الشظيه..

والتي بدورها تستدعي ()onArticleSelected لمشاركة الحدث مع النشاط:

KOTLIN

public class FragmentA : ListFragment() {

    var listener: OnArticleSelectedListener? = null
    ...
    override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) {
        // Append the clicked item's row ID with the content provider Uri
        val noteUri: Uri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id)
        // Send the event and Uri to the host activity
        listener?.onArticleSelected(noteUri)
    }
    ...
}

JAVA

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener listener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        listener.onArticleSelected(noteUri);
    }
    ...
}

 

معامل “باراميتر” المعرف الذي تم تمريره إلى ()onListItemClick هو معرف الصف الخاص بالعنصر الذي تم النقر عليه..

والذي يستخدمه النشاط (أو شظية أخرى) لجلب المقالة من “موفر المحتوى” ContentProvider الخاص بالتطبيق.

تتوفر المزيد من المعلومات حول إستخدام “موفر محتوى” في مستند موفري المحتوى.

 

 

 

 

 

إضافة عناصر إلى شريط التطبيق

يمكن أن تساهم الشظايا الخاصة بك بعناصر القائمة، لقائمة الخيارات الخاصة بالنشاط (وبالتالي، شريط التطبيق)..

من خلال تنفيذ ()onCreateOptionsMenu. رغم ذلك لكي تتمكن هذه الداله من تلقي الإستدعاء، يجب إستدعاء ()setHasOptionsMenu..

أثناء ()onCreate ، للإشارة إلى أن الشظيه تود إضافة عناصر إلى قائمة الخيارات. خلاف ذلك، فإن الشظيه لن تتلقى إستدعاء إلى ()onCreateOptionsMenu .

 

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

تتلقى الشظية أيضاً عمليات إستدعاء على ()onOptionsItemSelected عند تحديد عنصر قائمة.

 

يمكنك أيضاً تسجيل عرض في مخطط الشظيه، الخاص بك لتوفير قائمة سياق من خلال إستدعاء ()registerForContextMenu.

عندما يفتح المستخدم قائمة السياق، تتلقى الشظيه إستدعاء إلى ()onCreateContextMenu .

عندما يقوم المستخدم بتحديد عنصر، تتلقى الشظيه إستدعاء إلى ()ContextItemSelected .

ملاحظة: على الرغم من أن الشظية الخاصة بك تتلقى إستدعاءً محدداً على عنصر لكل عنصر قائمة تضيفه..

إلا أن النشاط هو أول من يحصل على الإستدعاء المعني عندما يحدد المستخدم عنصر القائمة. إذا كان تنفيذ النشاط الخاص..

بالإستدعاء الذي تم تحديده على العنصر لا يعالج العنصر المحدد، فسيتم تمرير الحدث إلى إستدعاء الشظيه.

وينطبق ذلك على قائمة الخيارات وقوائم السياق.

لمزيد من المعلومات حول القوائم، اقرأ دليل مطوري القوائم وفئة تدريب شريط التطبيق.

 

 

 

 

التعامل مع دورة حياة الشظية


إن إدارة دورة حياة الشظية يشبه إلى حدٍ كبير إدارة دورة حياة أي نشاط. مثل نشاط ما، شظية ما يمكن أن توجد في ثلاث حالات: 

الإستئناف

الشظية مرئيه في النشاط قيد التشغيل.

الإيقاف المؤقت

هناك نشاط آخر في المقدمة وله تركيز، ولكن النشاط الذي تقبع فيه هذه الشظيه ما زال مرئياً (يكون نشاط المقدمة شفاف جزئياً أو لا يغطي الشاشة بأكملها). 

التوقف

الشظيه غير مرئيه. سواء تم إيقاف النشاط المستضيف أو تمت إزالة الشظية من النشاط ولكن تمت إضافته إلى الكومة الخلفية.

لا تزال الشظية المتوقفة نشطه (يتم الإحتفاظ بجميع معلومات الحالات والأعضاء من قبل النظام).

ومع ذلك، لم يعد مرئياً للمستخدم ويتم قتله إذا تم قتل النشاط.

 

  الشكل 3. تأثير دورة حياة النشاط على دورة حياة الشظية.

 

أيضاً مثل النشاط، يمكنك الحفاظ على حالة واجهة المستخدم لشظية من خلال تغييرات التكوين وموت العملية..

بإستخدام مزيج من (onSaveInstanceState (Bundle و ViewModel ، والتخزين المحلي المستمر.

لمعرفة المزيد عن الحفاظ على حالة واجهة المستخدم، راجع حفظ حالات واجهة المستخدم.

الفرق الأكثر أهمية في دورة الحياة بين النشاط والشظية هو كيفية تخزينهما في الكومة الخلفية الخاصة بهما.

يتم وضع النشاط في كومة خلفية، مكونة من الأنشطة التي يديرها النظام عندما يتم إيقافها، بشكلٍ إفتراضي..

(بحيث يمكن للمستخدم الرجوع إليه مرة أخرى بإستخدام زر “الرجوع”، كما هو موضح في المهام و الكومة الخلفيه).

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

عن طريق إستدعاء ()addToBackStack أثناء إحدى المعاملات التي تزيل الشظيه.

خلاف ذلك، فإن إدارة دورة حياة الشظية تشبه إلى حدٍ كبير إدارة دورة حياة النشاط؛ تطبق نفس الممارسات.

اقرأ دليل دورة حياة النشاط و التعامل مع دورات الحياة بإستخدام مكونات مدركة لدورة الحياة – لمعرفة المزيد حول دورة حياة النشاط وممارسات لإدارتها.

 

تنبيه: إذا كنت بحاجة إلى كائن سياق بداخل الشظية الخاصة بك، يمكنك إستدعاء ()getContext.

مع ذلك، كن حذراً بإستدعاء ()getContext فقط عندما يتم إرفاق الشظية بالنشاط. عندما لا يتم إرفاق الشظية بعد..

أو تم فصلها في نهاية دورة حياتها، ستقوم ()getContext بإرجاع “فارغ”.

 

 

 

 

 

التنسيق مع دورة حياة النشاط

تؤثر دورة حياة النشاط الذي تقبع فيه الشظايا بشكلٍ مباشر على دورة حياة الشظية، بحيث ينتج عن كل إستدعاء لدورة حياة النشاط..

إستدعاء مماثل لكل شظية. مثال، عندما يتلقى النشاط دالة ()onPause ، تتلقى كل شظية في النشاط دالة ()onPause.

تحتوي الشظايا على بعض الإستدعاءات الإضافية لدورة الحياة، مع ذلك، تتعامل مع تفاعل فريد مع النشاط من أجل تنفيذ إجراءات..

مثل إنشاء و تدمير واجهة المستخدم للشظيه. دوال الإستدعاء الإضافية هذه هي:

()onAttach

تستدعى عندما تكون الشظية مرتبطة بالنشاط (يتم تمرير النشاط هنا).

()onCreateView

تستدعى لإنشاء التسلسل الهرمي لطريقة العرض المرتبطة بالشظية.

()onActivityCreated

تستدعى عندما يتم إرجاع دالة ()onCreate للنشاط.

()onDestroyView 

تستدعى عند إزالة التسلسل الهرمي لطريقة العرض المرتبطة بالشظية.

()onDetach

تستدعى عندما يتم فصل الشظية عن النشاط.

 

يوضح الشكل 3 تدفق دورة حياة الشظية، بما أنها تتأثر بنشاطها المستضيف، في هذا الشكل، يمكنك أن ترى..

كيف تحدد كل حالة متتالية من النشاط دوال الإستدعاء التي قد تتلقاها الشظية. على سبيل المثال، عندما يتلقى النشاط..

إستدعاء ()onCreate ، لا تتلقى الشظية الموجودة في النشاط أكثر من الإستدعاء ()onActivityCreated.

بمجرد وصول النشاط إلى حالة الإستئناف، يمكنك بحرية إضافة وإزالة الشظايا من النشاط. وبالتالي..

فقط عندما يكون النشاط في حالة الإستئناف، يمكن أن تتغير دورة حياة الشظية بشكلٍ مستقل.

مع ذلك، عندما يغادر النشاط حالة الإستئناف، يتم دفع الشظية مرة أخرى خلال دورة حياتها بواسطة النشاط.

 

 

 

 

 

 

أمــثــله


ولجلب كل ما تمت مناقشته في هذا المستند معاً، إليك مثال لنشاط يستخدم شظيتين لإنشاء مخطط من جزأين.

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

يوضح أيضاً كيفية توفير تكوينات مختلفة من الشظايا، بناءً على تكوين الشاشة.

 

ملاحظة: يتوفر الكود المصدر الكامل لهذا النشاط في نموذج التطبيق الذي يوضح إستخدام فئة FragmentLayout كمثال.

يطبق النشاط الرئيسي مخططاً بالطريقة المعتادة، أثناء ()onCreate:

KOTLIN

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContentView(R.layout.fragment_layout)
}

JAVA

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.fragment_layout);
}

 

 

المخطط المطبق هو fragment_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
            android:id="@+id/titles" android:layout_weight="1"
            android:layout_width="0px" android:layout_height="match_parent" />

    <FrameLayout android:id="@+id/details" android:layout_weight="1"
            android:layout_width="0px" android:layout_height="match_parent"
            android:background="?android:attr/detailsElementBackground" />

</LinearLayout>

بإستخدام هذا المخطط، يقوم النظام بتمثيل TitlesFragment (الذي يسرد عناوين المسرحية) بمجرد أن يقوم النشاط بتحميل المخطط..

بينما FrameLayout (حيث تظهر الشظية التي تعرض ملخص المسرحية) تستنفذ المساحة على الجانب الأيمن من الشاشة..

ولكن تبقى فارغة في البداية. كما سترى أدناه، لن يتم تحديد شظية من القائمة، حتى يختار المستخدم عنصر من القائمة التي توجد بها الشظية في FrameLayout.

مع ذلك، ليست جميع تكوينات الشاشة، عريضة بما يكفي لعرض كلٍ من قائمة المسرحيات والملخص، جنباً إلى جنب.

لذا، يتم إستخدام المخطط أعلاه فقط للتكوين الأفقي للشاشة، عن طريق حفظه في

res/layout-land/fragment_layout.xml.

وبالتالي، عندما تكون الشاشة في الإتجاه العمودي، يقوم النظام بتطبيق المخطط التالي، والذي يتم حفظه في res/layout/fragment_layout.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
            android:id="@+id/titles"
            android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>

يتضمن هذا المخطط “عنوان الشظية” TitlesFragment فقط. وهذا يعني أنه عندما يكون الجهاز في الإتجاه العمودي، تكون قائمة عناوين المسرحيات فقط مرئية.

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

تالياً، يمكنك معرفة كيف يتم إنجاز هذا في فئات الشظايا. الأول هو “عنوان الشظية” TitlesFragment، الذي يعرض قائمة عناوين مسرحية لشكسبير.

تمتد هذه الشظية إلى “قائمة الشظية” ListFragment وتعتمد عليها للتعامل مع معظم عمل “عرض القائمة”.

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

يمكنك إما إنشاء وعرض شظية جديدة لعرض التفاصيل في نفس النشاط (بإضافة الشظية إلى FrameLayout)، أو بدء نشاط جديد (حيث يمكن عرض الشظية)

KOTLIN

class TitlesFragment : ListFragment() {

    private var dualPane: Boolean = false
    private var curCheckPosition = 0

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        // Populate list with our static array of titles.
        listAdapter = ArrayAdapter<String>(
                activity,
                android.R.layout.simple_list_item_activated_1,
                Shakespeare.TITLES
        )

        // Check to see if we have a frame in which to embed the details
        // fragment directly in the containing UI.
        val detailsFrame: View? = activity?.findViewById(R.id.details)
        dualPane = detailsFrame?.visibility == View.VISIBLE

        curCheckPosition = savedInstanceState?.getInt("curChoice", 0) ?: 0

        if (dualPane) {
            // In dual-pane mode, the list view highlights the selected item.
            listView.choiceMode = ListView.CHOICE_MODE_SINGLE
            // Make sure our UI is in the correct state.
            showDetails(curCheckPosition)
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt("curChoice", curCheckPosition)
    }

    override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) {
        showDetails(position)
    }

    /**
     * Helper function to show the details of a selected item, either by
     * displaying a fragment in-place in the current UI, or starting a
     * whole new activity in which it is displayed.
     */
    private fun showDetails(index: Int) {
        curCheckPosition = index

        if (dualPane) {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            listView.setItemChecked(index, true)

            // Check what fragment is currently shown, replace if needed.
            var details = fragmentManager?.findFragmentById(R.id.details) as? DetailsFragment
            if (details?.shownIndex != index) {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index)

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                fragmentManager?.beginTransaction()?.apply {
                    if (index == 0) {
                        replace(R.id.details, details)
                    } else {
                        replace(R.id.a_item, details)
                    }
                    setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                    commit()
                }
            }

        } else {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            val intent = Intent().apply {
                setClass(activity, DetailsActivity::class.java)
                putExtra("index", index)
            }
            startActivity(intent)
        }
    }
}

JAVA

public static class TitlesFragment extends ListFragment {
    boolean dualPane;
    int curCheckPosition = 0;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Populate list with our static array of titles.
        setListAdapter(new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));

        // Check to see if we have a frame in which to embed the details
        // fragment directly in the containing UI.
        View detailsFrame = getActivity().findViewById(R.id.details);
        dualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;

        if (savedInstanceState != null) {
            // Restore last state for checked position.
            curCheckPosition = savedInstanceState.getInt("curChoice", 0);
        }

        if (dualPane) {
            // In dual-pane mode, the list view highlights the selected item.
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            // Make sure our UI is in the correct state.
            showDetails(curCheckPosition);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("curChoice", curCheckPosition);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        showDetails(position);
    }

    /**
     * Helper function to show the details of a selected item, either by
     * displaying a fragment in-place in the current UI, or starting a
     * whole new activity in which it is displayed.
     */
    void showDetails(int index) {
        curCheckPosition = index;

        if (dualPane) {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is currently shown, replace if needed.
            DetailsFragment details = (DetailsFragment)
                    getSupportFragmentManager().findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index) {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                if (index == 0) {
                    ft.replace(R.id.details, details);
                } else {
                    ft.replace(R.id.a_item, details);
                }
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        } else {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }
}

 

الشظية الثانية، تعرض “تفاصيل الشظية” DetailsFragment ملخص المسرحية للعنصر المختار من القائمة من “عنوان الشظية” TitlesFragment:

KOTLIN

    class DetailsFragment : Fragment() {

        val shownIndex: Int by lazy {
            arguments?.getInt("index", 0) ?: 0
        }

        override fun onCreateView(
                inflater: LayoutInflater,
                container: ViewGroup?,
                savedInstanceState: Bundle?
        ): View? {
            if (container == null) {
                // We have different layouts, and in one of them this
                // fragment's containing frame doesn't exist. The fragment
                // may still be created from its saved state, but there is
                // no reason to try to create its view hierarchy because it
                // isn't displayed. Note this isn't needed -- we could just
                // run the code below, where we would create and return the
                // view hierarchy; it would just never be used.
                return null
            }

            val text = TextView(activity).apply {
                val padding: Int = TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP,
                        4f,
                        activity?.resources?.displayMetrics
                ).toInt()
                setPadding(padding, padding, padding, padding)
                text = Shakespeare.DIALOGUE[shownIndex]
            }
            return ScrollView(activity).apply {
                addView(text)
            }
        }

        companion object {
            /**
             * Create a new instance of DetailsFragment, initialized to
             * show the text at 'index'.
             */
            fun newInstance(index: Int): DetailsFragment {
                val f = DetailsFragment()

                // Supply index input as an argument.
                val args = Bundle()
                args.putInt("index", index)
                f.arguments = args

                return f
            }
        }
    }
}

JAVA

public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist. The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // isn't displayed. Note this isn't needed -- we could just
            // run the code below, where we would create and return the
            // view hierarchy; it would just never be used.
            return null;
        }

        ScrollView scroller = new ScrollView(getActivity());
        TextView text = new TextView(getActivity());
        int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                4, getActivity().getResources().getDisplayMetrics());
        text.setPadding(padding, padding, padding, padding);
        scroller.addView(text);
        text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
        return scroller;
    }
}

 

إعادة إستدعاء من فئة “عنوان الشظية” TitlesFragment، إذا قام المستخدم بالنقر فوق عنصر قائمة..

ولم يتضمن المخطط الحالي عرض “معاينه” R.id.details (وهو المكان الذي تنتمي إليه “تفاصيل الشظية” DetailsFragment)..

فسيبدأ التطبيق نشاط “تفاصيل الشظية” DetailsActivity لعرض محتوى العنصر.

هذه هي “تفاصيل النشاط” DetailsActivity، التي تقوم ببساطة بتضمين “تفاصيل الشظية” DetailsFragment لعرض ملخص..

المسرحية المحدده عندما تكون الشاشة في الإتجاه العمودي:

KOTLIN

class DetailsActivity : FragmentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line with the list so we don't need this activity.
            finish()
            return
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            val details = DetailsFragment().apply {
                arguments = intent.extras
            }
            supportFragmentManager.beginTransaction()
                    .add(android.R.id.content, details)
                    .commit()
        }
    }
}

JAVA

public static class DetailsActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line with the list so we don't need this activity.
            finish();
            return;
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getSupportFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
        }
    }
}

 

لاحظ أن هذا النشاط ينهي نفسه إذا كان التكوين هو الإتجاه الأفقي، بحيث يمكن أن يتولى النشاط الرئيسي..

ويعرض “تفاصيل الشظية” DetailsFragment إلى جانب “عنوان الشظية” TitlesFragment. يمكن أن يحدث هذا إذا كان المستخدم..

يبدأ “تفاصيل النشاط” DetailsActivity بينما يكون في الإتجاه العمودي، ولكن بعد ذلك يتم تدويره إلى الوضع الأفقي (الذي يعيد تشغيل النشاط الحالي).

 

 

مصادر إضافية


يتم إستخدام الشظية في تطبيق Sunflower التجريبي.

 


للإطلاع على المقال باللغة الإنجليزية أضغط هنا.

الإعلانات