Fragment是可以嵌入Activity的UI片段,能让程序更加合理和充分地利用空间。
Fragment的基本用法
静态加载
1. 直接在宿主Activity的Layout中引入<fragment>
注意:
name指定绑定的Fragment
tag与id属性是必须添加的,作为Fragment的标记。
<?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设置布局
为了方便演示,就设置个纯色背景
<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. 设置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);
}
}
效果
动态加载
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. 设置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="我是动态加载的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.设置Fragment类,和上面静态加载代码相同
4. Activity中用代码动态加载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触发晚。
public class MyFragment extends Fragment {
//Fragment和宿主 Activity 绑定
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
//Fragment 和宿主 Activity 解除绑定
@Override
public void onDetach() {
super.onDetach();
}
//开始创建
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
//UI创建时,可见时调用
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
//绑定样式
return null;
}
//宿主Activity的onCreate执行完成后回掉
@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();
}
//销毁,开始回收内存
@Override
public void onDestroy() {
super.onDestroy();
}
}
FragmentTransaction常用API
1. add(int containerViewId, Fragment fragment, String tag);
添加Fragment,UI效果是层层叠加。
id:添加目标空间的id
fragment:要添加的 fragment 实例
tag:与添加的 fragment 对应,用于findFragmentByTag时查找到对应的Fragment
2. replace(int containerViewId, Fragment fragment, String tag)
先将之前添加的所有Fragment清除,然后再添加。
3. detach(Fragment fragment)
解除Fragment与宿主Activity的UI绑定,但是不调用Fragment的onDestroy()。
即Fragment依旧存在,只是不与宿主关联。
4. attach(Fragment fragment)
重新绑定Fragment,调用onCreateView()。
5. remove(Fragment fragment)
调用Fragment的onDestroy(),彻底删除Fragment与Activity的关联。
6. hide(Fragment fragment)
隐藏Fragment,不调用任何生命周期方法只是隐藏UI,避免反复调用创建,消耗内存。
7. show(Fragment fragment)
将隐藏UI显示出来。
commit() 与 commitAllowingStateLoss() 提交区别
Activity在以下情况容易触发onSaveInstanceState(Bundle outState)
按下HOME键
按下电源(关闭屏幕显示)键
屏幕方向切换
Activity跳转切换
在以上情况提交Fragment会抛出异常,
也就说尽量不能在onPause(),onStop(),onDestroy(),做commit()提交操作。
如果需要,就要用commitAllowingStateLoss()代替commit()。
Fragment的返回栈
Fragment默认不会响应Back键,因此点击Back键时,Fragment无回退状态。
如果想按下Back键回退到上一个碎片,就需要设置Fragment的返回栈。
设置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的名称
可以根据这个名称找到相应的添加Fragment操作,进行回退操作
popBackStack("popup1", POP_BACK_STACK_INCLUSIVE);
也可以传null代表不记录该次操作
fraTran.add(R.id.fra_content, new RedFragment(), "Tag")
.addToBackStack(null)
.commit();
}
}
Fragment动画
主要是使用FragmentTransaction中setCustomAnimations()设置动画
1.v4的Transaction支持XML动画,但不支持属性动画。
FragmentTransaction setCustomAnimations (int enter, int exit,
int popEnter, int popExit)
参数
enter:当一个Fragment被添加added 或者绑定 attached到视图上时
exit:当一个Fragment从视图上被移除removed或者解除绑定detached时
popEnter:当调用popBackStack()弹栈后,栈顶Fragment重新被添加时
popExit:当调用popBackStack()弹栈后,弹出的Fragment
slide_left_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_left_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>
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) {
//拿到传递的数据
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", "传递的数据");
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.多个Fragment间通讯
Fragment必定依存于Activity,因此将Activity作为中间层,通过接口进行交互。
举个例子
在FragmentTwo监听显示FragmentOne中Button的点击次数。
1. 为了方便,选择静态加载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实现
你可以理解为这个接口成了Activity的父类
当Fragment调用getActivity()时,根据多态特性,调用的是Activity的实现
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调用点击
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++;
//调用的还是子类的实现
mClickCountListener.clickCount(index);
}
});
}
}
4.showFragment定义方法用于显示计数,当clickFragment数值改变时,相应的也会调用。
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补充
1.屏幕旋转时Fragment数据丢失问题
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("index", index);
}
2.inflate
inflate(R.layout.fragment_one, container, false);
参数
绑定Layout布局
通知View,将定义的布局挂载上去。
false表示自己手动挂载,不需要自动添加。
网友评论