فرگمنت ها (Fragment) در اندروید

فرگمنت (Fragment) چیست

Fragment (فرگمنت) را می توان به عنوان یک زیر مجموعه و یا یک بخش از اکتیویتی (sub-activity) در نظر گرفت که در نهایت قسمتی از رابط کاربری را تشکیل داده و به واسطه آن یک رابط کاربری چند قسمتی ایجاد می شود. فرگمنت در اندروید مشابه آنچه قبلا برای اکتیویتی ها آموختیم، چرخه حیات و رفتار خاص خود را دارد، رویدادهای ورودی را دریافت می کند و از دو قسمت xml (لایه واسط کاربری) و کد عملیاتی (java) تشکیل شده است. هر اکتیویتی می تواند چندین فرگمنت را در خود جای دهد و هر فرگمنت می تواند در چندین اکتیویتی استفاده شود. بنابراین فرگمنت به تنهایی قابلیت اجرا ندارد و به اکتیویتی والد و چرخه حیات آن وابسته است. فرگمنت از API 11 (اندروید Honeycomb) اضافه شد.

چرخه حیات فرگمنت (Fragment Lifecycle)

فرگمنت هم مانند اکتیویتی چرخه حیات خاص خود را دارد که تا حد زیادی مشابه چرخه حیات اکتیویتی است. خوب است ابتدا مروری بر این چرخه حیات داشته باشیم.

چرخه حیات فرگمنت

()onAttach : این متد هنگامی که فرگمنت به اکتیویتی اضافه شده خوانده می شود.
()onCreate : این متد برای مقداردهی در هنگام ساخت فرگمنت فراخوانی می شود.
()onCreateView : این متد زمانی فراخوانده می شود که فرگمنت ایجاد شده و آماده ساخت واسط کاربری (UI) است. در اکتیویتی این وظیفه بر عهده onCreate() بود.
()onActivityCreated : این متد در زمانی فراخوانده می شود که اکتیویتی میزبان فرگمنت اجرا شده است.
()onStart : این متد زمانی فراخوانده می شود که رابط کاربری فرگمنت آماده نمایش است.
()onResume : در این زمان فرگمنت فعال است.
()onPause و ()onStop : این متد در زمان پایان فعالیت فرگمنت اجرا می شود و اگر لازم است چیزی ذخیره شود در این مرحله باید انجام داد.
()onDestroyView : این متد زمانی فراخوانده می شود که UI فرگمنت از اکتیویتی حذف می شود.
()onDestroy : در زمان انتهای حیات فرگمنت این متد اجرا می شود.
()onDetach : زمانی فراخوانده می شود که فرگمنت به طور کامل از اکتیویتی میزبان خود جدا شده است.
از مفاهیم فاصله گرفته و با ذکر مثالهایی، آموزش را ادامه می دهم.

پروژه شماره یک (فرگمنت های استاتیک)

شاید ساده ترین مثال، همان اپلیکیشن کتاب باشد که اگر قبلا در مورد فرگمنت در وب جستجو کرده باشید به احتمال زیاد با آن برخورد کرده اید.

Fragment example for news application

تصویر بالا یک تلفن هوشمند و یک تبلت را نشان می دهد. قصد دارم یک کتابچه اندرویدی توسعه بدهم. حالت ساده و ابتدایی این است که چینش اجزاء رابط کاربری در همه اندازه ها و حالت های مختلف صفحه نمایش، یکسان باشد. اما از نظر UX (تجربه کاربری) این امر پسندیده نبوده و باید حالتهای متفاوتی را برای اندازه های مختلف صفحه نمایش در نظر بگیریم تا تمامی کاربران تجربه خوبی هنگام تعامل با برنامه ما داشته باشند.

