Fragment
をViewPager
の別のViewPager
と交換しようとすると、いくつかの問題が発生します。
現在の状況
3ページのFragment
があり、それぞれがListView
です。最初のページでは、ListFragment
( "FacturasFragment")内にonListItemClick
があります。そのリストの項目をクリックすると、そのイベントを処理するためにListFragment
メソッドを使用します。
私が欲しいもの
Fragment
(請求書のリストを含む)を別のButton
(「DetallesFacturaFragment」、請求書の詳細を含む)に置き換えます。ListFragment
]に戻ります。Fragment
は変更されません。最初のページに「DetallesFacturaFragment」があり、2番目のページにスクロールしている場合、最初のページに戻ると「DetallesFacturaFragment」が引き続き表示されます。コード
FragmentActivity
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;
}
}
}
ListFragment
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
}
};
}
}
フラグメント
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;
}
}
現時点では、リスト項目をクリックすると、最初のページに白いビューが表示されます。 「DetallesFacturaFragment」のonCreateView
メソッドを確認しましたが、そのページには何も表示されません。
リスト項目をクリックすると、白い画面が表示されます。しかし、リストに戻った後、白い画面を表示するにはリスト項目を2回クリックする必要があります。
私はグーグルでいくつかの質問を見てきましたが、完成したコードで解決できる人は見つかりませんでした。
何時間も費やした後、 その答え でコードを修正する正しいソリューションを見つけました。
Fragment
の最初のページのViewPager
を別のページに置き換えます。2番目のFragment
から戻ると、最初のFragment
が正しく表示されます。最初のページに表示されるFragment
は重要ではありません。あるページから別のページにスワイプしても、そのFragment
は変更されません。
ここに私のコードがあります:
FragmentActivity
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;
}
}
}
FirstPageFragmentListener
public interface FirstPageFragmentListener {
void onSwitchToNextFragment();
}
FacturasFragment(FirstFragment)
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();
}
}
DetallesFacturaFragment(SecondFragment)
public class DetallesFacturaFragment extends SherlockFragment {
static FirstPageFragmentListener firstPageListener;
public DetallesFacturaFragment() {
}
public DetallesFacturaFragment(FirstPageFragmentListener listener) {
firstPageListener = listener;
}
public void backPressed() {
firstPageListener.onSwitchToNextFragment();
}
}
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つの方法を見つけました。
方法1:ViewPagerAdapterを更新する方法2:ルートフラグメントを使用する方法
Way1:このようにして、ビューページャーアダプタのフラグメントリストからフラグメントを更新し、変更についてフラグメントに通知する必要があります。例えば:
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;
}
}
}
私はこのコードでうまくやっていた。 FragmentStatePagerAdapterのsuper(manager)メソッドがAPI 28で非推奨になると心配になります。「super(manager、BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);」を使用するとフラグメントを置き換える最初の方法とともに、実行時にアプリケーションがクラッシュします。
また、viewpagerアダプターからadapter.notifydatasetchanged()を呼び出したときに効率的ではないという逆描画もあります。特定のフラグメントのみを変更しようとしている間に、ビューページャー全体を再作成しています。
だから、すべての問題の解決策と一緒に2はありません。
方法2:実際のフラグメントをビューページャーに追加せずに、ルートフラグメントをビューページャーに追加する必要があります。ルートフラグメントには、実際のフラグメントが追加されます(以前はビューページャーに追加しました。その後、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();
}
この方法により、フラグメントをより効率的に置き換えることができます。
Rootfragmentに現在追加されているフラグメントを取得するには、このコードを使用できます。
if (getSupportFragmentManager().findFragmentById(R.id.root_frame) instanceof HomePostFragment){
HomePostFragment postFragment = (HomePostFragment) getSupportFragmentManager().findFragmentById(R.id.root_frame);
}
詳細についてはこちらをご覧ください こちら