時(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中需要使用控件
RadioGroup和FrameLayout并指定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>