نکته : تجربه کاربری (UX) مفهومی است که در کنار مفهوم رابط کاربری (UI) مدتیست مورد توجه توسعه دهندگان وب و اپلیکیشن قرار گرفته. به طور خلاصه نحوه چینش عناصر، رنگهای بکار رفته و هرآنچه که باعث می شود تا کاربر ارتباط بهتری با محصول ما برقرار کند، در استفاده از بخش های مختلف آن دچار سردرگمی نشده و در نهایت تعامل رضایت بخشی را تجربه کرده باشد، همگی در حوزه تجربه کاربری قرار می گیرد. توصیه می کنم چند دقیقه ای وقت گذاشته و در این خصوص جستجو و مطالعه کنید.

اپلیکیشن کتاب ما شامل یک لیست موضوعی است که کاربر با انتخاب هریک از گزینه های موجود در لیست، به متن مربوط به آن هدایت می شود. در صفحات عمودی (Portrait) و همچنین صفحات کوچک، حالت مطلوب این است که در صفحه اصلی فقط لیست موضوعات نمایش داده شود و کاربر با انتخاب هر گزینه، برای مطالعه متن به صفحه جدید منتقل شود که به صورت کامل متن را نمایش داده و خبری از لیست موضوعات نیست. اما این حالت برای تبلت و در حالت افقی (Landscape) شاید منطقی به نظر نرسد و پذیرفتنی نیست که یک صفحه عریض بخواهد فقط چند کلمه را در هر سطر نمایش دهد. اینجا گزینه مطلوب این است که لیست و متن، هر دو را در کنار هم برای کاربر نمایش دهیم. هر موضوعی که کاربر انتخاب کرد، متن آن در کنار لیست نشان داده شود.
برای تحقق این هدف، از فرگمنت استفاده می کنیم. با بکارگیری فرگمنت، نیازی به تعریف چندباره لیست و قسمت مربوط به نمایش متن در اکتیویتی های مختلف نداریم و تنها کافیست یکبار آنها را در دو فرگمنت مجزا ایجاد کرده و سپس به تعداد لازم و در اکتیویتی های مختلف، فرگمنتها را فراخوانی کنیم.
یک پروژه با نام FragmentOne و API 16 می سازم. در زمان تهیه این آموزش بر اساس آمار گوگل حدود ۹۶ درصد دیوایس های اندرویدی فعال، شامل نسخه ۱۶ و بالاتر اندروید می شوند و من ترجیح میدهم پروژه خود را روی این ورژن پیاده سازی کنم.
در این مثال من وارد جزئیات از جمله لیست و متن موضوعات نمی شوم و به آشنایی با نحوه پیاده سازی فرگمنت ها بسنده می کنم.
فرگمنت ها به دو صورت ایستا (Static) و پویا (Dynamic) به اکتیویتی اضافه می شوند که در این پروژه من فرگمنتها را به صورت ایستا استفاده می کنم.
روی فولدر app پروژه راست کلیک کرده و در مسیر New > Fragment یک فرگمنت خالی (Blank) انتخاب می کنم:

اضافه کردن فرگمنت به پروژه اندروید

در مرحله بعد نام فرگمنت را تعیین می کنم. من برای این فرگمنت نام frg1 را انتخاب کردم:

تعیین نام فرگمنت

با انتخاب گزینه Create layout XML ، لایه رابط کاربری این فرگمنت به صورت خودکار ساخته شده و نیاز به ساخت دستی آن نیست. اندروید استودیو نام Layout را بر اساس نام فرگمنت تعیین می کند که نیازی به تغییر آن نمی بینم. در پایان دو گزینه به صورت پیش فرض انتخاب شده که من فعلا به متدهای اضافی نیازی ندارم و تیک هر دو را برمیدارم. با زدن گزینه Finish، فرگمنت ایجاد می شود.

کد frg1.java:

package ir.android_studio.fragmentone;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class frg1 extends Fragment {

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

}

(برای خلوت شدن محیط کار من متد سازنده را به صورت دستی حذف کردم)

کد fragment_frg1.mxl:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.android_studio.fragmentone.frg1">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

