在ViewPager中将一个片段替换为另一个片段

时间:2013-09-03 09:41:27

标签: android listview android-fragments android-viewpager

当我尝试将Fragment替换为ViewPager中的另一个ViewPager时,我遇到了一些问题。

现状

我有Fragment个3页,每个页面都是ListView。在第一页中,我在ListFragment(“FacturasFragment”)中有一个onListItemClick。当我点击该列表中的某个项目时,我使用ListFragment方法来处理该事件。

我想要什么

  • 单击列表项时,我想将Fragment(包含发票列表)替换为另一个Button(“DetallesFacturaFragment”,包含发票的详细信息)。
  • 当我在“DetallesFacturaFragment”中并按“返回ListFragment时,应返回Fragment
  • 页面之间的滚动不应更改第一个页面中显示的public class TabsFacturasActivity extends SherlockFragmentActivity { private MyAdapter mAdapter; private ViewPager mPager; private PageIndicator mIndicator; @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); mIndicator = (TitlePageIndicator)findViewById(R.id.indicator); mIndicator.setViewPager(mPager); } private static class MyAdapter extends FragmentPagerAdapter { private String[] titles = { "VER FACTURAS", "VER CONSUMO", "INTRODUCIR LECTURA" }; private final FragmentManager mFragmentManager; private Fragment mFragmentAtPos0; private Context context; public MyAdapter(FragmentManager fragmentManager) { super(fragmentManager); mFragmentManager = fragmentManager; } @Override public CharSequence getPageTitle(int position) { return titles[position]; } @Override public Fragment getItem(int position) { switch (position) { case 0: // Fragment # 0 return new FacturasFragment(); case 1: // Fragment # 1 return new ConsumoFragment(); case 2:// Fragment # 2 return new LecturaFragment(); } return null; } @Override public int getCount() { return titles.length; } @Override public int getItemPosition(Object object) { if (object instanceof FacturasFragment && mFragmentAtPos0 instanceof DetallesFacturaFragment) return POSITION_NONE; return POSITION_UNCHANGED; } } } 。如果我在第一页上有“DetallesFacturaFragment”并滚动到第二页,当返回第一页时应继续显示“DetallesFacturaFragment”。

代码

FragmentActivity

public class FacturasFragment extends ListFragment {

    private ListView lista;

    private ArrayList<TuplaFacturaWS> facturas;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);    
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.activity_facturas, container, false);
        facturas = myApplication.getFacturas();

        lista = (ListView) view.findViewById(id.list);

        MyAdapter myAdaptador = new MyAdapter(this, facturas);
        setListAdapter(myAdaptador);

        return view;
    }

    public void onListItemClick (ListView l, View v, int position, long id) {
        myApplication.setFacturaActual(position);
        mostrarDatosFactura();
    }


    private void mostrarDatosFactura() {
        final DetallesFacturaFragment fragment = new DetallesFacturaFragment();
        FragmentTransaction transaction = null;
        transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.pager, fragment); //id of ViewPager
        transaction.addToBackStack(null);
        transaction.commit();
    }

    private class MyAdapter extends BaseAdapter {
        private final FacturasFragment actividad;
        private final ArrayList<TuplaFacturaWS> facturas;

        public MyAdapter(FacturasFragment facturasActivity, ArrayList<TuplaFacturaWS> facturas) {
            super();
            this.actividad = facturasActivity;
            this.facturas = facturas;
        }

        @Override
        public View getView(int position, View convertView, 
                ViewGroup parent) {
            LayoutInflater inflater = actividad.getLayoutInflater(null);
            View view = inflater.inflate(R.layout.list_row, null, true);
            //Set data to view
            return view;
        }

        @Override
        public int getCount() {
            return facturas.size();
        }

        @Override
        public Object getItem(int pos) {
            return facturas.get(pos);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        private OnClickListener checkListener = new OnClickListener()
        {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub

            }

        };
    }
}

ListFragment

public class DetallesFacturaFragment extends SherlockFragment {

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);    
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.activity_factura, container, false);

        //Set data to view

        return view;
    }
}

片段

onCreateView

目前,当我点击列表项时,第一页会出现白色视图。我已经验证并执行了“DetallesFacturaFragment”的{{1}}方法,但该页面上没有任何内容。

