Android 碎片F(xiàn)ragment簡(jiǎn)單總結(jié)

時(shí)間:2016年5月24日16:44:21

作者:JustDo23

說明:在開發(fā)中經(jīng)常會(huì)遇到使用Fragment的情況。由于功能等的需要會(huì)對(duì)Fragment有一點(diǎn)點(diǎn)深入的理解?,F(xiàn)在簡(jiǎn)單總結(jié)記錄一下。

01. ViewPager + Fragment

在使用ViewPager嵌套Fragment的時(shí)候可能需要有以下的操作

  • Activity 需要繼承子 FragmentActivity

  • 需要在xml布局中添加ViewPager的控件并指定ID,具體代碼如下:

      <!-- 為了兼容需要使用v4包下面的控件 -->
      <android.support.v4.view.ViewPager
          android:id="@+id/vp_reserve"
          android:layout_width="fill_parent"
          android:layout_height="match_parent"/>
    
  • 需要一個(gè)ViewPager的適配器,可以繼承自FragmentPagerAdapter,同時(shí)需要重寫一些方法。各個(gè)方法有各自不同的作用。

      import android.support.v4.app.Fragment;
      import android.support.v4.app.FragmentManager;
      import android.support.v4.app.FragmentPagerAdapter;
    
      import java.util.List;
    
      /**
       * 訂單管理的ViewPagerIndicator適配器
       *
       * @author JustDo23
       */
      public class ReserveManageAdapter extends FragmentPagerAdapter {
    
          private List<Fragment> fragList;// 數(shù)據(jù)集合
          private String[] TITLES;// 標(biāo)題
    
          public ReserveManageAdapter(FragmentManager fm, List<Fragment> fragList, String[] TITLES) {
              super(fm);
              this.fragList = fragList;
              this.TITLES = TITLES;
          }
    
          @Override
          public int getCount() {
              return fragList.size();
          }
    
          @Override
          public Fragment getItem(int arg0) {
              return fragList.get(arg0);
          }
    
          @Override
          public int getItemPosition(Object object) {
              return super.getItemPosition(object);
          }
    
          @Override
          public CharSequence getPageTitle(int position) {
              return TITLES[position % TITLES.length];
          }
      }
    
  • 之后就可以在Activity中findViewById找到相應(yīng)的ViewPager控件對(duì)象。

  • 進(jìn)行List<Fragment>中各個(gè)Item的初始化。Fragment對(duì)象的new。

  • 如果使用的Fragment對(duì)象是相同類型的,F(xiàn)ragment需要使用參數(shù)的時(shí)候,需要在new之后用Bundle對(duì)象去傳遞參數(shù)。可以使用代碼:

      Fragment needVisit = new FragReserveList();
      needVisit.setArguments(getBundle(0));// [ 0,待處理 ]
      fragList.add(needVisit);
    
      Fragment finished = new FragReserveList();
      finished.setArguments(getBundle(1));// [ 1,已處理 ]
      fragList.add(finished);
    
  • 以上需要傳遞參數(shù)的代碼如下

      private Bundle getBundle(int type) {
          Bundle bundle = new Bundle();
          bundle.putInt("type", type);
          return bundle;
      }
    
  • 在Fragment的onCreateView方法中進(jìn)行參數(shù)的獲取

      Bundle bundle = this.getArguments();
      if (bundle != null) {
          type = bundle.getInt("type", -1);
      }
    
  • List<Fragment>初始化之后,進(jìn)行適配器Adapter的新建與設(shè)置。

      vp_reserve.setAdapter(new ReserveManageAdapter(getSupportFragmentManager(), fragList, TITLES));
    
  • 利用setCurrentItem(int position)方法可以設(shè)置ViewPager當(dāng)前顯示的位置。一般情況下是不用進(jìn)行設(shè)置的,這個(gè)位置是0的位置。

      vp_reserve.setCurrentItem(showPosition);
    
  • 至此就基本完成了ViewPager嵌套Fragment的實(shí)現(xiàn)步驟了。

02. setUserVisibleHint(boolean isVisibleToUser)方法