به ایمپورت های فرگمنت دقت کنید. دو کلاس android.support.v4.app.Fragment و android.view.LayoutInflater در لیست قرار دارند. قبلا گفتیم فرگمنت در API 11 به اندروید اضافه شده و برای استفاده از آن در نسخه های پایینتر لازم است به جای کلاس android.app.Fragment ، از کلاس android.support.v4.app.Fragment استفاده کنیم تا به واسطه کتابخانه Support امکان استفاده از آن میسر شود. البته در حال حاضر توسعه اپلیکیشن برای نسخه های ۱۱ به پایین توجیهی ندارد. من هم هنگام ساخت پروژه MinSDK را برابر ۱۶ قرار دادم. با این حال اندروید استودیو به صورت پیش فرض این کلاس را اضافه کرده که تفاوتی نمی کند و نیازی به تغییر نیست. در ادامه ملاحظه می کنید کلاس frg1 از Fragment ارث بری کرده است.
برای اتصال لایه xml به فرگمنت و نمایش آن، لازم است متد onCreateView را Override کنیم (مشابه اکتیویتی با این تفاوت که در آنجا متد onCreate استفاده می شد). در نهایت با شئ ای که از LayoutInflater ساخته شده لایه R.layout.fragment_frg1 به فرگمنت متصل شده است.
UI این فرگمنت شامل یک FrameLayout (از FrameLayout برای چهارچوب بندی در اندروید استفاده می شود) است که تنها یک TextView داخل آن قرار گرفته. برای این پروژه هم فعلا به چیز بیشتری نیاز ندارم. فقط برای تشخیص دو فرگمنت از یکدیگر، برای هرکدام متن و رنگ پس زمینه متمایز تعریف می کنم. مشابه قبل یک فرگمنت جدید با نام frg2 ایجاد کرده و Layout ها را مطابق زیر تغییر می دهم:

fragment_frg1.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.android_studio.fragmentone.frg1"
    android:background="#bf2e2e">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Fragment A"
        android:gravity="center"/>

</FrameLayout>

fragment_frg2.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.android_studio.fragmentone.frg2"
    android:background="#1e6ea7">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Fragment B" 
        android:gravity="center"/>

</FrameLayout>

هدف ما این بود تا در صفحات عادی و پیش فرض (که آنها را به عنوان استثنائات به صورت جداگانه تعریف نکردیم) فقط یک فرگمنت و در صفحات با سایز صفحه نمایش بزرگ (تبلت) و در حالت افقی، هر دو فرگمنت در کنار هم نمایش داده شوند. به سراغ activity_main.xml می روم. با استفاده از به صورت ایستا فرگمنت را به اکتیویتی اضافه می کنم.

فرگمنت ایستا | Static Fragment

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.android_studio.fragmentone.MainActivity">
    
    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