我第一次点击列表项时,会显示白屏。但回到列表后,我必须单击两次以显示白屏的列表项。

我一直在谷歌搜索并查看了一些问题,但找不到任何人用完成的代码解决。

3 个答案:

答案 0 :(得分:47)

花了这么多时间后,我在that answer找到了修改代码的正确解决方案。

它会将Fragment的第一页中的ViewPager替换为另一个Fragment,如果您从第二个Fragment返回,则会正确显示第一个Fragment。与第一页中显示的Fragment无关,如果您从一个页面滑动到另一个页面,则不会更改其public class TabsFacturasActivity extends SherlockFragmentActivity { public void onBackPressed() { if(mPager.getCurrentItem() == 0) { if (mAdapter.getItem(0) instanceof DetallesFacturaFragment) { ((DetallesFacturaFragment) mAdapter.getItem(0)).backPressed(); } else if (mAdapter.getItem(0) instanceof FacturasFragment) { finish(); } } } private static class MyAdapter extends FragmentPagerAdapter { private final class FirstPageListener implements FirstPageFragmentListener { public void onSwitchToNextFragment() { mFragmentManager.beginTransaction().remove(mFragmentAtPos0) .commit(); if (mFragmentAtPos0 instanceof FacturasFragment){ mFragmentAtPos0 = new DetallesFacturaFragment(listener); }else{ // Instance of NextFragment mFragmentAtPos0 = new FacturasFragment(listener); } notifyDataSetChanged(); } } private String[] titles = { "VER FACTURAS", "VER CONSUMO", "INTRODUCIR LECTURA" }; private final FragmentManager mFragmentManager; public Fragment mFragmentAtPos0; private Context context; FirstPageListener listener = new FirstPageListener(); public MyAdapter(FragmentManager fragmentManager) { super(fragmentManager); mFragmentManager = fragmentManager; } @Override public CharSequence getPageTitle(int position) { return titles[position]; } @Override public Fragment getItem(int position) { switch (position) { case 0: // Fragment # 0 if (mFragmentAtPos0 == null) { mFragmentAtPos0 = new FacturasFragment(listener); } return mFragmentAtPos0; case 1: // Fragment # 1 return new ConsumoFragment(); case 2:// Fragment # 2 return new LecturaFragment(); } return null; } @Override public int getCount() { return titles.length; } @Override public int getItemPosition(Object object) { if (object instanceof FacturasFragment && mFragmentAtPos0 instanceof DetallesFacturaFragment) { return POSITION_NONE; } if (object instanceof DetallesFacturaFragment && mFragmentAtPos0 instanceof FacturasFragment) { return POSITION_NONE; } return POSITION_UNCHANGED; } } }

这是我的代码:

FragmentActivity

public interface FirstPageFragmentListener {
    void onSwitchToNextFragment();
}

FirstPageFragmentListener

public class FacturasFragment extends ListFragment implements FirstPageFragmentListener {

    static FirstPageFragmentListener firstPageListener;

    public FacturasFragment() {
    }

    public FacturasFragment(FirstPageFragmentListener listener) {
        firstPageListener = listener;
    }

    public void onListItemClick (ListView l, View v, int position, long id) {
        firstPageListener.onSwitchToNextFragment();
    }
}

FacturasFragment (FirstFragment)

public class DetallesFacturaFragment extends SherlockFragment {

    static FirstPageFragmentListener firstPageListener;

    public DetallesFacturaFragment() {
    }

    public DetallesFacturaFragment(FirstPageFragmentListener listener) {
        firstPageListener = listener;
    }

    public void backPressed() {
        firstPageListener.onSwitchToNextFragment();
    }
}

DetallesFacturaFragment (SecondFragment)

{{1}}

答案 1 :(得分:0)

解决Android建议不使用非默认构造函数的小问题。您应该将构造函数更改为以下内容:

在FacturasFragment中:

 public static FacturasFragment createInstance(FirstPageFragmentListener listener) {
    FacturasFragment facturasFragment = new FacturasFragment(); 
    facturasFragment.firstPageListener = listener;
    return facturasFragment;
 }

然后你可以从getItem函数中调用它:

 mFragmentAtPos0 = FacturasFragment.createInstance(listener);

在DetallesFacturaFragment中:

 public static DetallesFacturaFragment createInstance(FirstPageFragmentListener listener) {
    DetallesFacturaFragment detallesFacturaFragment= new DetallesFacturaFragment(); 
    detallesFacturaFragment.firstPageListener = listener;
    return detallesFacturaFragment;
 }

然后你可以从FirstPageListener.onSwitchToNextFragment()函数中调用它:

 mFragmentAtPos0 = DetallesFacturaFragment.createInstance(listener);

答案 2 :(得分:0)

我发现了两种方法来替换viewpager中的片段。

方法1:通过更新ViewPagerAdapter 方式2:使用根片段

方式1: 这样,我们需要从viewpager适配器的片段列表中更新片段,并通知片段有关更改。 例如:

  private void changefragment(int position) {
        Fragment newFragment = CategoryPostFragment.newInstance();
        adapter.fragments.set(position, newFragment);
        adapter.notifyDataSetChanged();
        viewPager.setCurrentItem(position);

    }

这是为此的viewpager适配器代码

import java.util.List;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.PagerAdapter;

import com.trickbd.trickbdapp.ui.activity.homeactivity.fragments.FavFragment;
import com.trickbd.trickbdapp.ui.activity.homeactivity.fragments.HomePostFragment;

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
    public List<Fragment> fragments;

    public ViewPagerAdapter(FragmentManager manager, List<Fragment> fragments) {
        super(manager);
        this.fragments = fragments;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        if (fragments.get(position)!=null){
            return fragments.get(position);
        }else {
            if (position==0){
                return new HomePostFragment();
            }else {
                return new FavFragment();
            }
        }

    }

    @Override
    public int getCount() {
        return fragments.size();
    }

    //method to add fragment
    public void addFragment(Fragment fragment) {
        fragments.add(fragment);
    }


    @Override
    public int getItemPosition(@NonNull Object object) {
        if (object instanceof FavFragment) {
            return POSITION_UNCHANGED; // don't force a reload
        } else {
            // POSITION_NONE means something like: this fragment is no longer valid
            // triggering the ViewPager to re-build the instance of this fragment.
            return POSITION_NONE;
        }
    }

}

我在这段代码上做得很好。当api 28中不推荐使用FragmentStatePagerAdapter的super(manager)方法时,我会感到担心。 当我使用“ super(manager,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);”时连同替换碎片的第一种方法,应用程序会在运行时崩溃。

还有一个回想,当我们从viewpager适配器中调用adapter.notifydatasetchanged()时效率不高。当我们尝试仅更改特定片段时,它将重新创建整个viewpager。

所以,解决所有问题的方法都不是第二种。

方式2: 在不将实际片段添加到viewpager的情况下,我们应该将根片段添加到viewpager。在根片段中将添加实际的片段(以前我们在viewpager中添加了。然后,无需FragmentStatePagerAdapter的帮助,我们就可以轻松替换任何片段。 根片段的代码:

Rootfragment.java

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentTransaction;

import com.trickbd.trickbdapp.R;

import dagger.android.support.DaggerFragment;

public class RootFragment extends DaggerFragment {
    public RootFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.root_layout, container, false);
        if (getFragmentManager() != null) {
            FragmentTransaction transaction = getFragmentManager()
                    .beginTransaction();
            transaction.replace(R.id.root_frame, new HomePostFragment());

            transaction.commit();
        }

        return view;

    }
}

root_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/root_frame">

</FrameLayout>

因此以前的替换代码将如下更新

private void changefragment(int position) {
        Fragment newFragment = CategoryPostFragment.newInstance();
        replacefragment(newFragment);
        viewPager.setCurrentItem(position);

    }

public void replacefragment(Fragment fragment){
        getSupportFragmentManager();
        FragmentTransaction trans = getSupportFragmentManager()
                .beginTransaction();
        trans.replace(R.id.root_frame, fragment);
        trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        trans.addToBackStack(null);
        trans.commit();
    }

通过这种方式,我们可以更高效地替换片段。

要获取根片段中当前添加的片段,我们可以使用此代码。

if (getSupportFragmentManager().findFragmentById(R.id.root_frame) instanceof HomePostFragment){
            HomePostFragment postFragment = (HomePostFragment) getSupportFragmentManager().findFragmentById(R.id.root_frame);

 }

您可能会详细了解此here