一般情況下,在ViewPager嵌套Fragment使用的時(shí)候,ViewPager會(huì)在初始化的時(shí)候一次性初始化2個(gè)Fragment,這兩個(gè)都會(huì)走onCreateView并進(jìn)入到resume狀態(tài)。但是用戶是只能看到第一個(gè)Fragment,第二Fragment雖然沒有顯示卻同樣進(jìn)入到了resume狀態(tài)。此時(shí)再用舊的想法當(dāng)Fragment對(duì)用戶可見的時(shí)候在onResume()方法中處理某些事情,如網(wǎng)絡(luò)請(qǐng)求等這種想法就不太科學(xué)了。

在這種情況下Fragment中有個(gè)setUserVisibleHint(boolean isVisibleToUser)的方法就派上用場(chǎng)了。這個(gè)方法是專門設(shè)置Fragment顯示和不顯示的。

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    if (isFirst && isVisibleToUser && TextUtils.isEmpty(nextUrl)) {
        getDataFromServer(ConstantURLs.RESERVE_LIST, true, true);
    }
    super.setUserVisibleHint(isVisibleToUser);
}

ViewPager會(huì)在初始化及切換Fragment的時(shí)候調(diào)用這個(gè)方法來設(shè)置Fragment的顯示與否。ViewPager會(huì)在設(shè)置Adapter之后立即調(diào)用第一個(gè)、第二個(gè)fragment的setUserVisibleHint(boolean isVisibleToUser)方法設(shè)置為false,然后會(huì)對(duì)第一個(gè)fragment再次調(diào)用setUserVisibleHint(boolean isVisibleToUser)方法設(shè)置為true。

需要注意的是setUserVisibleHint(boolean isVisibleToUser)方法會(huì)在ViewPager嵌套Fragment這種情況下調(diào)用。別的情況可能不會(huì)調(diào)用。

03. RadioButton + FrameLayout + Fragment

這一種機(jī)制和ViewPager嵌套Fragment是兩種完全不同的機(jī)制。使用RadioButton這種機(jī)制更類似于很早以前的TabHost的使用。因?yàn)橹暗?code>TabHost使用非常復(fù)雜而且不好用,所以很多人提出了使用RadioButton + FrameLayout + Fragment這種比較流行的解決方法。

