我有一个活动,最初主持一个ViewPager,连接到FragmentPagerAdapter。
当用户点击ViewPager的子片段中的项目时,我正在使用FragmentTransaction将空容器视图替换为我想要导航到的新片段。
如果我在事务上使用addToBackStack(),提交事务然后导航回来,我不会返回到ViewPager的视图(初始布局)。
如果我不对事务使用addToBackStack(),则提交事务然后导航回来,应用程序退出。
看起来很明显ViewPager没有被添加到backstack中(这并不令人惊讶,因为它本身不是一个片段)..但我希望默认行为是背压将我带回那个活动的初始视图(ViewPager)。
根据我所读到的内容,似乎可能是因为片段事务正在发生,ViewPager或PagerAdapter会丢失应该显示哪个片段的跟踪。
我真的对此感到困惑,但我最终创建了一大堆代码覆盖了onBackPress并显示和隐藏了viewpager视图。我认为有一种更简单的方法可以使用默认行为来执行适当的导航。
TL;博士
A是托管片段的Viewpager。 B是一个新片段。
当我用B替换A,然后按回来时,我希望导航回A,但这不会发生。
非常感谢任何建议。
代码:
MainActivity:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
headingLayout = (RelativeLayout) findViewById(R.id.headingLayout);
headingLayout.setVisibility(View.GONE);
// Set up the ViewPager, attaching the adapter and setting up a listener
// for when the
// user swipes between sections.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setPageMargin(8);
/** Getting fragment manager */
FragmentManager fm = getSupportFragmentManager();
/** Instantiating FragmentPagerAdapter */
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm);
/** Setting the pagerAdapter to the pager object */
mViewPager.setAdapter(pagerAdapter);
.
.
.
}
public void onListItemClicked(Fragment fragment) {
fromPlayer = false;
InitiateTransaction(fragment, true);
}
public void InitiateTransaction(Fragment fragment, boolean addToBackStack) {
invalidateOptionsMenu();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragmentContainer, fragment).addToBackStack(null)
.commit();
}
PagerAdapter:
package another.music.player;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import another.music.player.fragments.AlbumListFragment;
import another.music.player.fragments.ArtistListFragment;
import another.music.player.fragments.SongListFragment;
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 3;
/** Constructor of the class */
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
/** This method will be invoked when a page is requested to create */
@Override
public Fragment getItem(int i) {
switch (i) {
case 0:
ArtistListFragment artistListFragment = new ArtistListFragment();
Bundle artistData = new Bundle();
artistData.putInt("current_page", i + 1);
artistListFragment.setArguments(artistData);
return artistListFragment;
case 1:
AlbumListFragment albumListFragment = new AlbumListFragment();
Bundle albumData = new Bundle();
albumData.putInt("current_page", i + 1);
albumData.putBoolean("showHeader", false);
albumListFragment.setArguments(albumData);
return albumListFragment;
default:
SongListFragment songListFragment = new SongListFragment();
Bundle songData = new Bundle();
songData.putInt("current_page", i + 1);
songListFragment.setArguments(songData);
return songListFragment;
}
}
/** Returns the number of pages */
@Override
public int getCount() {
return PAGE_COUNT;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Artists";
case 1:
return "Albums";
default:
return "Songs";
}
}
}
main xml(包含fragmentContainer& ViewPager):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/app_background_ics" >
<RelativeLayout
android:id="@+id/headingLayout"
android:layout_width="match_parent"
android:layout_height="56dp" >
</RelativeLayout>
<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/headingLayout" />
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<android.support.v4.view.PagerTabStrip
android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
</RelativeLayout>
答案 0 :(得分:37)
很长一段时间我也遇到过同样的问题。解决方案变得非常简单,并且您不需要任何具有ViewPager可见性的黑客攻击。我在其他与SO相关的问题中对此进行了描述:Fragment in ViewPager not restored after popBackStack
但是,为简单起见,您只需在ViewPager适配器中使用getChildFragmentManager(),而不是getSupportFragmentManager()。所以,而不是:
/** Getting fragment manager */
FragmentManager fm = getSupportFragmentManager();
/** Instantiating FragmentPagerAdapter */
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm);
/** Setting the pagerAdapter to the pager object */
mViewPager.setAdapter(pagerAdapter);
你这样做:
/** Getting fragment manager */
FragmentManager fm = getChildFragmentManager();
/** Instantiating FragmentPagerAdapter */
MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fm);
/** Setting the pagerAdapter to the pager object */
mViewPager.setAdapter(pagerAdapter);
答案 1 :(得分:9)
更新:
这不是“Android方式”,它会导致列表视图的用户体验不佳。而是创建一个新活动。
对于寻找这个问题的简单解决方案的人,我只想总结一下我做了什么。
我的架构:
FragmentActivity中的ViewPager(ActionBarActivity实际上是ActionBar支持。但是ActionBarActivity实现了FragmentActivity)。
2个标签:
对于每个FragmentContainer,我们在onCreate方法中调用getChildFragmentManager,并添加我们想要在此容器中显示的片段:
FragmentToShow fragment = new FragmentToShow();
getChildFragmentManager()
.beginTransaction()
.add(R.id.container, fragment)
.commit();
我们不希望将第一个片段添加到片段容器的backstack中,因为如果我们按下后退按钮,我们不想显示片段容器。
然后,如果我们想用FragmentToShow类中的另一个片段替换FragmentToShow(就像使用listView一样):
Fragment itemFragment = new ItemFragment();
getFragmentManager()
.beginTransaction()
.replace(R.id.container, itemFragment)
.addToBackStack(null)
.commit();
这里我们检索子片段管理器,然后将itemFragment添加到后栈。
现在我们想按下后退按钮返回listView(FragmentToShow实例)。我们的活动(FragmentActivity)是唯一知道后退按钮的活动,因此我们必须在此活动中覆盖onBackPressed()方法:
@Override
public void onBackPressed() {
// We retrieve the fragment manager of the activity
FragmentManager frgmtManager = getSupportFragmentManager();
// We retrieve the fragment container showed right now
// The viewpager assigns tags to fragment automatically like this
// mPager is our ViewPager instance
Fragment fragment = frgmtManager.findFragmentByTag("android:switcher:" + mPager.getId() + ":" + mPager.getCurrentItem());
// And thanks to the fragment container, we retrieve its child fragment manager
// holding our fragment in the back stack
FragmentManager childFragmentManager = fragment.getChildFragmentManager();
// And here we go, if the back stack is empty, we let the back button doing its job
// Otherwise, we show the last entry in the back stack (our FragmentToShow)
if(childFragmentManager.getBackStackEntryCount() == 0){
super.onBackPressed();
} else {
childFragmentManager.popBackStack();
}
}
由于我们在活动中调用了getSupportFragmentManager,我们只能在子片段中调用getFragmentManager。这将返回一个支持FragmentManager实例。
就是这样!我不是专家,所以如果你有建议或评论,请随意。
答案 2 :(得分:3)
我发现实现这一目标的唯一方法是执行以下操作:
导航离开viewPager时,使用Visiblity.GONE将viewPager发送出视图。将任何片段事务添加到Backstack。
当返回viewPager屏幕时(通过背面按下),覆盖onBackPressed。您可以查看Backstack中有多少片段。如果viewPager是片段事务发生之前的第一个视图,那么您可以检查片段backstack条目计数是否为0。
fragmentManager.getBackStackEntryCount()== 0,Backstack中没有片段。
如果该陈述为真,那么只需使用Visibility.VISIBLE将viewPager重新置于视图中。
答案 3 :(得分:0)
如果您使用的ViewPager
Fragments
可以Activities
启动ViewPager
,则可以通过以下方式正确导航回Activity
中的位置或者从Activities
导航起来(假设您为ViewPager
宣布了向上导航)。
首先,您需要在Intent
中将Activity
的当前位置作为额外内容传递,以启动新的Activity
。
然后你会将这个位置传回给父Intent upIntent = NavUtils.getParentActivityIntent(this);
upIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
upIntent.putExtra(FeedPagerActivity.EXTRA_POSITION, position);
NavUtils.navigateUpTo(this, upIntent);
这样做:
{{1}}
将该代码放在
中onOptionsItemSelected(MenuItem item)
答案 4 :(得分:0)
我想我遇到了类似的问题。
似乎FragmentManager
的行为有点分层。我解决这个问题的方法是使用活动中的“main”FragmentManager,它托管容器和ViewPager,而不是可以从ViewPager内部的片段中检索的那个。
要做到这一点,我用过:
this.getActivity().getSupportFragmentManager()
其中this
是Fragment的一个实例。
现在,如果我从ViewPager中的项目导航到具有“替换”事务的其他片段,则在返回时我可以看到处于我离开状态的ViewPager。
更完整的代码示例如下所示:
FragmentManager fragmentManager = MyCurrentFragment.this.getActivity().getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);
transaction.commit();