替换片段A ViewPager内 [英] Replace Fragment inside a ViewPager
问题描述
我试图用FragmentPagerAdapter使用片段与ViewPager。 我正在寻找的实现是更换一个片段,定位在ViewPager的第一页,用一个又一个。
寻呼机由两页组成。第一个是FirstPagerFragment,第二个是SecondPagerFragment。点击的第一页的一个按钮。我想,以取代与NextFragment的FirstPagerFragment。
下面有我的code。
公共类FragmentPagerActivity扩展FragmentActivity {
静态最终诠释NUM_ITEMS = 2;
MyAdapter mAdapter;
ViewPager mPager;
@覆盖
保护无效的onCreate(包savedInstanceState){
super.onCreate(savedInstanceState);
的setContentView(R.layout.fragment_pager);
mAdapter =新MyAdapter(getSupportFragmentManager());
mPager =(ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
/ **
*寻呼机适配器
* /
公共静态类MyAdapter扩展FragmentPagerAdapter {
公共MyAdapter(FragmentManager FM){
超(FM);
}
@覆盖
公众诠释getCount将(){
返回NUM_ITEMS;
}
@覆盖
公共片段的getItem(INT位置){
如果(位置== 0){
返回FirstPageFragment.newInstance();
} 其他 {
返回SecondPageFragment.newInstance();
}
}
}
/ **
*第二个页面片段
* /
公共静态类SecondPageFragment扩展片段{
公共静态SecondPageFragment的newInstance(){
SecondPageFragment F =新SecondPageFragment();
返回F;
}
@覆盖
公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
//Log.d("DEBUG,onCreateView);
返回inflater.inflate(R.layout.second,集装箱,假);
}
}
/ **
*第一页面片段
* /
公共静态类FirstPageFragment扩展片段{
Button按钮;
公共静态FirstPageFragment的newInstance(){
FirstPageFragment F =新FirstPageFragment();
返回F;
}
@覆盖
公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
//Log.d("DEBUG,onCreateView);
查看根= inflater.inflate(R.layout.first,集装箱,假);
按钮=(按钮)root.findViewById(R.id.button);
button.setOnClickListener(新OnClickListener(){
@覆盖
公共无效的onClick(视图v){
FragmentTransaction反= getFragmentManager()的BeginTransaction()。
trans.replace(R.id.first_fragment_root_id,NextFragment.newInstance());
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(空);
trans.commit();
}
});
返回根;
}
/ **
*在第一页下页片段
* /
公共静态类NextFragment扩展片段{
公共静态NextFragment的newInstance(){
NextFragment F =新NextFragment();
返回F;
}
@覆盖
公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
//Log.d("DEBUG,onCreateView);
返回inflater.inflate(R.layout.next,集装箱,假);
}
}
}
...这里的XML文件
fragment_pager.xml
< XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=http://schemas.android.com/apk/res/android
机器人:方向=垂直机器人:填充=4dip
机器人:重力=center_horizontal
机器人:layout_width =match_parent机器人:layout_height =match_parent>
< android.support.v4.view.ViewPager
机器人:ID =@ + ID /寻呼机
机器人:layout_width =match_parent
机器人:layout_height =match_parent
机器人:layout_weight =1>
< /android.support.v4.view.ViewPager>
< / LinearLayout中>
first.xml
< XML版本=1.0编码=UTF-8&GT?;
< LinearLayout中的xmlns:机器人=http://schemas.android.com/apk/res/android
机器人:ID =@ + ID / first_fragment_root_id
机器人:方向=垂直
机器人:layout_width =match_parent
机器人:layout_height =match_parent>
<按钮机器人:ID =@ + ID /按钮
机器人:layout_width =WRAP_CONTENT机器人:layout_height =WRAP_CONTENT
机器人:文本=下一个/>
< / LinearLayout中>
现在的问题...我应该在
使用的ID trans.replace(R.id.first_fragment_root_id,NextFragment.newInstance());
如果我用R.id.first_fragment_root_id,更换工作,但层次查看器显示一个奇怪的现象,如下图所示。
目前的开头的情况
更换后的情况是
正如你所看到的有什么不对,我希望找到后,我更换片段显示为第一张照片相同的状态。
目前,这并不需要修改 ViewPager
来源$ C $ c和<$另一种解决方案C $ C> FragmentStatePagerAdapter ,以及它的工作原理与使用人提供的 FragmentPagerAdapter
基类。
我想先回答笔者的了解,他应该使用的标识问题;它是容器的ID,即图寻呼机本身的ID。然而,正如你可能已经注意到自己,使用该ID在code使任何事情发生。我将解释为什么:
首先,使 ViewPager
重新填充的网页,您需要调用 notifyDataSetChanged()
驻留在基类的适配器。
其次, ViewPager
使用 getItemPosition()
抽象的方法来检查哪些网页应该被销毁,这应该是保留。此函数的默认实现总是返回 POSITION_UNCHANGED
,这将导致 ViewPager
来保存所有当前的页面,因此没有附加的新的一页。因此,为了使片段置换工作, getItemPosition()
需要在你的适配器被覆盖,并且不能返回 POSITION_NONE
调用时有一个古老的,被隐藏,片段作为参数。</ P>
这也意味着你的适配器,总是需要知道,应该显示在位置0, FirstPageFragment
或 NextFragment $其中片段C $ C>。这样做的一个方法是创建
FirstPageFragment
,当它是时候切换片段将被调用时提供的监听器。我觉得这是一件好事,但是,让你的片段适配器处理所有片段交换机和调用 ViewPager
和 FragmentManager
三, FragmentPagerAdapter
缓存使用的片段通过它是从位置导出,所以,如果有一个片段在位置0名称,则它不会被即使更换这个类是新的。有两个解决方案,但最简单的方法是使用 FragmentTransaction
的删除()
的功能,这将删除其标签为好。
这是一个大量的文字,这里是code应该在你的情况是:
公共类MyAdapter扩展FragmentPagerAdapter
{
静态最终诠释NUM_ITEMS = 2;
私人最终FragmentManager mFragmentManager;
私人片段mFragmentAtPos0;
公共MyAdapter(FragmentManager FM)
{
超(FM);
mFragmentManager = FM;
}
@覆盖
公共片段的getItem(INT位置)
{
如果(位置== 0)
{
如果(mFragmentAtPos0 == NULL)
{
mFragmentAtPos0 = FirstPageFragment.newInstance(新FirstPageFragmentListener()
{
公共无效onSwitchToNextFragment()
{
。mFragmentManager.beginTransaction()删除(mFragmentAtPos0).commit();
mFragmentAtPos0 = NextFragment.newInstance();
notifyDataSetChanged();
}
});
}
返回mFragmentAtPos0;
}
其他
返回SecondPageFragment.newInstance();
}
@覆盖
公众诠释getCount将()
{
返回NUM_ITEMS;
}
@覆盖
公众诠释getItemPosition(Object对象)
{
如果(的instanceof FirstPageFragment和放大器的对象;&安培; mFragmentAtPos0的instanceof NextFragment)
返回POSITION_NONE;
返回POSITION_UNCHANGED;
}
}
公共接口FirstPageFragmentListener
{
无效onSwitchToNextFragment();
}
希望这可以帮助任何人!
I'm trying to use Fragment with a ViewPager using the FragmentPagerAdapter. What I'm looking for to achieve is to replace a fragment, positioned in the first page of the ViewPager, with another one.
The pager is composed by two pages. The first one is the FirstPagerFragment, the second one is the SecondPagerFragment. Clicking on a button of the first page. I'd like to to replace the FirstPagerFragment with the NextFragment.
There is my code below.
public class FragmentPagerActivity extends FragmentActivity {
static final int NUM_ITEMS = 2;
MyAdapter mAdapter;
ViewPager mPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pager);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
/**
* Pager Adapter
*/
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
if(position == 0) {
return FirstPageFragment.newInstance();
} else {
return SecondPageFragment.newInstance();
}
}
}
/**
* Second Page FRAGMENT
*/
public static class SecondPageFragment extends Fragment {
public static SecondPageFragment newInstance() {
SecondPageFragment f = new SecondPageFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
return inflater.inflate(R.layout.second, container, false);
}
}
/**
* FIRST PAGE FRAGMENT
*/
public static class FirstPageFragment extends Fragment {
Button button;
public static FirstPageFragment newInstance() {
FirstPageFragment f = new FirstPageFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
View root = inflater.inflate(R.layout.first, container, false);
button = (Button) root.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
trans.addToBackStack(null);
trans.commit();
}
});
return root;
}
/**
* Next Page FRAGMENT in the First Page
*/
public static class NextFragment extends Fragment {
public static NextFragment newInstance() {
NextFragment f = new NextFragment();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Log.d("DEBUG", "onCreateView");
return inflater.inflate(R.layout.next, container, false);
}
}
}
...and here the xml files
fragment_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
</LinearLayout>
first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/first_fragment_root_id"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/button"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="to next"/>
</LinearLayout>
Now the problem... which ID should I use in
trans.replace(R.id.first_fragment_root_id, NextFragment.newInstance());
?
If I use R.id.first_fragment_root_id, the replacement works, but Hierarchy Viewer shows a strange behavior, as below.
At the beginning the situation is
after the replacement the situation is
As you can see there is something wrong, I expect to find the same state shown as in the first picture after I replace the fragment.
There is another solution that does not need modifying the source code of ViewPager
and FragmentStatePagerAdapter
, and it works with the FragmentPagerAdapter
base class that was used by the author.
I'd like to start by answering the author's question about which ID he should use; it is the ID of the container, i.e. the ID of the view pager itself. However, as you probably noticed yourself, using that ID in your code causes nothing to happen. I will explain why:
First of all, to make ViewPager
repopulate the pages, you need to call notifyDataSetChanged()
that resides in the base class of your adapter.
Second, ViewPager
uses the getItemPosition()
abstract method to check which pages should be destroyed and which should be kept. The default implementation of this function always returns POSITION_UNCHANGED
, which causes ViewPager
to keep all current pages, and consequently not attaching your new page. Thus, to make fragment replacement work, getItemPosition()
needs to be overridden in your adapter and must return POSITION_NONE
when called with an old, to be hidden, fragment as argument.
This also means that your adapter always needs to be aware of which fragment that should be displayed in position 0, FirstPageFragment
or NextFragment
. One way of doing this is supplying a listener when creating FirstPageFragment
, which will be called when it is time to switch fragments. I think this is a good thing though, to let your fragment adapter handle all fragment switches and calls to ViewPager
and FragmentManager
.
Third, FragmentPagerAdapter
caches the used fragments by a name which is derived from the position, so if there was a fragment at position 0, it will not be replaced even though the class is new. There are two solutions, but the simplest is to use the remove()
function of FragmentTransaction
, which will remove its tag as well.
That was a lot of text, here is code that should work in your case:
public class MyAdapter extends FragmentPagerAdapter
{
static final int NUM_ITEMS = 2;
private final FragmentManager mFragmentManager;
private Fragment mFragmentAtPos0;
public MyAdapter(FragmentManager fm)
{
super(fm);
mFragmentManager = fm;
}
@Override
public Fragment getItem(int position)
{
if (position == 0)
{
if (mFragmentAtPos0 == null)
{
mFragmentAtPos0 = FirstPageFragment.newInstance(new FirstPageFragmentListener()
{
public void onSwitchToNextFragment()
{
mFragmentManager.beginTransaction().remove(mFragmentAtPos0).commit();
mFragmentAtPos0 = NextFragment.newInstance();
notifyDataSetChanged();
}
});
}
return mFragmentAtPos0;
}
else
return SecondPageFragment.newInstance();
}
@Override
public int getCount()
{
return NUM_ITEMS;
}
@Override
public int getItemPosition(Object object)
{
if (object instanceof FirstPageFragment && mFragmentAtPos0 instanceof NextFragment)
return POSITION_NONE;
return POSITION_UNCHANGED;
}
}
public interface FirstPageFragmentListener
{
void onSwitchToNextFragment();
}
Hope this helps anyone!
这篇关于替换片段A ViewPager内的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!