کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

طرح بندی چند قابه-multiple-pane layout در اندروید

 

clip_image001

دوره آموزش برنامه نویسی اندروید

کلیه حقوق مادی و معنوی این مقاله متعلق به آموزشگاه تحلیل داده می باشد و هر گونه استفاده غیر قانونی از آن پیگرد قانونی دارد.

ایجاد طرح بندی چند قابه قسمت اول 

بکاربردن Fragment  ها در برنامه های کاربردی اندروید

در این مبحث با نحوه ی استفاده از کلاس fragment برای ایجاد طرح بندی چند قابه (multiple-pane layout) در اپلیکیشن های اندروید آشنا می شوید (برای مثال برنامه هایی که بر اساس پهنای موجود صفحه نمایش، مقیاس و اندازه ی تصویر خود را تنظیم می کنند). این مقاله ی آموزشی بر پایه ی Eclipse 4.4 (Lunu)، Java 1.7 و Android 5.0. (Lollipop)  نوشته شده است.

فهرست محتوا

1. مبانی اندروید

2. Fragments

طرح بندی تک قابه (single-pane layout) و چند قابه (multiple-pane layout) چیست؟

Fragment  چیست؟

Fragments و دسترسی به Context

مزایای استفاده از fragments

آموزش نحوه ی پشتیبانی از صفحه نمایش با اندازه های متفاوت به کمک fragments

3. آموزش نحوه ی تعریف و استفاده از  fragments

نحوه ی تعریف کردن fragment

برقراری ارتباط با برنامه از طریق fragment

4. طول عمر  fragment

5. تعریف fragments برای activity مورد نظر

افزودن fragment ها به صورت ایستا  (static)به فایل layout

نحوه ی مدیریت fragment ها به صورت پویا (dynamic)

بررسی کنید آیا fragment در طرح کلی (layout) موجود است

بررسی حالت یا مُد activity (single)،  double،  multiple mode

6. افزودن fragment transition به پشته (backstack)

7. تعریف animations برای fragment transition

8. ماندگار کردن داده ها (persisting data) در fragment ها

ماندگار کردن اطلاعات بین راه اندازی مجدد برنامه های کاربردی

ماندگار کردن اطلاعات بین تغییرات پیکربندی (configuration changes)

9. استفاده از fragment برای پردازش پیش زمینه ای

Headless fragments

حفظ Headless fragment ها به منظور مدیریت تغییرات پیکربندی

 10. نکات آموزشی درباره ی fragment ها

هدف اصلی این تمرین آموزشی

ایجاد طرح های کلی (layout) متعارف و استاندارد

ایجاد کلاس های fragment

RSSfeedActivity

تست کردن نمونه

11. طرح بندی (layout) با نمای عمودی (portrait mode)

ایجاد طرح کلی با نمای عمودی

DetailActivity

تنظیم و اصلاح RSSfeedActivity

اجرا

12. تمرین : افزودن fragment ها به activity به صورت پویا (dynamic)

هدف این تمرین

استفاده از placeholder برای فایل های layout

تعیین حالت (dual-pane mode یا single-pane) با تعریف متغیر

جایگزین کردن fragment ها با استفاده از fragment manager

 

1. مبانی اندروید

برای درک بهتر این مبحث لازم است پیش زمینه ای از برنامه نویسی و طراحی تحت اندروید داشته باشید. در دروس پیشین کلیه ی مقدمات و پیش نیازهای آموزشی تشریح شد.

2. Fragments

طرح بندی تک قابه (single-pane layout) و چند قابه (multiple-pane layout) چیست؟

دستگاه های اندروید با چگالی تصویر و اندازه  صفحه نمایش های گوناگون عرضه می شوند.

