之前写的第一篇Fragment实例,和大多数人一開始学的一样。都是通过FragmentTransaction的replace方法来实现,replace方法相当于先移除remove()原来全部已存在的fragments,然后加入add()当前这个fragment。这就导致了一个问题,我们切换一次,然后再切换回来,相当于又一次载入了这个fragment,原来的状态不复存在,这显然与我们的日常使用不符。

想要保存切换后的状态。思路还是非常easy的。我们先加入了若干fragments。切换后将全部fragments都隐藏hide()。并显示show()切换后的fragment就可以。


实例:山寨微信

因为代码较长。这里仅仅讲核心的部分,有兴趣的能够下载源代码来看一下

public class MainActivity extends ActionBarActivity implements OnClickListener {

private View weixinLayout, tongxunluLayout, faxianLayout, woLayout;
private TextView weixinTv, tongxunluTv, faxianTv, woTv;
private ImageView weixinIv, tongxunluIv, faxianIv, woIv;
private Fragment1 fragment1;
private Fragment2 fragment2;
private Fragment3 fragment3;
private Fragment4 fragment4;
private FragmentManager fm;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化
initViews();

fm = getFragmentManager();

// 初识状态是显示微信
weixinIv.setBackgroundResource(R.drawable.weixin2);
weixinTv.setTextColor(getResources().getColor(R.color.green));
showFragment(1);
}

void initViews() {
// 注冊各IamgeView
weixinIv = (ImageView) findViewById(R.id.weixin_iv);
tongxunluIv = (ImageView) findViewById(R.id.tongxunlu_iv);
faxianIv = (ImageView) findViewById(R.id.faxian_iv);
woIv = (ImageView) findViewById(R.id.wo_iv);

// 注冊各TextView
weixinTv = (TextView) findViewById(R.id.weixin_tv);
tongxunluTv = (TextView) findViewById(R.id.tongxunlu_tv);
faxianTv = (TextView) findViewById(R.id.faxian_tv);
woTv = (TextView) findViewById(R.id.wo_tv);

// 注冊各Layout
weixinLayout = (View) findViewById(R.id.weixin_layout);
tongxunluLayout = (View) findViewById(R.id.tongxunlu_layout);
faxianLayout = (View) findViewById(R.id.faxian_layout);
woLayout = (View) findViewById(R.id.wo_layout);

// 各Layout注冊监听器
weixinLayout.setOnClickListener(this);
tongxunluLayout.setOnClickListener(this);
faxianLayout.setOnClickListener(this);
woLayout.setOnClickListener(this);

}

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
// 当点击某个layout时。先清除状态。这里的状态指的是布局里面的图片和文字
clearState();
switch (arg0.getId()) {
case R.id.weixin_layout:
// 假设点的是微信。将微信布局的图片和文字的颜色变为绿色
weixinIv.setBackgroundResource(R.drawable.weixin2);
weixinTv.setTextColor(getResources().getColor(R.color.green));
// 显示微信的fragment
showFragment(1);
break;
case R.id.tongxunlu_layout:
tongxunluIv.setBackgroundResource(R.drawable.tongxunlu2);
tongxunluTv.setTextColor(getResources().getColor(R.color.green));
showFragment(2);
break;
case R.id.faxian_layout:
faxianIv.setBackgroundResource(R.drawable.faxian2);
faxianTv.setTextColor(getResources().getColor(R.color.green));
showFragment(3);
break;
case R.id.wo_layout:
woIv.setBackgroundResource(R.drawable.wo2);
woTv.setTextColor(getResources().getColor(R.color.green));
showFragment(4);
break;
}
}

public void clearState() {
// 未选中时的图片
weixinIv.setBackgroundResource(R.drawable.weixin1);
tongxunluIv.setBackgroundResource(R.drawable.tongxunlu1);
faxianIv.setBackgroundResource(R.drawable.faxian1);
woIv.setBackgroundResource(R.drawable.wo1);
// 未选中时字体颜色
weixinTv.setTextColor(getResources().getColor(R.color.black));
tongxunluTv.setTextColor(getResources().getColor(R.color.black));
faxianTv.setTextColor(getResources().getColor(R.color.black));
woTv.setTextColor(getResources().getColor(R.color.black));
}

public void showFragment(int index) {
FragmentTransaction ft = fm.beginTransaction();

// 想要显示一个fragment,先隐藏全部fragment。防止重叠
hideFragments(ft);

switch (index) {
case 1:
// 假设fragment1已经存在则将其显示出来
if (fragment1 != null)
ft.show(fragment1);
// 否则是第一次切换则加入fragment1,注意加入后是会显示出来的。replace方法也是先remove后add
else {
fragment1 = new Fragment1();
ft.add(R.id.content, fragment1);
}
break;
case 2:
if (fragment2 != null)
ft.show(fragment2);
else {
fragment2 = new Fragment2();
ft.add(R.id.content, fragment2);
}
break;
case 3:
if (fragment3 != null)
ft.show(fragment3);
else {
fragment3 = new Fragment3();
ft.add(R.id.content, fragment3);
}
break;
case 4:
if (fragment4 != null)
ft.show(fragment4);
else {
fragment4 = new Fragment4();
ft.add(R.id.content, fragment4);
}
break;
}
ft.commit();
}

// 当fragment已被实例化,就隐藏起来
public void hideFragments(FragmentTransaction ft) {
if (fragment1 != null)
ft.hide(fragment1);
if (fragment2 != null)
ft.hide(fragment2);
if (fragment3 != null)
ft.hide(fragment3);
if (fragment4 != null)
ft.hide(fragment4);
}

}

Android组件:Fragment切换后保存状态_javascript

当我们一開始把微信fragment的ListView下拉到如上图时,切换到通讯录fragment。然后再切换回去微信fragment。此时微信的ListView还是原来的状态。这是由于并不是又一次载入微信fragment,而是将其先hide起来,切换回来后再show出来。

引用上篇文章的fragment生命周期图:

Android组件:Fragment切换后保存状态_javascript_02

假设是repalce方法,我们切换至当前fragment则进行红线以上的生命周期。切换到其它fragment后进行红线下面的生命周期。

可是。假设我们使用hide()和show()的方法,切换至当前fragment依旧进行红线以上的生命周期,切换到其它fragment后并没有进行其它生命周期,仅仅是简单地隐藏了起来。这样应该非常明了了吧。