對(duì)于這種有一個(gè)參考的demo,仿微信導(dǎo)航欄https://github.com/JayFang1993/android-demos

  • 使用這種方法Activity 同樣需要繼承子 FragmentActivity

  • 在xml中需要使用控件RadioGroupFrameLayout并指定id

      <?xml version="1.0" encoding="utf-8"?>
      <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                      android:id="@+id/ll_root"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:background="@android:color/white">
    
          <RadioGroup
              android:id="@+id/rg_nav"
              android:layout_width="match_parent"
              android:layout_height="55dip"
              android:layout_alignParentBottom="true"
              android:orientation="horizontal">
    
              <RadioButton
                  android:id="@+id/rb_message"
                  style="@style/MainNavigation"
                  android:checked="true"
                  android:drawableTop="@drawable/nav_selector_message"
                  android:text="@string/message"/>
    
              <RadioButton
                  android:id="@+id/rb_patient_manage"
                  style="@style/MainNavigation"
                  android:drawableTop="@drawable/nav_selector_patient_manage"
                  android:text="@string/patient_manage"/>
    
              <RadioButton
                  android:id="@+id/rb_me"
                  style="@style/MainNavigation"
                  android:drawableTop="@drawable/nav_selector_me"
                  android:text="@string/me"/>
          </RadioGroup>
    
          <!-- 小紅點(diǎn)實(shí)現(xiàn),完全可以刪除 -->    
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="55dip"
              android:layout_alignParentBottom="true"
              android:orientation="horizontal">
    
              <RelativeLayout style="@style/MainNavigation"/>
    
              <RelativeLayout style="@style/MainNavigation"/>
    
              <RelativeLayout
                  style="@style/MainNavigation"
                  android:gravity="right|top">
    
                  <View
                      android:id="@+id/message_view"
                      android:layout_width="10dp"
                      android:layout_height="10dp"
                      android:layout_marginRight="40dp"
                      android:background="@drawable/shape_red_round"
                      android:visibility="gone"/>
              </RelativeLayout>
          </LinearLayout>
    
          <FrameLayout
              android:id="@+id/frag_container"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_above="@+id/v_divider"
              android:layout_alignParentTop="true">
          </FrameLayout>
    
      </RelativeLayout>
    
  • Activity 中通過findViewById方法來獲取 RadioGroup對(duì)象的引用

  • 設(shè)置 RadioGroup的切換監(jiān)聽

      rg_nav.setOnCheckedChangeListener(this);
    
  • 監(jiān)聽方法的實(shí)現(xiàn)

      @Override
      public void onCheckedChanged(RadioGroup group, int checkedId) {
          switch (checkedId) {
              case R.id.rb_message:
                  setTabSelected(0);
                  break;
              case R.id.rb_patient_manage:
                  setTabSelected(1);
                  break;
              case R.id.rb_me:
                  setTabSelected(2);
                  break;
              default:
                  break;
          }
      }
    
  • 兩個(gè)重點(diǎn)方法

      private void setTabSelected(int i) {
          FragmentManager fm = getSupportFragmentManager();
          FragmentTransaction transaction = fm.beginTransaction();
          hideTab(transaction);
          switch (i) {
              case 0:
                  fragMessage = fm.findFragmentByTag("message");
                  if (fragMessage == null) {
                      fragMessage = new FragMessage();
                      transaction.add(R.id.frag_container, fragMessage, "message");
                  } else {
                      transaction.show(fragMessage);
                  }
                  break;
              case 1:
                  fragPatientManage = fm.findFragmentByTag("patientmanage");
                  if (fragPatientManage == null) {
                      fragPatientManage = new FragPatientManage();
                      transaction.add(R.id.frag_container, fragPatientManage, "patientmanage");
                  } else {
                      transaction.show(fragPatientManage);
                  }
                  break;
              case 2:
                  fragMe = fm.findFragmentByTag("me");
                  if (fragMe == null) {
                      fragMe = new FragMe();
                      transaction.add(R.id.frag_container, fragMe, "me");
                  } else {
                      transaction.show(fragMe);
                  }
                  break;
              default:
                  break;
          }
          transaction.commitAllowingStateLoss();
      }
    
      private void hideTab(FragmentTransaction transaction) {
          if (fragMessage != null) {
              transaction.hide(fragMessage);
          }
          if (fragPatientManage != null) {
              transaction.hide(fragPatientManage);
          }
          if (fragMe != null) {
              transaction.hide(fragMe);
          }
      }
    

04. onHiddenChanged(boolean hidden)方法

這個(gè)方法和setUserVisibleHint(boolean isVisibleToUser)有些類似。但這個(gè)方法一看名稱就是很明顯是顯示和隱藏的方法。在上邊RadioButton + FrameLayout + Fragment模式中的Fragment中可以使用onHiddenChanged(boolean hidden)方法進(jìn)行判斷,而且setUserVisibleHint(boolean isVisibleToUser)方法是不會(huì)執(zhí)行的。

05. add() show() hide() 以及 replace()

對(duì)于上邊提到的RadioButton + FrameLayout + Fragment模式中使用的主要是第一種add() show() hide()方式進(jìn)行Fragment的顯示和隱藏。對(duì)于Fragment界面的切換還可以使用replace()的方法進(jìn)行。

對(duì)于這兩種方法有各自的特點(diǎn),暫時(shí)沒有總結(jié)到。

  • 使用replace()方法,每次會(huì)把Fragment的生命周期都走一邊。

06. Fragment中的Context為空現(xiàn)象

在Fragment中使用context最常用的就是使用getActivity()方法進(jìn)行獲取上下文對(duì)象。但是有時(shí)候總是會(huì)出現(xiàn)getActivity()方法獲取的對(duì)象為空的情況。這里忘記了當(dāng)時(shí)使用的切換方式,應(yīng)該是使用replace()方式的時(shí)候經(jīng)常出現(xiàn)空的現(xiàn)象。

