19、Fragment
一、Fragment
1.1、fragment介紹
fragment的出現(xiàn)是為了同時(shí)適應(yīng)手機(jī)和平板,可以將其看做Activity的組成部分,甚至Activity界面完全由不同的Fragment組成,它擁有自己的生命
周期和接收、處理用戶的事件,更為重要的是,可以動(dòng)態(tài)的添加、替換和移除某個(gè)Fragment。
1.2、fragment版本
由于Fragment是在 3.0 后才有的,要使用 Fragment SDK 版本需要 大于 11; 由于Fragment的廣泛使用,google 后期在V4包中提供了Fragment的支持.
在實(shí)際開(kāi)發(fā)過(guò)程中,V4 包中Fragment 得到廣泛使用。
1.3、fragment兼容
由于Fragment是在 3.0 后才有的,要使用 Fragment SDK 版本需要 大于 11; 由于Fragment的廣泛使用,google 后期在V4包中提供了 Fragment的支持.
在實(shí)際開(kāi)發(fā)過(guò)程中,V4 包中Fragment 得到廣泛使用
a)新建Class繼承android.app.Fragment(sdk>11)或android.support.v4.app.Fragment(通用,建議使用)
b)重寫fragment中的onCreateView()方法。
public class MyFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater,@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {/**Inflate the layout for this fragment*/return inflater.inflate(R.layout.left_fragment, container,false);} }注意:inflater.inflate(R.layout.your_fragment_layout, container, false);中的參數(shù)必須為false
1.4、fragment生命周期
Fragment必須是依存于Activity而存在的,因此Activity的生命周期會(huì)直接影響到Fragment的生命周期。官網(wǎng)這張圖很好的說(shuō)明了兩者生命周期的關(guān)系:
可以看到Fragment比Activity多了幾個(gè)額外的生命周期回調(diào)方法:
注意:除了onCreateView,其他的所有方法如果你重寫了,必須調(diào)用父類對(duì)于該方法的實(shí)現(xiàn)。
生命周期
①Activity加載Fragment的時(shí)候,依次調(diào)用方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume
②當(dāng)Fragment所在的Activity可見(jiàn),但不獲得焦點(diǎn):onPause
③當(dāng)對(duì)話框關(guān)閉,Activity又獲得焦點(diǎn): onResume
④當(dāng)我們替換Fragment,并調(diào)用addToBackStack()將他添加到Back棧中 onPause -> onStop -> onDestoryView?
注意,此時(shí)的Fragment還沒(méi)有被銷毀哦!!!
⑤當(dāng)我們按下鍵盤的回退鍵,Fragment會(huì)再次顯示出來(lái): onCreateView -> onActivityCreated -> onStart -> onResume
⑥如果我們替換后,在事務(wù)commit之前沒(méi)有調(diào)用addToBackStack()方法將 Fragment添加到back棧中的話;又或者退出了Activity的話,那么Fragment將會(huì)被完全結(jié)束,
? Fragment會(huì)進(jìn)入銷毀狀態(tài) onPause -> onStop -> onDestoryView -> onDestory -> onDetach
1.5、靜態(tài)加載
a) 創(chuàng)建Activity繼承于FragmentActivity
b) 創(chuàng)建Fragment,分別為L(zhǎng)eftFragment以及RightFragment,2.3.3版本需要導(dǎo)入的是v4包中的fragment
public class LeftFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater,@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {/** Inflate the layout for this fragment */return inflater.inflate(R.layout.left_fragment, container, false);} }c) 創(chuàng)建fragment的布局,比較簡(jiǎn)單這里直接省略
d) 在activity的布局中使用fragment
<fragmentandroid:id="@+id/left_fragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"class="cn.legend.fragment.LeftFragment" /> <fragmentandroid:id="@+id/right_fragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="2"class="cn.legend.fragment.RightFragment" />配置過(guò)程中,Activity的布局文件內(nèi)必須指定fragment的class或android:name為對(duì)應(yīng)的Fragment的全包名類名。(通用性和靈活性不強(qiáng))
1.6、動(dòng)態(tài)加載
可以非常靈活的對(duì)Activity的視圖進(jìn)行增加和移除等操作,開(kāi)發(fā)中推薦使用動(dòng)態(tài)加載。
1.fragment實(shí)例
FragmentManager是Activity的中用來(lái)添加和移除Fragment的工具,因此FragmentManager是在Activity中使用的,也是在Activity中獲得的。
a) SDK > 11
FragmentManager fm = getFragmentManager();b) 通用V4包(Activity必須繼承FragmentActivity)
FragmentManager fm = getSupportFragmentManager();2.fragment添加
a)為Activity新建布局文件,采用FrameLayout當(dāng)做容器,這樣方便于兩個(gè)fragment切換,并給其創(chuàng)建唯一ID。
b)在Activity的onCreate()方法中加載fragment,注意3.0版本Activity繼承Activity,3.0以下需要繼承FragmentActivity。
Fragment leftFragment = new LeftFragment(); Fragment rightFragment = new RightFragment(); FragmentManager fm = getSupportFragmentManager(); FragmentTransaction transaction = fm.beginTransaction(); transaction.add(R.id.activity_add_container,leftFragment,"fragment_left"); transaction.hide(R.id.activity_add_container,rightFragment,"fragment_right"); transaction.show(leftFragment); transaction.commit();3.fragment替換
FragmentManager fm = getSupportFragmentManager(); FragmentTransaction transaction = fm.beginTransaction(); transaction.replace(R.id.activity_add_container,new LeftFragment(),"fragment_left"); transaction.commit();4.fragment移除
FragmentManager fm = getSupportFragmentManager(); FragmentTransaction transaction = fm.beginTransaction(); transaction.replace(R.id.activity_add_container,new LeftFragment(),"fragment_left"); transaction.commit();4.fragment移除
transaction.remove(Fragment);5.子fragment管理器
如果存在fragment嵌套fragment的情況,我們想獲取fragment的管理器則需要調(diào)用以下方式:
FragmentManager childFragmentManager = getChildFragmentManager();1.7、Fragment的onTouchEvent
fragment默認(rèn)是沒(méi)有提供onTouchEvent事件的,如果我們想在fragment中做手勢(shì)識(shí)別則需要用到宿主Activity來(lái)相應(yīng)事件,具體操作如下:
a)在Activity中創(chuàng)建內(nèi)部接口,并對(duì)外提供注冊(cè)touch事件的方法,由于可能存在多個(gè)fragment需要相應(yīng)touch事件,所以將touch事件放入ArrayList中
/**實(shí)現(xiàn)監(jiān)聽(tīng)觸摸事的接口,讓fragment去實(shí)現(xiàn)*/ private ArrayList<MyOnTouchListener> onTouchListeners = new ArrayList<MyOnTouchListener>(10); @Override public boolean dispatchTouchEvent(MotionEvent ev) {for (MyOnTouchListener listener : onTouchListeners) {listener.onTouch(ev);}return super.dispatchTouchEvent(ev); } public void registerMyOnTouchListener(MyOnTouchListener myOnTouchListener) {onTouchListeners.add(myOnTouchListener); } public void unregisterMyOnTouchListener(MyOnTouchListener myOnTouchListener) {onTouchListeners.remove(myOnTouchListener); } public interface MyOnTouchListener {public boolean onTouch(MotionEvent ev); }b) 讓需要響應(yīng)touch事件的fragment來(lái)實(shí)現(xiàn)上方的activity中所提供的內(nèi)部接口即可。
mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {//手指在屏幕上滑動(dòng)//e1,e2:手指的事件:手指第一次觸摸屏幕觸發(fā)->手指離開(kāi)屏幕觸發(fā)//vX vY:水平和垂直方向的速度 @Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2,float velocityX, float velocityY) {//過(guò)濾掉Y的移動(dòng)if(Math.abs(e1.getRawY()-e2.getRawY())>150){Toast.makeText(mActivity,"手勢(shì)無(wú)效", Toast.LENGTH_SHORT).show();return false;}if(e1.getRawX()-e2.getRawX()>30){//從右向左滑,顯示下一個(gè)界面 showState();return true;}else if (e2.getRawX()-e1.getRawX()>30) {//從左向右滑,顯示上一個(gè)界面 showOrder();return true;}return super.onFling(e1, e2, velocityX, velocityY);} }); mMyTouchListener = new NewFrameActivity.MyOnTouchListener() {@Overridepublic boolean onTouch(MotionEvent ev) {return mGestureDetector.onTouchEvent(ev);} }; mParentActivity = (NewFrameActivity)getActivity(); mParentActivity.registerMyOnTouchListener(mMyTouchListener);上述所使用到的動(dòng)畫效果,在下方會(huì)繼續(xù)進(jìn)行講解。
1.8、fragment切換動(dòng)畫
Fragment的轉(zhuǎn)場(chǎng)動(dòng)畫實(shí)現(xiàn)分為使用v4包和不使用v4包兩種情況,不使用v4包的話,最低API Level需要是11。
1.標(biāo)準(zhǔn)過(guò)渡動(dòng)畫
可以給Fragment指定標(biāo)準(zhǔn)的轉(zhuǎn)場(chǎng)動(dòng)畫,通過(guò)setTransition(int transit)方法。
該方法可傳入的三個(gè)參數(shù)是:
TRANSIT_NONE,
TRANSIT_FRAGMENT_OPEN,
TRANSIT_FRAGMENT_CLOSE
分別對(duì)應(yīng)無(wú)動(dòng)畫、打開(kāi)形式的動(dòng)畫和關(guān)閉形式的動(dòng)畫。標(biāo)準(zhǔn)動(dòng)畫設(shè)置好后,在Fragment添加和移除的時(shí)候都會(huì)有。
2.自定義過(guò)渡動(dòng)畫
a)自定義轉(zhuǎn)場(chǎng)動(dòng)畫是通過(guò)setCustomAnimations()方法,因?yàn)镕ragment添加時(shí)可以指定加入到Back Stack中,所以轉(zhuǎn)場(chǎng)動(dòng)畫有添加、移除、從Back stack中pop出來(lái),
還有進(jìn)入四種情況。注意:setCustomAnimations()方法必須在add、remove、replace調(diào)用之前被設(shè)置,否則不起作用。
? b)不使用v4包的情況下(min API >=11)所對(duì)應(yīng)的動(dòng)畫類型是Property Animation。即動(dòng)畫資源文件需要放在res\animator\目錄下,且根標(biāo)簽是<set>, <objectAnimator>,
or <valueAnimator>三者之一。這一點(diǎn)也可以從Fragment中的這個(gè)方法看出:onCreateAnimator(int transit, boolean enter, int nextAnim),返回值是Animator。
? c)自定義轉(zhuǎn)場(chǎng)動(dòng)畫時(shí),四個(gè)參數(shù)的形式setCustomAnimations (int enter, int exit, int popEnter, int popExit)是API Level 13才有的,11只引入了兩個(gè)動(dòng)畫的形式,
即無(wú)法指定Back Stack棧操作時(shí)的轉(zhuǎn)場(chǎng)動(dòng)畫
private void addFragment() {if (mFragmentManager == null) {mFragmentManager = getFragmentManager();}mTextFragmentOne = new MyFragmentOne();FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();/**標(biāo)準(zhǔn)動(dòng)畫*/// fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);// fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);// fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);/**自定義動(dòng)畫*/// API LEVEL 11 fragmentTransaction.setCustomAnimations(R.animator.fragment_slide_left_enter,R.animator.fragment_slide_right_exit);// API LEVEL 13// fragmentTransaction.setCustomAnimations(R.animator.fragment_slide_left_enter,R.animator.fragment_slide_left_exit,// R.animator.fragment_slide_right_enter,R.animator.fragment_slide_right_exit); fragmentTransaction.add(R.id.container, mTextFragmentOne);// 加入到BackStack中fragmentTransaction.addToBackStack(null);fragmentTransaction.commit(); }其中下面四個(gè)動(dòng)畫是從apiDemos中提取的,3.0之后的動(dòng)畫的根標(biāo)簽是set,而3.0之前的動(dòng)畫是不一樣的。
fragment_slide_left_enter:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="100dp" android:valueTo="0dp"android:valueType="floatType"android:propertyName="translationX"android:duration="@android:integer/config_mediumAnimTime" /><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="0.0" android:valueTo="1.0"android:valueType="floatType"android:propertyName="alpha"android:duration="@android:integer/config_mediumAnimTime" /> </set>fragment_slide_left_exit:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="0dp" android:valueTo="-100dp"android:valueType="floatType"android:propertyName="translationX"android:duration="@android:integer/config_mediumAnimTime" /><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="1.0" android:valueTo="0.0"android:valueType="floatType"android:propertyName="alpha"android:duration="@android:integer/config_mediumAnimTime" /> </set>fragment_slide_right_enter:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="-100dp" android:valueTo="0dp"android:valueType="floatType"android:propertyName="translationX"android:duration="@android:integer/config_mediumAnimTime" /><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="0.0" android:valueTo="1.0"android:valueType="floatType"android:propertyName="alpha"android:duration="@android:integer/config_mediumAnimTime" /> </set>fragment_slide_right_exit:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="0dp" android:valueTo="100dp"android:valueType="floatType"android:propertyName="translationX"android:duration="@android:integer/config_mediumAnimTime" /><objectAnimatorandroid:interpolator="@android:interpolator/decelerate_quint"android:valueFrom="1.0" android:valueTo="0.0"android:valueType="floatType"android:propertyName="alpha"android:duration="@android:integer/config_mediumAnimTime" /> </set>使用v4包,Fragment的使用不再局限于API Level 11之上,低等級(jí)的API也可以使用,但是這時(shí)候轉(zhuǎn)場(chǎng)動(dòng)畫的類型是View Animation。動(dòng)畫資源放在res\anim\路徑下。
Fragment中的方法:onCreateAnimation(int transit, boolean enter, int nextAnim)返回值A(chǔ)nimation。
FragmentTransaction中的setCustomAnimations()方法,兩參數(shù)類型和四參數(shù)類型都可用。
所以一般還是用v4包的這個(gè)版本,一是兼容性比較好,另外View Animation其實(shí)基本可以滿足轉(zhuǎn)場(chǎng)動(dòng)畫的需要。
private void addFragment() {if (null == mFragmentManager) {mFragmentManager = getSupportFragmentManager();}mTextFragmentOne = new MyFragmentOne();FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();fragmentTransaction.setCustomAnimations(R.anim.push_left_in,R.anim.push_left_out,R.anim.push_left_in,R.anim.push_left_out);fragmentTransaction.add(R.id.container, mTextFragmentOne);fragmentTransaction.addToBackStack(null);fragmentTransaction.commit(); }早期版本所使用到的轉(zhuǎn)場(chǎng)動(dòng)畫請(qǐng)參考手勢(shì)識(shí)別篇的動(dòng)畫。
1.9、回退棧
在使用Fragment的時(shí)候我們一般會(huì)這樣寫
對(duì)于是否需要添加transaction.addToBackStack(null),也就是將Fragment添加到回退棧。取決于你是否要在回退的時(shí)候顯示上一個(gè)Fragment。
2.0、Fragment通信
1)組件獲取
Fragment獲得Activity中的組件: getActivity().findViewById(R.id.list);
Activity獲得Fragment中的組件(根據(jù)id或tag也行):getFragmentManager.findFragmentByid(R.id.fragment1)
2)數(shù)據(jù)傳遞
①Activit傳遞數(shù)據(jù)給Fragment:
?? 在Activity中創(chuàng)建Bundle數(shù)據(jù)包,調(diào)用Fragment實(shí)例的setArguments(bundle) 從而將Bundle數(shù)據(jù)包傳給Fragment,然后Fragment中調(diào)用getArguments獲得 Bundle對(duì)象,進(jìn)行解析即可。
②Fragment傳遞數(shù)據(jù)給Activity
在Fragment中定義一個(gè)內(nèi)部回調(diào)接口,再讓包含該Fragment的Activity實(shí)現(xiàn)該回調(diào)接口, Fragment就可以通過(guò)回調(diào)接口傳數(shù)據(jù)了,回調(diào),。
Step 1:定義一個(gè)回調(diào)接口:(Fragment中)
public interface CallBack{ /*定義一個(gè)獲取信息的方法*/ public void getResult(String result); }Step 2:接口回調(diào)(Fragment中)
/*接口回調(diào)*/ public void getData(CallBack callBack){ /*獲取文本框的信息,當(dāng)然你也可以傳其他類型的參數(shù),看需求咯*/ String msg = editText.getText().toString(); callBack.getResult(msg); }Step 3:使用接口回調(diào)方法讀數(shù)據(jù)(Activity中)
leftFragment.getData(new CallBack() { @Override public void getResult(String result) {Toast.makeText(MainActivity.this, "-->>" + result, 1).show(); }}); }總結(jié):
在Fragment定義一個(gè)接口,接口中定義抽象方法,需要傳什么類型的數(shù)據(jù)參數(shù)就設(shè)置什么類型;
接著寫一個(gè)調(diào)用借口中的抽象方法,把要傳遞的數(shù)據(jù)傳過(guò)去 然后就是Activity了,調(diào)用Fragment提供的那個(gè)方法,然后重寫抽象方法的時(shí)候進(jìn)行數(shù)據(jù)的讀取即可。
?
2.1、Fragment中的回調(diào)
我們知道在Activity中想要獲取開(kāi)啟的另外一個(gè)Activity中的返回值,可以通過(guò)startActivityForResult來(lái)開(kāi)啟,然后在本Activity中實(shí)現(xiàn)onActivityResult方法并監(jiān)聽(tīng)結(jié)果值即可。
其實(shí)在Frament中也是一樣的,不過(guò)關(guān)于Fragment的回調(diào)可能存在以下幾種情況:
1、Fragment中直接開(kāi)啟Activity
這種情況下可以直接在Fragment中開(kāi)啟Activity即可。
2、Fragment中存在listView,我們?cè)贏dapter中進(jìn)行開(kāi)啟
這種情況我們需要在Adapter中獲取Fragment實(shí)例,并調(diào)用startActivityForResult方法。
3、Fragment多層嵌套的時(shí)候
在多層嵌套的情況下,我們首先看Activity中是否實(shí)現(xiàn)了OnActivityResult方法,并切忌不要?jiǎng)h除Activity中的super.OnActivityResult即可。
?
轉(zhuǎn)載于:https://www.cnblogs.com/pengjingya/p/5509102.html
總結(jié)
以上是生活随笔為你收集整理的19、Fragment的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 快手sig签名和did egid的注册(
- 下一篇: 使用 IPsec 与组策略隔离服务器和域