本文记录如何实现同个Activity中存在多个Fragment多次切换依次返回之后或者任意返回。
依次返回
思路:自己定义一个栈,将我们每次显示的Fragment放到我们的栈里面,想要依次返回的时候就从栈顶开始弹栈,如果想要返回到任意Fragment的时候,就去栈中找到这个Fragment
实现这个需求需要用到Stack这个类了
首先简单介绍下Stack,首先它是继承Vector,在Vector基础上,做了一些拓展,主要方法如下
方法名 | 返回类型 | 说明 |
---|---|---|
empty | boolean | 判断是否为空 |
peek | E | 返回栈顶元素 |
pop | E | 弹出栈顶元素,并将该元素返回 |
push | E | 将元素压入栈 |
search | int | 返回最靠近顶端的目标元素到顶端的距离。 |
1,首先需要3个Fragment
public class Fragment1 extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1,container,false);
TextView mTextView = (TextView) view.findViewById(R.id.tv_fragment_content);
mTextView.setText("Fragment1");
return view;
}
}
public class Fragment2 extends Fragment1 {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1,container,false);
TextView mTextView = (TextView) view.findViewById(R.id.tv_fragment_content);
mTextView.setText("Fragment2");
return view;
}
}
public class Fragment3 extends Fragment1{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1,container,false);
TextView mTextView = (TextView) view.findViewById(R.id.tv_fragment_content);
mTextView.setText("Fragment3");
return view;
}
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_fragment_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="40sp"
android:text="--"
/>
</LinearLayout>
有了3个Fragment之后,我们要实现的效果跟之前一样,依次切换3个Fragment然后通过按返回键依次返回之前的Fragment
下面是Activity的代码:
为什么纯代码写布局,因为工作所迫
public class StackActivity extends FragmentActivity {
private Stack<Fragment> mFragmentStack = new Stack<>();//自己维护要处理Fragment的栈,这么做的好处是可以灵活的使用里面保存的Fragmtnt
private Fragment mContentFragment,MainFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout mParentLayout = new LinearLayout(this); //最外层布局
mParentLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
mParentLayout.setOrientation(LinearLayout.VERTICAL);
LinearLayout mContentLayout = new LinearLayout(this);//内容布局
LinearLayout.LayoutParams mContentParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
mContentParams.weight = 1;
mContentLayout.setLayoutParams(mContentParams);
mContentLayout.setId(R.id.tv_fragment_content);
Button toggleFragment = new Button(this);//下面按钮
toggleFragment.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp2px(40)));
toggleFragment.setText("toggle");
toggleFragment.setOnClickListener(mToggleClickListener);
mParentLayout.addView(mContentLayout);
mParentLayout.addView(toggleFragment);
Window mWindow = getWindow();
mWindow.setContentView(mParentLayout);
MainFragment = new Fragment1();
mFragmentStack.push(MainFragment);//将元素添加到栈
getSupportFragmentManager().beginTransaction().add(R.id.tv_fragment_content,MainFragment,"fragment1").commit();
}
/**
* 切换Fragment 这里的if条件是防止多次点击相同元素多次进栈
* 可以根据自己业务灵活变动
*/
protected View.OnClickListener mToggleClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mFragmentStack.size() <= 1){
mContentFragment = new Fragment2();
mFragmentStack.push(mContentFragment);//将元素添加到栈
getSupportFragmentManager().beginTransaction().replace(R.id.tv_fragment_content,mContentFragment,"fragment1").commit();
}else if(mFragmentStack.size() == 2){
mContentFragment = new Fragment3();
showStacks(mFragmentStack);
getSupportFragmentManager().beginTransaction().replace(R.id.tv_fragment_content,mContentFragment,"fragment1").commit();
}
}
};
/**
* 返回键
* 触发栈里面的元素弹栈,栈顶开始
* 这里因为往栈里面塞了2个元素所以第一次弹栈的是最后添加的Fragment ->fragment2
*/
@Override
public void onBackPressed() { //返回键
if(!mFragmentStack.isEmpty()) {
mContentFragment = mFragmentStack.pop();
getSupportFragmentManager().beginTransaction().replace(R.id.tv_fragment_content, mContentFragment, "fragment1").commit();
}else
finish();
}
public void showStacks(Stack<Fragment> stack){
if(stack.size() == 0){
Log.e("TAG","栈里面是空的");
}else{
Enumeration mEnum = stack.elements();//得到stack中的枚举对象
while(mEnum.hasMoreElements()){
Log.e("TAG","elements : "+ mEnum.nextElement());
}
}
}
}
/**
* dp转换为px
* @param inparam
* @return
*/
public int dp2px(float inparam) {
float destiny = getResources().getDisplayMetrics().density;
return (int) (destiny * inparam + 0.5f);
}
这是最基础的依次返回,也可以按照自己的意愿返回到任意Fragment,只要存在在我们的栈中,则可以随意拿出来使用
任意返回
上面的search
方法,这个会返回目标元素到顶端的距离。
然后我们可以用Vector
的ElementAt
方法来获取到当前的对象
//这里只做了直接返回第一个Fragment,其他的没有处理
@Override
public void onBackPressed() { //返回键
if(!mFragmentStack.isEmpty()) {
mContentFragment = mFragmentStack.elementAt(mFragmentStack.size() - mFragmentStack.search(MainFragment));
getSupportFragmentManager().beginTransaction().replace(R.id.tv_fragment_content, mContentFragment, "fragment1").commit();
}else
finish();
}