網(wǎng)上搜索后有提到Activity會(huì)被系統(tǒng)回收重建,但是Fragment不會(huì),所以出現(xiàn)Fragment丟失Activity的情況。多數(shù)的解決方法是在onSaveInstanceState方法中進(jìn)行處理。

本人的解決方法是在BaseFragment中定義mContext并在其onCreateView方法中進(jìn)行獲取。簡(jiǎn)單代碼如下:

protected Context mContext;

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    if (rootView == null) {
        rootView = inflater.inflate(getContentView(), null);
        mContext = getActivity();
        initView();
    }

    ViewGroup parent = (ViewGroup) rootView.getParent();
    if (parent != null) {
        parent.removeView(rootView);
    }

    return rootView;
}

另外提供一個(gè)搜索關(guān)鍵詞fragment getactivity() 為空

最后

以上基本都是本人在工作過程中遇到的東西。工作比較忙碌以及本人寫記錄的習(xí)慣不強(qiáng)等原因。本人能力問題等,本片文檔寫的比較淺,并不很深。還是需要不斷的學(xué)習(xí)努力,不斷的提高。

最后附上一個(gè)剛看的連接,主要使用友盟相關(guān)http://www.itdecent.cn/p/850556d33f63

不斷完善,繼續(xù)努力!

補(bǔ)丁

時(shí)間:2016年9月12日15:11:48

作者:JustDo23

簡(jiǎn)述:樣式設(shè)置相關(guān)的代碼做一個(gè)補(bǔ)充。

01. RadioButton使用的style

<!-- 導(dǎo)航按鈕 -->
<style name="MainNavigation">
    <item name="android:layout_width">0dip</item>
    <item name="android:layout_height">match_parent</item>
    <item name="android:layout_weight">1</item>
    <item name="android:button">@null</item>
    <item name="android:background">@null</item>
    <!-- 消除不同版本上的位置錯(cuò)亂問題 -->
    <item name="android:drawablePadding">0dip</item>
    <item name="android:gravity">center</item>
    <item name="android:scaleX">0.8</item>
    <item name="android:scaleY">0.8</item>
    <item name="android:paddingTop">3dip</item>
    <item name="android:textSize">15sp</item>
    <item name="android:textColor">@drawable/selector_text_color_main</item>
</style>

02. 圖片使用的selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/ic_nav_me_on" android:state_checked="true" android:state_window_focused="false"/>
    <item android:drawable="@mipmap/ic_nav_me_off" android:state_checked="false" android:state_window_focused="false"/>
    <item android:drawable="@mipmap/ic_nav_me_off" android:state_checked="false"/>
    <item android:drawable="@mipmap/ic_nav_me_on" android:state_checked="true"/>

</selector>

03. 小紅點(diǎn)

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval"
       android:useLevel="false">

    <!--小紅點(diǎn)-->
    <gradient
        android:endColor="#F74A28"
        android:startColor="#F74A28"/>

</shape>

04. 飄紅帶數(shù)字

<!-- [融云]飄紅 -->
<style name="Little_Red_Dot">
    <item name="android:background">@drawable/rc_unread_count_bg</item>
    <item name="android:gravity">center</item>
    <item name="android:textColor">@android:color/white</item>
    <item name="android:textSize">9sp</item>
    <item name="android:layout_centerVertical">true</item>
    <item name="android:layout_alignParentRight">true</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
</style>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,036評(píng)論 25 709
  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,873評(píng)論 2 45
  • 好奇好奇心強(qiáng)的2歲寶寶,常常覺得自己是個(gè)小大人,凡事都想自己解決,由于經(jīng)驗(yàn)不足,不僅常常把事情搞砸了,也給身邊的人...
    寶樂匯閱讀 493評(píng)論 0 1
  • 千里山野紅粉妝, 萬叢丹殷嬌羞藏。 翩翩隱隱蝶雙舞, 花思青春人思郎。
    w小郭閱讀 286評(píng)論 0 1
  • 前一晚便定好,我等他踢完球,喝茶吃飯。 選定在達(dá)德喝茶,倒是個(gè)鬧中取靜的好地方,雪芽的茶具兩人都喜歡。 突然問到我...
    王炯炯閱讀 553評(píng)論 0 0

友情鏈接更多精彩內(nèi)容