单Activity管理多个Fragment进行界面展示、页面跳转是很常见的界面编程方式,Fragment在使用时有一些使用技巧和“坑人”的地方,本文进行总结与分享。
Activity管理Fragment
Activity控制Fragment的展示、布局。
Fragment的展示和切换(出入栈)
通过FragmentManager管理Fragment出入栈,建议为每个Fragment定义一个tag(字符串常量),方便Fragment管理、Activity与Fragment通信,FragmentManager管理Fragment核心代码如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
   | public static final String TAG_LEAVE = "tag_leave"; public static final String TAG_LEAVE_APPLY = "tag_leave_apply";
  private void navigateToTargetFragment(String tag, Bundle param) {          BaseFragment targetFragment;          if (TAG_LEAVE.equals(tag)) {         if (leaveFragment == null) {             leaveFragment = new LeaveFragment();         }         targetFragment = leaveFragment;     } else if (TAG_LEAVE_APPLY.equals(tag)) {         if (leaveApplyFragment == null) {             leaveApplyFragment = new LeaveApplyFragment();         }         targetFragment = leaveApplyFragment;     } else {         if (leaveFragment == null) {             leaveFragment = new LeaveFragment();         }         targetFragment = leaveFragment;         tag = TAG_LEAVE;     }          if (targetFragment == null || targetFragment.isVisible() || targetFragment.isAdded()) {         return;     }          displayLayout(tag);          if (param != null) {         targetFragment.setArguments(param);     }                    if (currentFragment == null) {         fragmentManager.beginTransaction()                 .replace(R.id.fragment_container, targetFragment, tag)                 .addToBackStack(tag)                 .commit();     } else {         fragmentManager.beginTransaction()                 .add(R.id.fragment_container, targetFragment, tag)                 .addToBackStack(tag)                 .commit();     }     currentFragment = targetFragment;     fragmentTag = tag; }
 
 
 
  private void displayLayout(String tag) {     setCommonRightIcon(R.drawable.common_transparent);     switch (tag) {         case TAG_LEAVE: {                          setCommonTitle(R.string.room_leave_resign_manage);                          setCommonRightIcon(R.drawable.action_bar_add);         }         break;
          case TAG_LEAVE_APPLY: {             setCommonTitle(R.string.room_leave_apply);         }         break;
          default:     } }
 
 
  | 
 
如上是Activity添加Fragment到当前界面,并在Fragment入栈时设置Activity UI。
通常情况下,当用户点击返回键(物理返回键、界面虚拟返回键)时,需要返回到上一个Activity而不是直接FinishActivity,而Fragment无法直接拦截物理返回键点击事件,因此需要通过宿主Activity来管理Fragment的出栈。核心代码在Activity,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | @Override public void onBackPressed() {     backFragment(); }
  protected void backFragment() {     fragmentManager.popBackStackImmediate();     if (fragmentManager.getBackStackEntryCount() == 0) {         finish();     } else {         fragmentTag = fragmentManager.getFragments().get(fragmentManager.getBackStackEntryCount() - 1).getTag();         displayLayout(fragmentTag);     } }
 
 
  | 
 
Fragment通信
Fragment和Activity通信、Fragment之间通信(例如左右布局)
Fragment和Activity通信
- 通过接口回调实现Fragment向Activity的通信,宿主Activity实现通信接口,Fragment调用FragmentEvent的Activity实例传递事件和参数。通信接口类如下:
 
1 2 3 4 5 6 7 8 9 10 11
   | public interface FragmentEvent {
      
 
 
 
 
      Object onFragmentEvent(String event, Object param); }
 
 
  | 
 
Activity实现接口,Fragment获取实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
   | public class LeaveActivity extends BaseActivity implements FragmentEvent {   ...
    @Override   public Object onFragmentEvent(String event, Object param) {       if (CommonUtil.isEmpty(event)) {           return null;       }       switch (event) {           case TAG_LEAVE_DETAIL: {               Bundle params = new Bundle();               params.putLong(LeaveDetailFragment.PARAM_LEAVE_ID, (Long) param);               navigateToTargetFragment(TAG_LEAVE_DETAIL, params);           }           break;
            case TITLE_TAG: {               fragmentTag = param.toString();               displayLayout(fragmentTag);           }           break;
            case BACK_TAG: {               backFragment();           }           break;       }       return null;   }
    ... }
 
 
 
  if (getActivity() instanceof FragmentEvent) {     this.mFragmentEvent = (FragmentEvent) getActivity(); }
 
  mFragmentEvent.onFragmentEvent(BACK_TAG, null);
 
 
  | 
 
- 通过广播,在Activity中注册广播,Fragment发送广播;
 
Activity向Fragment通信
通过fragmet的setArguments()方法,在fragment初始化的时候传递参数和事件;
 
Fragment中定义public方法,通过Activity中的fragment实例调用;
 
通过EventBus在activity中向fragment传递事;
 
Fragment之间通信
通过fragment的public方法,首先fragmentA通过getActivity().getFragmentManager().getFragment…()获取到fragmentB,然后调用fragmentB的public方法,比较繁琐。
 
使用接口(推荐),首先如上通过接口实现fragment向activity的通信,其次通过public方法实现activity向Fragment的通信,从而间接实现Fragment之间的通信。
 
使用setTargetFragment()、onActivityResult()、getTargetFragment()进行fragment间的通信
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | FragmentA { 	 	private void send(){ 		setTargetFragment(fargmentB, ...); 	}
  	@Override     public void onActivityResult(int requestCode, int resultCode, Intent data) {         super.onActivityResult(requestCode, resultCode, data); 		...     } }
  FragmentB { 	getTargetFragment().onActivityResult(requestCode, resultCode, Intent data); }
 
 
  | 
 
Fragment一些坑点
Fragment点击事件穿透
Fragment入栈后若没有被hide,上层Fragment的点击事件会被下发到下一层,通过拦截点击事件消除此影响。
在BaseFragment中为rootView设置点击属性,消化掉此层的点击事件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
   | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {     if (rootView == null) {         rootView = inflater.inflate(this.getLayoutResId(), container, false);     }     if (rootView.getParent() != null) {         ((ViewGroup) rootView.getParent()).removeView(rootView);     } 	 	rootView.setClickable(true); 	... }
 
 
  | 
 
参考
https://blog.csdn.net/u012881042/article/details/51798736
(完)