Panel یا همان pane بخشی از رابط کاربری را تشکیل می دهد. کلمه ی pane، واژه ای عمومی است که به مفهوم چندین view گنجانده شده در view ای مرکب (واحد) اشاره دارد. view مرکب بر اساس مقدار فضای موجود تنظیم می شود.

 در صورت نبود فضای کافی، تنها یک panel نمایش داده می شود. به این نوع طرح بندی، single-pane layout (طرح بندی تک قابی( می گویند.

 چنانچه فضای کافی وجود داشته باشد، چندین panel نمایش داده می شود.

Fragment چیست؟

Fragment عبارتند از کامپوننت یا مولفه ای مستقل که توسط هر activity ای می تواند مورد استفاده قرار بگیرد. fragment قابلیت (functionality) های لازم را در خود کپسوله سازی کرده و به همین دلیل استفاده ی مجدد از آن در activity و layout سهل می باشد.

Fragment در متن (context) activity قرار دارد، با این وجود طول عمر (life-cycle) و رابط کاربری مجزا و مختص به خود را دارد. این امکان نیز وجود دارد که fragment را بدون رابط کاربری تعریف کرد (نمونه ی آن headless fragment است).

 Fragments  و دسترسی به Context

Fragment ها زیرکلاس Context نمی باشد. به همین دلیل باید از متد  getActivity ()برای دستیابی به activity والد استفاده کرد.

مزایای استفاده از fragments

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

به این خاطر که می توان fragment ها را به صورت پویا (dynamic) به activity افزود یا از آن حذف کرد، قابلیت ایجاد رابط کاربری بسیار انعطاف پذیر بوجود می آید.

معمول ترین نمونه آن، فهرستی از آیتم های activity است که روی تبلت در تنها یک صفحه قابل نمایش می باشد (برای مثال، می توانید روی آیتم مورد نظر در سمت راست صفحه کلیک کنید)، ولی در یک گوشی اندروید مجبورید به detail screen دیگری  برای مشاهده ی تمام جزئیات مراجعه کنید.

 مبحث زیر فرض می گیرد شما دو fragment دارید (یکی اصلی / main و دیگری detail / جانبی(. همچنین دو activity که یکی main و دیگری detailed خوانده می شود برای این بخش استفاده می کنیم. توجه داشته باشید که در تبلت activity اصلی شامل هر دو fragment در طرح کلی خود می باشد، در حالی که گوشی هوشمند (handset) تنها fragment اصلی (main) را در activity اصلی دربر خواهد داشت.

 آموزش نحوه ی پشتیبانی از صفحه نمایش با اندازه های متفاوت به کمک  fragments

می توان fragment های activity را در فایل layout تعریف کرد (که به آن تعریف ایستا / static definition گفته می شود) یا آن ها را در زمان اجرا (runtime) معرفی کرد (که به آن تعریف پویا / dynamic definition گفته می شود).

به منظور نمایش fragment های متفاوت بر اساس فضای موجود در activity های مورد نظر

از activity ای استفاده کنید که در تبلت یا گوشی، تنها دو fragment نمایش می دهد. در این مورد، در صورت نیاز باید fragment مربوطه را در زمان اجرا اصلاح کرد. در این مثال شما نمونه هایی از کلاس  FrameLayoutرا به عنوان placeholder در طرح کلی خود تعریف کرده، سپس fragment ها را در زمان اجرا به آن ها اضافه می کنید.

در گوشی های هوشمند (handset) از activity های مجزا برای هر fragment (به عنوان میزبان( استفاده کنید. به عنوان مثال اگر به تبلت توجه کرده باشید، رابط کاربری (UI) آن از دو fragment در یک activity استفاده می کند، برای گوشی نیز از همین activity استفاده کنید ولی طرح کلی جایگزینی برای آن درنظر بگیرید که تنها یک fragment را در خود جای می دهد. چنانچه detailed fragment از قبل آنجا حضور دارد، main activity به fragment مذکور دستور بروز رسانی خود را می دهد، اما اگر detail fragment در دسترس نباشد، activity اصلی detailed activity را راه اندازی می کند.

لازم به ذکر است که تعریف پویا انعطاف پذیرتر بوده، در عین حال پیاده سازی آن کمی دشوارتر می باشد.

3. آموزش نحوه ی تعریف و استفاده از fragments

نحوه ی تعریف کردن  fragment

برای تعریف fragment جدید، کافی است کلاس  android.app.Fragment یا یکی از زیرکلاس های آن را گسترش و توسعه دهید (به طور مثال، زیر کلاس های ListFragment، DialogFragment، PreferenceFragment یا WebViewFragment (.

مثال

package com.example.android.rssfeed;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class DetailFragment extends Fragment {
  @Override
 
public View onCreateView(LayoutInflater inflater، ViewGroup container،
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_rssitem_detail،
        container، false);
    return view;
  }
  public void setText(String item) {
    TextView view = (TextView) getView().findViewById(R.id.detailsText);
    view.setText(item);
  }
}

 برقراری ارتباط با برنامه از طریق  fragment

برای افزایش قابلیت استفاده ی دوباره از fragment ها، آن ها نباید مستقیم با هم ارتباط داشته باشند، بلکه هرگونه برقراری ارتباط بین fragment ها لازم است از طریق activity میزبان (host activity) صورت گیرد.

برای این منظور، fragment باید رابط کاربری به عنوان نوع داخلی (inner type) تعریف کند و  activityای که از fragment مزبور استفاده می کند باید سرانجام این رابط کاربری را بکار بگیرد. از این طریق مانع از هرگونه آگاهی fragment از activity میزبان (activity ای که fragment نام برده را بکار می برد) می شوید. fragment با بررسی متد onAttach() چک می کند آیا activity رابط مورد نظر را به درستی پیاده سازی کرده یا خیر.

به عنوان مثال، فرض کنید fragment ای دارید که باید مقداری را به activity والد خود مخابره کند مانند مثال زیر

 package com.example.android.rssfeed;
import android.app.Activity;

import android.app.Fragment;

import android.os.Bundle;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.Button;

public class MyListFragment extends Fragment {

 
private OnItemSelectedListener listener;
  @Override
 
public View onCreateView(LayoutInflater inflater، ViewGroup container،
      Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_rsslist_overview،

        container،
false);
    Button button = (Button) view.findViewById(R.id.button1);

    button.setOnClickListener(
new View.OnClickListener() {
      @Override
     
public void onClick(View v) {
        updateDetail();

      }

    });

   
return view;
  }

 
public interface OnItemSelectedListener {
   
public void onRssItemSelected(String link);
  }

  @Override
 
public void onAttach(Activity activity) {
   
super.onAttach(activity);
   
if (activity instanceof OnItemSelectedListener) {
      listener = (OnItemSelectedListener) activity;

    }
else {
     
throw new ClassCastException(activity.toString()
          +
" must implemenet MyListFragment.OnItemSelectedListener");
    }

  }


  @Override
 
public void onDetach() {
   
super.onDetach();
    listener =
null;
  }

 
// may also be triggered from the Activity
 
public void updateDetail() {
   
// create a string just for testing
   
String newTime = String.valueOf(System.currentTimeMillis());
   
// inform the Activity about the change based
   
// interface defintion
    listener.onRssItemSelected(newTime);

  }

}

 4. طول عمر fragment (life-cycle)

طول عمر یک fragment به طول عمر activity میزبان مرتبط است.

اگرچه fragment چرخه ی دوام خود را دارد، اما از این لحاظ به طول عمر activity والد نیز وابسته است.

چرخه حیات Fragment

در صورت متوقف شدن activity، fragment های آن هم متوقف می شوند. به همین روش در صورت نابود شدن activity، fragment های آن نیز نابود می شوند.

جدول 1. Fragment life-cycle

متد  

توصیف و شرح عملکرد  

onAttach() 

 نمونه ی fragment ونمونه ی activity را به هم متصل می کند. البته fragment و activity کاملاً مقداردهی اولیه نمی شوند، بلکه معمولاً یک ارجاع / reference به activity داخل این متد قرار داده می شود که ازfragment مزبور برای ادامه و تکمیل فرایند مقداردهی اولیه /initialization  استفاده می کند.

onCreate() 

fragment لازمه را ایجاد می کند. متد onCreate() پس از متد onCreate()  اکتیویتی و پیش از متد onCreateView() فرگمنت فراخوانی می شود.

onCreateView() 

 نمونه ی fragment سلسله مراتب view / view hierarchy خود را بوجود می آورد. fragment رابط کاربری مورد نیاز خود را در متد onCreateView() ایجاد می کند. اینجا می توانید با فراخوانی متد  inflate () از شی inflator که به عنوان پارامتر به این متد ارسال شده، طرح کلی را ظاهر (inflate) کنید. در این متد شما نمی توانید با activity تعامل داشته و ارتباط برقرار کنید زیرا که activity مربوطه هنوز کامل تعیین وضعیت و مقداردهی اولیه نشده است. البته نیازی به پیاده سازی این متد برای headless fragment نیست. view های ظاهر شده (inflated views) بخشی از سلسه مراتب view و در نهایت activity میزبان می شود.

onActivityCreated()

 onActivityCreated() پس از متد onCreateView() و زمانی که activity میزبان به وجود می آید، فراخوانده می شود. Activity، نمونه ی fragment و همچنین سلسه مراتب activity همگی در این زمان بوجود آمده اند. حال می توان با استفاده از متد findViewById() به view دسترسی پیدا کرد. در این متد جهت نمونه سازی اشیا به Context object نیاز دارید.

onStart()

این متد بلافاصله پس از ظاهر شدن fragment فراخوانی می شود.

onResume()

Fragment به وسیله ی این متد فعال می شود.

onPause()

در این برهه، fragment مورد نظر قابل رویت می باشد ولی دیگر فعال نیست.

onStop()

با استفاده از این متدfragment  متوقف شده و دیگر قابل رویت نمی باشد.

onDestroyView()

   به وسیله ی این متد view (مربوط به) fragment مورد نظر نابود می گردد. در صورت بازسازی fragment مذکور از طریق backstack، ابتدا این متد فراخوانی می شود سپس متد onCreateView صدا زده می شود.

onDestroy()

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

 

5. تعریف fragments برای activity مورد نظر

افزودن fragment ها به صورت ایستا (static) به فایل layout

می توانید برای استفاده از fragment جدید، آن را به صورت ایستا به XML layout خود اضافه کنید. در مثال زیر خصیصه ی android : name به کلاس مربوط اشاره دارد، همان طور که در تکه کد زیر مشاهده می کنید.

<?xml version="1.0" encoding="utf-8" ?>

‎‎<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"

               android:layout_width="fill_parent"

               android:layout_height="fill_parent"

               android:baselinealigned="false"

               android:orientation="horizontal">

        <fragment android:id="@+id/listFragment"

                    android:layout_width="0dp"

                    android:layout_weight="1"

                    android:layout_height="match_parent"

                    class="com.example.android.rssfeed.MyListFragment">

        </fragment>

            <fragment android:id="@+id/detailFragment"

                        android:layout_width="0dp"

                        android:layout_weight="2"

                        android:layout_height="match_parent"

                        class="com.example.android.rssfeed.DetailFragment">

                            </fragment>

 </linearlayout>

 چنانچه برای پیکربندی های متفاوت دستگاه (نحوه ی دیگر پیکربندی دستگاه)، فایل های static layout مجزا و متفاوتی دارید، می توانید از این سناریو نهایت استفاده را ببرید.

 

نحوه ی مدیریت fragment ها به صورت پویا (dynamic)

می توان با استفاده از متد getFragmentManager ()، به کلاس fragmentmanager در activity دسترسی پیدا کرد. کلاس مزبور این امکان را در اختیار شما قرار می دهد که fragment های مورد نظر را از شَمای کلی (layout) فعالیت (activity) خود حذف کرده یا به آن fragment جدید اضافه کنید و یا حتی آن ها را با fragment های دیگر جایگزین کنید.

این اصلاحات باید در قالب یک تراکنش (transaction) و توسط کلاس  FragmentTranscationصورت گیرد.

به منظور اصلاح fragment های بیان شده، لازم است یک FrameLayout placeholder در فایل layout خود تعریف کنید.

<?xml version="1.0" encoding="utf-8" ?>

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"

               android:layout_width="match_parent"

               android:layout_height="match_parent"

               android:orientation="horizontal">

            <framelayout android:id="@+id/listcontainer"

                       android:layout_width="match_parent"

                       android:layout_height="match_parent" />

        <framelayout android:id="@+id/detailscontainer"

                       android:layout_width="match_parent"

                       android:layout_height="match_parent"

                       android:visibility="gone" />

</linearlayout>

 همچنین برای جایگزین کردن fragment (درونcontainer) از  FragmentManager استفاده کنید.

   // get fragment manager
    
FragmentManager fm = getFragmentManager();
         
// add
    
FragmentTransaction ft = fm.beginTransaction();
     ft.add(R.id.your_placehodler
،
new YourFragment());
    
// alternatively add it with a tag
    
// trx.add(R.id.your_placehodler، new YourFragment()، "detail");
    
ft.commit();
         
// replace
    
FragmentTransaction ft = fm.beginTransaction();
     ft.
replace(R.id.your_placehodler، new YourFragment());
     ft.commit();

         
// remove
    
Fragment fragment = fm.findFragmentById(R.id.your_placehodler);
     FragmentTransaction ft = fm.beginTransaction();

     ft.remove(fragment);

     ft.commit();

 همان طور که مستحضر هستید، fragment ای جدید جایگزین fragment جاری (منظور فرگمنت موجود در container است) می شود.

اگر می خواهید تراکنش (transaction) مربوط را به backstack اندروید اضافه کنید، باید از متد  addtoBackStack () برای این منظور کمک بگیرید. این کار عمل یا کنش (action) مورد نظر را به تاریخچه ی پشته ی history stack activity اضافه می کند (به طور مثال، به شما اجازه می دهد اصلاحات وارد آمده به Fragment را با استفاده از دکمه ی برگشت (back button) به حالت قبلی بازگردانید).

1394/07/27 8143 3702
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...