فرگمنت به اکتیویتی اضافه شد. عرض و ارتفاع را match_parent تنظیم کردم تا فرگمنت تمام اکتیویتی را به خود اختصاص دهد. (دقت کنید ممکن است اختصاص دهم که با استفاده از خاصیت android:name امکانپذیر است:

خاصیت name فرگمنت

مقدار این خاصیت را برابر نام کلاسی قرار می دهم که می خواهم نمایش داده شود. اندروید استودیو لیست فرگمنت ها را نمایش داده و نیازی به وارد کردن دستی نیست. با این حال اگر لازم شد نام را خودتان وارد کنید، ترکیب PackageName.FragmentClass است. به هر فرگمنت می بایست یک id نیز اختصاص داد که fr1 را انتخاب می کنم:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.android_studio.fragmentone.MainActivity">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fr1"
        android:name="ir.android_studio.fragmentone.frg1" />

</RelativeLayout>

اگر Layout را در حالت Design قرار دهید ارور زیر را مشاهده خواهید کرد:

ارور نمایش فرگمنت در محیط توسعه

مضمون پیغام این است که اگر مایلم در حالت Preview و در محیط توسعه هم فرگمنت انتخاب شده نمایش داده شود، با کلیک روی Use @layout/fragment_frg1 خاصیت مربوط به آن به اضافه می شود که به دلخواه توسعه دهنده است و استفاده یا عدم استفاده از آن تاثیری در عملکرد اپلیکیشن برای کاربر ندارد و صرفا محدود به محیط اندروید استودیو است. با تایید این پیغام، خط زیر به فرگمنت اضافه می شود:

tools:layout="@layout/fragment_frg1"

حالا در محیط توسعه هم فرگمنت نمایش داده می شود:

خاصیت tools فرگمنت

اضافه کردن به اکتیویتی را به صورت Drag & Drop هم می‌شود انجام داد:

اضافه کردن فرگمنت به اکتیویتی به شیوه Drag & Drop

پس از کشیدن بر روی صفحه، پنجره ای باز می شود که فرگمنت مدنظر را انتخاب کرده و سپس در قسمت Properties سایر تنظیمات از جمله اختصاص id، ارتفاع و … را انجام می دهیم.
چون در این آموزش صرفا نحوه اضافه کردن فرگمنتها را بررسی می کنیم، از انتقال به Fragment B صرف نظر می کنم و به سراغ مرحله دوم می روم، یعنی ساخت رابط کاربری مناسب تبلت ها در حالت افقی. در اندروید سایز صفحه نمایش در ۴ دسته Small، Normal، Large و X-Large قرار می گیرد. قصد ندارم در این آموزش به مبحث سایز بندی بپردازم و صرفا جهت آشنایی با فرگمنت ها به صورت اجمالی ساخت Layout جدید را توضیح می دهم. صفحه نمایش تبلت در رده سایز Large قرار می گیرد. از طرفی قصد دارم لایه جدید بر روی صفحه ای که در حالت افقی (Landscape) قرار گرفته اعمال شود. بنابراین در کنار پوشه layout پروژه، یک پوشه جدید با نام layout-large-land می سازم و یک کپی از activity_main.xml اصلی داخل آن قرار می دهم.

اضافه کردن پوشه جدید به پروژه اندرویدی

برای ساخت پوشه جدید، روی res راست کلیک کرده و Android resource directory را انتخاب می کنم. حالا با انتخاب layout به عنوان Resource type و تکمیل نام دایرکتوری، پوشه جدید را می سازم:

اضافه کردن لایه سایز Large و Landscape به پروژه

علاوه بر نوشتن دستی نام فولدر، با انتخاب گزینه های Size و Orientation و انتقال آنها به قسمت Chosen qualifiers و در نهایت انتخاب گزینه مدنظر، نام دایرکتوری به صورت خودکار تکمیل می شود (ضمن اینکه در خارج از محیط اندروید استودیو و در محل ذخیره پروژه هم به راحتی می توان دایرکتوری موردنیاز را به پروژه اضافه کرد).
حالا یک کپی از activity_main.xml ساخته و به دایرکتوری layout-large-land منتقل می کنم. هنگامی که ساختار نمایش پروژه روی Android تنظیم شده، دایرکتوری که جدید ساختیم نمایش داده نمی شود و لازم است حالت نمایش پروژه را موقتا از Android به Project تغییر داده و فایل کپی شده را روی دایرکتوری مدنظر Paste کنیم (و یا باز هم در محل ذخیره پروژه در سیستم عامل خود، عمل کپی فایل به دایرکتوری را انجام دهیم).

لیست دایرکتوری ها

البته روش ساده تری هم هست. وقتی من activity_main.xml را کپی کرده و یک دایرکتوری خالی هم وجود دارد، اندروید استودیو هدف من را تشخیص می دهد و کافیست در همان حالت نمایش Android، روی layout راست کلیک و Paste کنیم. پنجره ای باز می شود که مسیر انتقال را layout-large-land معرفی می کند که با تایید آن، انتقال به درستی انجام می شود:

اضافه کردن activity_main.xml به دایرکتوری layout-large-land

اضافه کردن activity_main.xml به دایرکتوری layout-large-land

اضافه کردن activity_main.xml به دایرکتوری layout-large-land

نکته : الزامی به کپی کردن layout قبلی و انتقال به دایرکتوری جدید نیست و در واقع این عمل همان ساخت layout جدید است. در مواردی که لایه ما کامپوننت های متعددی داشته و قصد اعمال تغییرات جزئی داشته باشیم، احتمالا کپی راه حل ساده تری است اما در مواردی مثل پروژه فعلی که یک اکتیویتی ساده داریم و علاوه بر آن، لایه پیش فرض را از جنس RelativeLayout ساخته بودیم که لازم است در حالت Large Landscape لایه را از نوع LinearLayout بسازیم، ساخت یک لایه جدید و همنام با لایه پیش فرض منطقی خواهد بود:

Layout > New > Resource File

اگر می خواهید لایه جدید را به این شیوه بسازید و قبلا آنرا توسط کپی از لایه پیش فرض ساخته اید، کافیست آنرا حذف کرده و مجدد از این طریق اقدام کنید.

لایه جدید ایجاد شد و در قسمت Preview به صورت افقی نمایش داده شده است:

لایه افقی Landscape

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</LinearLayout>

حالا دو activity_main.xml داریم که دومی مقابل آن large-land قید شده. هنگامی که برنامه روی دیوایسی با سایز صفحه نمایش Large اجرا شود و دیوایس در حالت افقی قرار گرفته باشد، به جای activity_main.xml پیش فرض، activity_main.xml موجود در دایرکتوری layout-large-land برای کاربر رندر می شود. پس در این لایه دو را به صورت افقی در کنار یکدیگر قرار می دهم:

<?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="ir.android_studio.fragmentone.frg1"
        android:id="@+id/fr1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

    <fragment
        android:name="ir.android_studio.fragmentone.frg2"
        android:id="@+id/fr2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2" />

</LinearLayout>

خاصیت orientation را به horizontal تغییر دادم تا دو فرگمنت به صورت افقی در کنار هم قرار بگیرند. با وزن دهی (layout_weight) قبلا در فصل پنجم آشنا شدیم.
حالا پروژه آماده ی اجراست. من یک دیوایس Tablet روی جنی موشن ساخته ام و پروژه را روی آن اجرا می کنم. دیوایس در ابتدا روی حالت عمودی قرار دارد:

اجرای پروژه اندروید روی دیوایس با صفحه نمایش عمودی

همانطور که انتظار داشتم فقط یک فرگمنت نمایش داده می شود (Fragment A). در مرحله بعد با کلیک روی گزینه تنظیمات دیوایس (سه نقطه) و یا Ctrl + F11 دیوایس در حالت افقی قرار می گیرد:

چرخش صفحه نمایش دیوایس به Landscape

صفحه نمایش افقی Landscape

با چرخش دیوایس، Layout موجود در دایرکتوری large-land به درستی جایگزین layout اصلی پروژه شد.

پروژه شماره دو (فرگمنت های داینامیک)

در مثال قبل با فرگمنت های استاتیک آشنا شدیم. تفاوت فرگمنت پویا با استاتیک در این است که در فرگمنت پویا در زمان اجرا می توان یک فرگمنت را جایگزین فرگمنت قبلی کرد. یعنی می توان در یک اکتیویتی چند محتوای متفاوت را بنا به نیازی که کاربر دارد نمایش داد بدون اینکه لازم باشد از یک اکتیویتی به اکتیویتی دیگر منتقل شود. یا به عنوان مثال به جای اینکه به وسیله Intent کاربر به برنامه پیش فرض دوربین دیوایس منتقل شده، عکس گرفته و مجدد به برنامه برگردد و روی تصویر ویرایش انجام دهد، تمامی مراحل درون برنامه انجام شود (مشابه نرم افزارهای بارکدخوان و…).
در این مثال قصد دارم فرگمنت های پویا را با یک مثال ساده معرفی کنم.
از پروژه قبل خارج شده (File > Close Project) و یک پروژه جدید با نام FragmentTwo می سازم. پروژه من شامل یک اکتیویتی و دو فرگمنت است. درون اکتیویتی دو Button و یک FrameLayout وجود دارد که با لمس هریک از دکمه ها، یکی از دو فرگمنت در FrameLayout نمایش داده شده و جایگزین فرگمنت قبل می شود.
ابتدا دو فرگمنت با نامهای FrgOne و FrgTwo عینا مشابه پروژه قبل اضافه می کنم. در مرحله بعد لایه activity_main.xml را همانگونه که در پاراگراف بالا عنوان شد می سازم. اکتیویتی را به نوع LinearLayout و چینش عمودی تغییر داده و به هریک از عناصر یک id اختصاص داده ام.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="ir.android_studio.fragmenttwo.MainActivity">
    
    <Button
        android:id="@+id/btn_a"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Select Fragment A" />

    <Button
        android:id="@+id/btn_b"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Select Fragment B" />

    <FrameLayout
        android:id="@+id/frg_holder"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </FrameLayout>
    
</LinearLayout>

رابط کاربری اکتیویتی activity_main.xml

سپس Button ها را داخل اکتیویتی تعریف کرده و دو متد مربوط به دکمه ها را نیز اضافه می کنم:

package ir.android_studio.fragmenttwo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button btnOne, btnTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnOne = (Button) findViewById(R.id.btn_a);
        btnTwo = (Button) findViewById(R.id.btn_b);

        btnOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });

        btnTwo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

    }
}

