前言:·前一篇已经讲了Fragment的基本使用,那么现在开始深入一点讨论
在上一篇博客,我们在动态使用Fragment时,已经见到了。再次我们重新回顾一下那段代码:
fm = getFragmentManager(); ft = fm.beginTransaction(); ft.replace(R.id.container, new FragmentLife()); ft.commit();
注:变量的声明,private FragmentManager fm; private FragmentTransaction ft;
肯定有不少人对这两个类的情况表示迷茫,现在我们简单介绍一下这两个类的情况。
1. FragmentManager:用于管理activity中的fragments, 可通过getFragmentManager()或getSupportFragmentManager()获得。
注意:该函数会先把containerViewId中所有fragment删除,然后再add进去当前的fragment
# 在transaction.commit()之前,使用addToBackStack()将其添加到回退栈中
transaction.addToBackStack(String tag);
# 在需要回退时,使用popBackStack()将最上层的操作弹出回退栈
manager.popBackStack();
注:当栈中有多层时,我们可以根据id或TAG标识来指定弹出到的操作所在层
void popBackStack(int id, int flags);
void popBackStack(String name, int flags);
参数解释:
|--参数int id是当提交变更时transaction.commit()的返回值
|--参数string name是transaction.addToBackStack(String tag)中的tag值
|--参数int flags有两个取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE
|--当取值0时,表示除了参数指定这一层之上的所有层都退出栈,指定的这一层为栈顶层
|--当取值POP_BACK_STACK_INCLUSIVE时,表示连着参数一指定的这一层一起退出栈
关于事务回退的原则:回退是以commit()提交的一次事务为单位的,而不是以其中的add,replace等等操作为单位回退的.举例: 若在一次提交时,一次性添加了fragment2,fragment3,fragment4,则回退时,会依据添加时的顺序,将它们一个个删除,返回到没有添加fragment4,fragment3,fragment2的状态.
[这样说一些纯文字,可能比较枯燥,但是这些还是必须要掌握的,关于这写函数的例子就不多写了,给推荐一个博客:http://blog.csdn.net/harvic880925/article/details/44927375,这位大牛写的很详细,就不多献丑了]
3. 在实战中的运用方法:
|-- 如果使用replace来切换页面,那么在每次切换的时候,Fragment都会重新实例化,重新加载一边数据,这样非常消耗性能和用户的数据流量。
|--这是因为replace操作每次都会把container中的现有的fragment实例清空,然后再把指定的fragment添加进去,就造成了在切换到以前的fragment时,就会重新实例会fragment。
|-- 正确的切换方式是add(),切换时hide(),add()另一个Fragment;再次切换时,只需hide()当前,show()另一个。这样就能做到多个Fragment切换不重新实例化
|-- 基本算法:
public void switchContent(Fragment from, Fragment to) { if (!to.isAdded()) { // 先判断是否被add过 // 隐藏当前的fragment,add下一个到Activity中 transaction.hide(from).add(R.id.content_frame, to).commit(); } else { transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个 } }
|-- add()和replace()千万不要共用
看了那么前面一大段的理论性东西,现在我们通过一个小案例来进一步掌握刚刚的知识(FragmentManager和FragmentTranscation的使用)。
- 需求:给出一个界面,界面上方是登录、注册横向导航,实现登录、注册的切换
- 代码实现:
- activity_switch_ragment.xml:
<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="com.johnnie.fragment.MainActivity" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:id="@+id/tv_login" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#483D8B" android:gravity="center" android:text="@string/btn_login" android:textColor="#FFFFFF" android:textSize="25sp" /> <TextView android:id="@+id/tv_regist" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:background="#0000FF" android:gravity="center" android:text="@string/btn_regist" android:textColor="#FFFFFF" android:textSize="25sp" /> </LinearLayout> <LinearLayout android:id="@+id/ll_content" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > </LinearLayout> </LinearLayout>
- fragment_login.xml:
<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="com.johnnie.login.MainActivity" > <EditText android:id="@+id/et_username" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="@string/et_username" /> <EditText android:id="@+id/et_userpass" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" android:inputType="textPassword" android:hint="@string/et_userpass" /> <Button android:id="@+id/btn_login" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_login" /> </LinearLayout>
- fragment_regist.xml:
<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="com.johnnie.login.MainActivity" > <EditText android:id="@+id/et_username" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="@string/et_username" /> <EditText android:id="@+id/et_userpass" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" android:inputType="textPassword" android:hint="@string/et_userpass" /> <Button android:id="@+id/btn_regist" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_regist" /> </LinearLayout>
- LoginFragment:
public class LoginFragment extends Fragment{ // 控件的声明 private EditText et_username; private EditText et_userpass; private Button btn_login; private View view; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_login, container, false); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); et_username = (EditText) view.findViewById(R.id.et_username); et_userpass = (EditText) view.findViewById(R.id.et_userpass); btn_login = (Button) view.findViewById(R.id.btn_login); btn_login.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { login(); } }); } /** * 用户登录 */ private void login() { System.out.println("登录..."); // 获取用户输入 String username = et_username.getText().toString().trim(); String userpass = et_userpass.getText().toString().trim(); // 输入校验 boolean flag = false; String msg = "登录失败!"; if (!TextUtils.isEmpty(userpass) && !TextUtils.isEmpty(username)) { msg = "登录成功!"; flag = true; } // 弹出提示 Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show(); if (flag) { // 通过调用 newInstance 函数来获取实例并传递参数 WelcomeFragment fragment = WelcomeFragment.newInstance(username); FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); ft.replace(R.id.content, fragment); ft.commit(); } } }
- RegistFragment:
public class RegistFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_regist, null); } }
- SwitchFragmentActivity:
public class SwitchFragmentActivity extends Activity implements OnClickListener{ public FragmentManager fm; public FragmentTransaction ft; private LoginFragment loginFragment; private RegistFragment registFragment; private TextView tv_login; private TextView tv_regist; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_switch_ragment); tabWithFragment(); } private void tabWithFragment() { tv_login = (TextView) findViewById(R.id.tv_login); tv_regist = (TextView) findViewById(R.id.tv_regist); tv_login.setOnClickListener(this); tv_regist.setOnClickListener(this); fm = getFragmentManager(); ft = fm.beginTransaction(); loginFragment = new LoginFragment(); // 默认是显示 LoginFragment ft.replace(R.id.ll_content, loginFragment); ft.commit(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.tv_login: ft = fm.beginTransaction(); loginFragment = new LoginFragment(); // 默认是显示 loginFragment ft.replace(R.id.ll_content, loginFragment); break; case R.id.tv_regist: ft = fm.beginTransaction(); registFragment = new RegistFragment(); // 默认是显示 registFragment ft.replace(R.id.ll_content, registFragment); break; } ft.commit(); } }
- 部署项目,运行如下:
点击注册,变成如下注册界面
经过理论和实践,就基本掌握了Fragment的使用。现在总结一下刚才所学。|-- FragmentManager 和 FragmentTranscation 的基本使用|-- 如何在同一个Activity中管理Fragment,进行Fragment的切换?步骤如下:
下一篇将讲解Fragment之间的数据传递,以及实现抽屉导航,敬请期待...1.获取到FragmentManager: 在V4包中通过getSupportFragmentManager,原生的Fragment是通过getFragmentManager
2.开启一个事务: beginTransaction
3.向容器内加入Fragment: add或者replace,需要传入容器的id和Fragment的实例
4.提交事务: commit