Fragment是可以嵌入Activity的UI片段,能讓程序更加合理和充分地利用空間可都。
Fragment的基本用法
靜態(tài)加載
1. 直接在宿主Activity的Layout中引入<fragment>
注意:
name指定綁定的Fragment
tag與id屬性是必須添加的啄枕,作為Fragment的標(biāo)記婚陪。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activity.MainActivity">
<fragment
android:id="@+id/fra_id"
android:name="com.w.review.ui.fragment.MyFragment"
android:layout_width="match_parent"
android:layout_height="300dp"
android:tag="fra_demo" />
</android.support.constraint.ConstraintLayout>
2. 為Fragment設(shè)置布局
為了方便演示,就設(shè)置個(gè)純色背景
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是Fragment"
android:textColor="#FFF"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
3. 設(shè)置Fragment類
public class MyFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
//綁定樣式
return inflater.inflate(R.layout.fragment_demo, container, false);
}
}
效果
動(dòng)態(tài)加載
1. 在宿主Activity中留出一塊布局频祝,用來裝載Fragment的樣式
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activity.MainActivity">
<FrameLayout
android:id="@+id/fra_content"
android:layout_width="match_parent"
android:layout_height="300dp" />
</android.support.constraint.ConstraintLayout>
2. 設(shè)置Fragment的布局
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是動(dòng)態(tài)加載的Fragment"
android:textColor="#FFF"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
3.設(shè)置Fragment類泌参,和上面靜態(tài)加載代碼相同
4. Activity中用代碼動(dòng)態(tài)加載Fragment
public class MainActivity extends AppCompatActivity {
private MyFragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFragment();
}
private void initFragment(){
mFragment = new MyFragment();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction
.replace(R.id.fra_content,mFragment,"fra_demo")
.commit();
}
}
效果
Fragment的生命周期
Fragment依賴于Activity存在,它的生命周期相較于宿主Activity觸發(fā)晚常空。
public class MyFragment extends Fragment {
//Fragment和宿主 Activity 綁定
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
//Fragment 和宿主 Activity 解除綁定
@Override
public void onDetach() {
super.onDetach();
}
//開始創(chuàng)建
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
//UI創(chuàng)建時(shí)沽一,可見時(shí)調(diào)用
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
//綁定樣式
return null;
}
//宿主Activity的onCreate執(zhí)行完成后回掉
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
//UI銷毀,變得不可見
@Override
public void onDestroyView() {
super.onDestroyView();
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
//銷毀窟绷,開始回收內(nèi)存
@Override
public void onDestroy() {
super.onDestroy();
}
}
FragmentTransaction常用API
1. add(int containerViewId, Fragment fragment, String tag);
添加Fragment锯玛,UI效果是層層疊加。
id:添加目標(biāo)空間的id
fragment:要添加的 fragment 實(shí)例
tag:與添加的 fragment 對應(yīng)兼蜈,用于findFragmentByTag時(shí)查找到對應(yīng)的Fragment
2. replace(int containerViewId, Fragment fragment, String tag)
先將之前添加的所有Fragment清除攘残,然后再添加。
3. detach(Fragment fragment)
解除Fragment與宿主Activity的UI綁定为狸,但是不調(diào)用Fragment的onDestroy()歼郭。
即Fragment依舊存在,只是不與宿主關(guān)聯(lián)辐棒。
4. attach(Fragment fragment)
重新綁定Fragment病曾,調(diào)用onCreateView()。
5. remove(Fragment fragment)
調(diào)用Fragment的onDestroy()漾根,徹底刪除Fragment與Activity的關(guān)聯(lián)泰涂。
6. hide(Fragment fragment)
隱藏Fragment,不調(diào)用任何生命周期方法只是隱藏UI辐怕,避免反復(fù)調(diào)用創(chuàng)建逼蒙,消耗內(nèi)存。
7. show(Fragment fragment)
將隱藏UI顯示出來寄疏。
commit() 與 commitAllowingStateLoss() 提交區(qū)別
Activity在以下情況容易觸發(fā)onSaveInstanceState(Bundle outState)
按下HOME鍵
按下電源(關(guān)閉屏幕顯示)鍵
屏幕方向切換
Activity跳轉(zhuǎn)切換
在以上情況提交Fragment會(huì)拋出異常是牢,
也就說盡量不能在onPause(),onStop()陕截,onDestroy()驳棱,做commit()提交操作。
如果需要农曲,就要用commitAllowingStateLoss()代替commit()社搅。
Fragment的返回棧
Fragment默認(rèn)不會(huì)響應(yīng)Back鍵,因此點(diǎn)擊Back鍵時(shí),F(xiàn)ragment無回退狀態(tài)罚渐。
如果想按下Back鍵回退到上一個(gè)碎片却汉,就需要設(shè)置Fragment的返回棧。
設(shè)置Fragment
public class RedFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = new View(getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, 56);
view.setLayoutParams(params);
params.setMargins(0, 0, 0, 20);
view.setBackgroundColor(getResources().getColor(R.color.colorAccent));
//綁定樣式
return view;
}
}
public class MainActivity extends AppCompatActivity {
private Button mBtnAddFra, mBrnPopupFra;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
}
private void initEvent() {
mBtnAddFra.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loadFra();
}
});
mBrnPopupFra.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getSupportFragmentManager().popBackStack();
}
});
}
private void initView() {
mBtnAddFra = findViewById(R.id.btn_add_fra);
mBrnPopupFra = findViewById(R.id.btn_popup_fra);
}
private void loadFra() {
FragmentTransaction fraTran = getSupportFragmentManager().beginTransaction();
addToBackStack(String name)
name 代表這次Transaction的名稱
可以根據(jù)這個(gè)名稱找到相應(yīng)的添加Fragment操作荷并,進(jìn)行回退操作
popBackStack("popup1", POP_BACK_STACK_INCLUSIVE);
也可以傳null代表不記錄該次操作
fraTran.add(R.id.fra_content, new RedFragment(), "Tag")
.addToBackStack(null)
.commit();
}
}
Fragment動(dòng)畫
主要是使用FragmentTransaction中setCustomAnimations()設(shè)置動(dòng)畫
1.v4的Transaction支持XML動(dòng)畫,但不支持屬性動(dòng)畫青扔。
FragmentTransaction setCustomAnimations (int enter, int exit,
int popEnter, int popExit)
參數(shù)
enter:當(dāng)一個(gè)Fragment被添加added 或者綁定 attached到視圖上時(shí)
exit:當(dāng)一個(gè)Fragment從視圖上被移除removed或者解除綁定detached時(shí)
popEnter:當(dāng)調(diào)用popBackStack()彈棧后源织,棧頂Fragment重新被添加時(shí)
popExit:當(dāng)調(diào)用popBackStack()彈棧后,彈出的Fragment
slide_left_in.xml:左視圖進(jìn)入時(shí)動(dòng)畫
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="700"
android:fromXDelta="-100%p"
android:toXDelta="0%p" />
<alpha
android:duration="700"
android:fromAlpha="0.5"
android:toAlpha="1.0" />
</set>
slide_left_out.xml:左視圖離開時(shí)動(dòng)畫
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="700"
android:fromXDelta="0%p"
android:toXDelta="-100%p" />
<alpha
android:duration="700"
android:fromAlpha="1.0"
android:toAlpha="0.5" />
</set>
slide_right_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="700"
android:fromXDelta="100%p"
android:toXDelta="0%p" />
<alpha
android:duration="700"
android:fromAlpha="0.5"
android:toAlpha="1.0" />
</set>
slide_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="700"
android:fromXDelta="0%p"
android:toXDelta="100%p" />
<alpha
android:duration="700"
android:fromAlpha="1.0"
android:toAlpha="0.5" />
</set>
public class MainActivity extends AppCompatActivity {
private Button mBtnPrevious, mBtnNext;
private RedFragment mRedFra;
private BlueFragment mBlueFra;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
initFra();
}
private void initFra() {
mRedFra = new RedFragment();
mBlueFra = new BlueFragment();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fra_content, mRedFra)
.commit();
}
private void initEvent() {
mBtnPrevious.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getSupportFragmentManager()
.popBackStack();
}
});
mBtnNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.anim.slide_right_in,
R.anim.slide_left_out,
R.anim.slide_left_in,
R.anim.slide_right_out
).replace(R.id.fra_content, mBlueFra)
.addToBackStack(null)
.commit();
}
});
}
private void initView() {
mBtnPrevious = findViewById(R.id.btn_previous);
mBtnNext = findViewById(R.id.btn_next);
}
}
Fragment通訊
1.Activity和Fragment通訊微猖,使用Bundle
public class MyFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
//拿到傳遞的數(shù)據(jù)
String res = getArguments().get("key").toString();
TextView textView = new TextView(getContext());
textView.setLayoutParams(
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setText(res);
return textView;
}
}
public class MainActivity extends AppCompatActivity {
private Button mBtnAddFra;
private MyFragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
}
private void addFra() {
mFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("key", "傳遞的數(shù)據(jù)");
mFragment.setArguments(bundle);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fra_content, mFragment, "fra")
.commit();
}
private void initEvent() {
mBtnAddFra.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addFra();
}
});
}
private void initView() {
mBtnAddFra = findViewById(R.id.btn_add_fra);
}
}
效果
2.多個(gè)Fragment間通訊
Fragment必定依存于Activity谈息,因此將Activity作為中間層,通過接口進(jìn)行交互凛剥。
舉個(gè)例子
在FragmentTwo監(jiān)聽顯示FragmentOne中Button的點(diǎn)擊次數(shù)侠仇。
1. 為了方便,選擇靜態(tài)加載Fragment布局
<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=".ui.activity.MainActivity">
<fragment
android:id="@+id/fra_red"
android:name="com.w.review.ui.fragment.ShowFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:tag="showFra" />
<fragment
android:id="@+id/fra_blue"
android:name="com.w.review.ui.fragment.ClickFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:tag="clickFra" />
</LinearLayout>
2.定義接口犁珠,由Activity實(shí)現(xiàn)
你可以理解為這個(gè)接口成了Activity的父類
當(dāng)Fragment調(diào)用getActivity()時(shí)逻炊,根據(jù)多態(tài)特性,調(diào)用的是Activity的實(shí)現(xiàn)
public interface IClickCountListener {
void clickCount(int index);
}
public class MainActivity extends AppCompatActivity implements IClickCountListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void clickCount(int index) {
ShowFragment showFrat = (ShowFragment) getSupportFragmentManager()
.findFragmentByTag("showFra");
showFrat.setCount(index);
}
}
3.ClickFragment調(diào)用點(diǎn)擊
public class ClickFragment extends Fragment {
private View mView;
private Button mBtnAddCount;
private int index = 0;
private IClickCountListener mClickCountListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_blue, container, false);
mBtnAddCount = mView.findViewById(R.id.btn_add_count);
return mView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//獲取Activity的引用犁享,子類指向父類
mClickCountListener = (IClickCountListener) getActivity();
initEvent();
}
private void initEvent() {
mBtnAddCount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
index++;
//調(diào)用的還是子類的實(shí)現(xiàn)
mClickCountListener.clickCount(index);
}
});
}
}
4.showFragment定義方法用于顯示計(jì)數(shù)余素,當(dāng)clickFragment數(shù)值改變時(shí),相應(yīng)的也會(huì)調(diào)用炊昆。
public class ShowFragment extends Fragment {
private View mView;
private TextView mTvCount;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_red, container, false);
mTvCount = mView.findViewById(R.id.tv_count);
return mView;
}
public void setCount(int index) {
mTvCount.setText(String.valueOf(index));
}
}
Fragment補(bǔ)充
1.屏幕旋轉(zhuǎn)時(shí)Fragment數(shù)據(jù)丟失問題
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("index", index);
}
2.inflate
inflate(R.layout.fragment_one, container, false);
參數(shù)
綁定Layout布局
通知View桨吊,將定義的布局掛載上去。
false表示自己手動(dòng)掛載凤巨,不需要自動(dòng)添加视乐。