نکته : برای اینکه فرگمنت اجرا شود، باید اکتیویتی والد آن حتما از FragmentActivity یا AppCompatActivity ارث بری شده باشد.

ابتدا متد یکی از دکمه ها را کامل کرده و سپس به توضیح جزئیات می پردازم.

btnOne.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {

        FrgOne frg1 = new FrgOne();
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.frg_holder, frg1);
        ft.commit();

    }
});

در خط اول ابتدا یک نمونه از فرگمنت FrgOne با نام frg1 ساختم. در قدم بعد برای مدیریت فرگمنت ها به نمونه ای از کلاس FragmentManager نیاز دارم:

کلاس FragmentManager

دو گزینه در اختیار داریم که اولی مربوط به کتابخانه Support می شود. همین را انتخاب می کنم. برای گرفتن آن دو گزینه getSupportFragmentManager() یا getFragmentManager() قرار می گیرد که مسلما باید getSupportFragmentManager() را انتخاب کنم. برای تبادل پیامهای فرگمنت در اکتیویتی (add، remove و replace) باید از FragmentTransaction استفاده کنیم که نام ft را درنظر گرفتم و در مقابل با متد beginTransaction() فرگمنت آماده جایگزینی می شود. در خط بعد، از متد replace استفاده کرده ام که دو ورودی می گیرد. اولی، id مربوط به FrameLayout که قرار است فرگمنت در آن جایگذاری شود و دوم، نام فرگمنت موردنظر. در نهایت لازم است با دستور commit() انجام این پروسه را آغاز کنیم.
برای دکمه دوم هم به همینصورت کد را تکمیل می کنم با این تفاوت که فرگمنت دوم باید جایگزین شود.

کد نهاییی MainActivity.java:

package ir.android_studio.fragmenttwo;

import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button btnOne, btnTwo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnOne = (Button) findViewById(R.id.btn_a);
        btnTwo = (Button) findViewById(R.id.btn_b);

        btnOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                FrgOne frg1 = new FrgOne();
                FragmentManager fm = getSupportFragmentManager();
                FragmentTransaction ft = fm.beginTransaction();
                ft.replace(R.id.frg_holder, frg1);
                ft.commit();

            }
        });

        btnTwo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                FrgTwo frg2 = new FrgTwo();
                FragmentManager fm = getSupportFragmentManager();
                FragmentTransaction ft = fm.beginTransaction();
                ft.replace(R.id.frg_holder, frg2);
                ft.commit();

            }
        });

    }
}

پروژه را اجرا می کنم:

اجرای پروژه اندرویدی

در ابتدا ناحیه مربوط به FrameLayout خالی است به این معنی که هیچ فرگمنتی در آن جایگذاری نشده. انتظار دارم با کلیک روی دکمه ها، فرگمنت های مرتبط نمایش داده شوند:

نمایش فرگمنت اول

نمایش فرگمنت دوم

برنامه به درستی کار می کند.

دانلود فایل آموزشی با فرمت PDF به همراه سورس پروژه ها
تعداد صفحات : ۳۰
حجم : ۱٫۶ مگابایت
قیمت : رایگان

برچسب ها :
سوالاتی که مشمول موارد زیر باشد تایید و پاسخ داده نخواهد شد :
۱ : جزء موارد پاسخ داده شده در مطلب "مشکلات و پرسش های رایج" باشد
۲ : سوال قبلا توسط افراد در دیدگاهها مطرح و پاسخ داده شده باشد
۳ : سوال خارج از مبحث آموزشی موجود در این صفحه باشد
  • سیامک گفت:

    سلام
    من وقتی پروژه میسازم فایل gradle ساخته میشه
    ولی وقتی فایل source شما رو اجرا میکنم build نمیشه
    باید چکار کنم؟

    1. سید مهدی مطهری (مدیر) گفت:

      خب ببینید چه اروری میگیرید.

  • عادل گفت:

    سلام من یه viewPagerTabActivity ساختم و داخل یکی از فرگمنت هاش recyclerView گذاشتم و با کلیک روی هر یک از ایتم ها میخوام یه اکتیویتی نمایش داده شود
    حالا چطور ارتباط بین اینا رو درست کنم؟

  • salari گفت:

    سلام
    خیلی ممنون از اموزش های خوبتون
    یک سوال داشتم متوجه هستم که در یک اکتوتی میشه چند فرگمنت همزمان داشت که کارها جدا انجام بدن و از یک فرگمنت میتوان چند جا استفاده کرد. با این توصیف سوال من این خیلی ممنون میشم اگه وقت بگذارید و پاسخ بدین:
    ۱- جز اکتوتی اصلی برنامه، کاری هست که فقط اکتوتی بتونه انجام بده ولی فرگمنت نتونه؟ یعنی مجبور به تعریف اکتوتی باشیم نه فرگمنت؟
    ۲- اگر یک صفحه بشه به صورت یکسان هم در اکتوتی هم در فرگمنت پیاده سازی کرد از نظر بارکاری و هزینه اولویت با کدوم؟
    ۳- ایا بهتره تا حد ممکن از فرگمنت استفاده کرد یا اکتوتی؟
    ممنون

    1. سید مهدی مطهری (مدیر) گفت:

      به طور کل بهتره جایی که میشه فرگمنت استفاده کرد، از اضافه کردن اکتیویتی پرهیز کنیم. مطالب زیادی در این خصوص در وب هست. لطفا مطالعه بفرمایید:
      https://goo.gl/GKuUBR

  • فردین گفت:

    سپاس از زحمات شما
    توضیحاتتون عالیه

  • سید علی فخری گفت:

    سلام
    میخواستم یک تشکر صمیمانه داشته باشم از همه عزیزانی که برای این سایت زحمت میکشن.
    سایتتون خیلی خیلی خیلی خیلی خیلی خیلی فوق العاده است. جدی میگم. بهترین سایت آموزشی فارسی که تابحال دیدم.
    من خودم برنامه نویس اندروید هستم و از آموزش های شما هم خیلی استفاده کردم.
    با آرزوی شادی، سلامتی، ثروت و سعادت در دنیا و آخرت

  • علیرضا طهرانی گفت:

    ممنون از آموزش عالیتون. فقط مشکلی که من دارم اینه که در فرگمنت پویا، من در xml فرگمنتم یک textview دارم اما setText آن که داخل onCreateView نوشتم کار نمیکنه. یعنی خطایی نمیده ولی متن textView هم تغییری نمیکنه. این کد رو در onCreateView نوشتم:
    LayoutInflater lf = getActivity().getLayoutInflater();
    View rootView =lf.inflate(R.layout.fragment_category,container,false);

    TextView txtTest=(TextView)rootView.findViewById(R.id.txtTest) ;
    txtTest.setText(“salam. worked!”);

  • مهدی گفت:

    سلام خسته نباشید میخواستم بپرسم که چجوری باید از if استفاده کرد وقتی میخوام چک کنم ببینم توی کدوم case از فرگمنت هستم ؟

  • ahmadreza گفت:

    سلام
    روز به خیر
    خسته نباشید و ممنون
    ببخشید من یه تازه کار هستم
    میخواستم در هر فرگمنت یه تعداد کلید و تکست باکس تعریف کنم و با اونا کار کنم
    در ساخت ظاهر فرگمنت اونجور که مد نظرم هست با استفاده از راهنمایی سایت شما موفق شدم اما نمیدونم کجا و چطور و با چه دستوراتی در جاوای مربوط به فرگمنا مقادیر تکست باکس ها رو بخونم و با کلید روی اونا اعمال مورد نظرمو انجام بدم
    اصلا آیا این امکان پذیر هست که برای فرگمنت ویجت تعریف کرد و روی اونا عملیات خاصی رو انجام داد ؟؟

    1. سید مهدی مطهری (مدیر) گفت:

      فرگمنت تفاوتی با یه اکتیویتی نداره و هرچیزی که مدنظرتون هست رو میتونید پیاده کنید. همونطور که داخل یه اکتیویتی ویجت تعریف میشه و تو کلاس جاواش عملیات رو تعریف کرد

      1. احمدرضا گفت:

        ممنون از پاسختون
        الان من میخوام تو فرگمنتم یه ادیت تکست و یه باتن تعریف کنم که یک مقدار رو بعنوان سانتیمتر بگیره و با فشار باتن اونو به اینچ تبدیل کنه
        در فرگمنت دوم هم یه ادیت تکست و یه باتن تعریف کنم و میخوام سانتیگراد رو به فارنهایت تبدیل کنه
        اما نمیدونم کد جاوای فرگمنت ها رو کجا بنویسم و چطور این کار رو بکنم
        خواهش میکنم اگه وقتتون اجازه میده کمک کنید
        ممنون
        ببخشید اگه سوالام مبتدیه خیلی

        1. سید مهدی مطهری (مدیر) گفت:

          ببینید فرگمنت هم مثل اکتیویتی از یه لایه و فایل جاوا تشکیل شده که داخل آموزش واضح توضیح دادم. ینی fragment_frg1.xml و frg1.java مربوط به فرگمنت اول هستند.

          1. AHMADREZA گفت:

            علیرغم اینکه مشکلم حل نشد ولی از اینکه با صبوری پاسخ دادین متشکر و قدردان هستم
            ممنونم از اینکه حوصله به خرج دادین و پاسخ حقیر رو دادین

  • علیرضا طهرانی گفت:

    میتونید یک منبع خوب و کامل در مورد UI اندروید معرفی کنید؟
    ممنون از آموزش های خوبتون

    1. سید مهدی مطهری (مدیر) گفت:

      منبع خاصی مدنظرم نیست. سرچ کنید

  • علی بذرافشان گفت:

    سلام. خیلی مفید، کاربردی، کامل و عالی بود. تشکر از زحمات شما.

  • علی گفت:

    لطفا آموزش در خصوص ارتباط اندورید با وب سرویس Asp.net هم بزارید

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

کد امنیتی *