Lấy phiên bản Fragment hiện tại trong viewpager


210

Dưới đây là mã của tôi, 3 Fragment classesmỗi mã được nhúng với mỗi trong số 3 tab trên ViewPager. Tôi có một tùy chọn menu. Như được hiển thị trong onOptionsItemSelected(), bằng cách chọn một tùy chọn, tôi cần cập nhật đoạn hiện đang hiển thị. Để cập nhật rằng tôi phải gọi một phương thức trong lớp phân đoạn. Ai đó có thể đề nghị làm thế nào để gọi phương pháp đó?

public class MainActivity  extends ActionBarActivity {

     ViewPager ViewPager;
     TabsAdapter TabsAdapter;

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

            ViewPager = new ViewPager(this);
            ViewPager.setId(R.id.pager);
            setContentView(ViewPager);

            final ActionBar bar = getSupportActionBar();

            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            //Attaching the Tabs to the fragment classes and setting the tab title.
            TabsAdapter = new TabsAdapter(this, ViewPager);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
                    FragmentClass1.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
              FragmentClass2.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
              FragmentClass3.class, null);


            if (savedInstanceState != null) {
                bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
            }

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

            case R.id.addText:

           **// Here I need to call the method which exists in the currently visible Fragment class**

                    return true;

            }

            return super.onOptionsItemSelected(item);
        }


     @Override
     protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
            outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());

     }

     public static class TabsAdapter extends FragmentPagerAdapter
      implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

      private final Context mContext;
            private final ActionBar mActionBar;
            private final ViewPager mViewPager;
            private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

            static final class TabInfo {
                private final Class<?> clss;
                private final Bundle args;

                TabInfo(Class<?> _class, Bundle _args) {
                    clss = _class;
                    args = _args;
                }
            }

      public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
       super(activity.getSupportFragmentManager());
                mContext = activity;
                mActionBar = activity.getSupportActionBar();
                mViewPager = pager;
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
            }

      public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
                TabInfo info = new TabInfo(clss, args);
                tab.setTag(info);
                tab.setTabListener(this);
                mTabs.add(info);
                mActionBar.addTab(tab);
                notifyDataSetChanged();

            }

      @Override
      public void onPageScrollStateChanged(int state) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageSelected(int position) {
       // TODO Auto-generated method stub
       mActionBar.setSelectedNavigationItem(position);
      }

      @Override
      public void onTabReselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onTabSelected(Tab tab, FragmentTransaction ft) {
       Object tag = tab.getTag();
                for (int i=0; i<mTabs.size(); i++) {
                    if (mTabs.get(i) == tag) {
                        mViewPager.setCurrentItem(i);

                    }
                }

                tabPosition = tab.getPosition();
      }

      @Override
      public void onTabUnselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public Fragment getItem(int position) {
       TabInfo info = mTabs.get(position);
                return Fragment.instantiate(mContext, info.clss.getName(), info.args);
      }

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

     }

    }

Giả sử bên dưới là lớp phân đoạn với phương thức updateList()tôi muốn gọi:

 public class FragmentClass1{

    ArrayList<String> originalData;


    @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container,
           Bundle savedInstanceState) {

          View fragmentView = inflater.inflate(R.layout.frag1, container, false);

          originalData = getOriginalDataFromDB();

          return fragmentView;

         }


    public void updateList(String text)
    {
       originalData.add(text);
       //Here I could do other UI part that need to added
    }
}

bạn muốn gọi phương thức phân đoạn nào?
Biraj Zalavadia

@BirajZalavadia Phương thức được xác định riêng của tôi, có một tham số trong đó và sử dụng các biến thể hiện của lớp phân đoạn đó đã được khởi tạo trong khi tạo ra một khung nhìn.
rick

1
bạn có thể cung cấp tên Class của các mảnh vỡ của bạn trong viewpager không?
Biraj Zalavadia


Cách đơn giản nhất để truy cập vào các mảnh có thể nhìn thấy sẽ là thông qua stackoverflow.com/questions/7379165/ , hãy nhìn vào hai câu trả lời hàng đầu.
Luksprog

Câu trả lời:


205

bằng cách chọn một tùy chọn, tôi cần cập nhật đoạn hiện đang hiển thị.

Một cách đơn giản để làm điều này là sử dụng một mẹo liên quan đến việc FragmentPagerAdapterthực hiện:

case R.id.addText:
     Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
     // based on the current position you can then cast the page to the correct 
     // class and call the method:
     if (ViewPager.getCurrentItem() == 0 && page != null) {
          ((FragmentClass1)page).updateList("new item");     
     } 
return true;

Vui lòng suy nghĩ lại quy ước đặt tên biến của bạn, sử dụng làm tên biến, tên của lớp rất khó hiểu (vì vậy không ViewPager ViewPager, sử dụng ViewPager mPagerchẳng hạn).


23
Thẻ đó có phải là bằng chứng trong tương lai không, nếu API thay đổi?
Maarten

7
@Maarten Không, đó chỉ là một hack phổ biến đã được sử dụng kể từ khi bộ điều hợp xuất hiện (và mã nguồn của nó đã có sẵn), nó vẫn chưa thay đổi. Nếu bạn muốn một cái gì đó đáng tin cậy hơn, bạn sẽ cần sử dụng các tùy chọn khác, đáng chú ý nhất là ghi đè instantiateItem()phương thức và tự mình tham khảo các đoạn thích hợp.
Luksprog

5
Sau nhiều giờ thất vọng và hỏi các trang trực tiếp từ mAdapter.getItem(position), tuyệt vời ... Ít nhất bây giờ tôi biết rằng 8512 thử nghiệm khác đã không hoạt động. Cảm ơn
Diolor

29
Lưu ý rằng điều này không hoạt động nếu bạn sử dụng FragmentStatePagerAd CHƯƠNG chứ không phải FragmentPagerAd CHƯƠNG.
Shawn Lauzon

3
@ShawnLauzon FragmentStatePagerAd CHƯƠNG có một cách triển khai khác, trong trường hợp của bạn, bạn gọi phương thức InstantiateItem () của nó để lấy các đoạn có thể nhìn thấy.
Luksprog

155
    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }

28
Google nên cung cấp FragmentPageAd Module.getCienPrimaryItem () trả lại mCienPrimaryItem.
eugene

1
Tôi cũng sử dụng kỹ thuật này. Tôi cũng xác định PagerFragment với các phương thức onPageSelected/ onPageDeselectedvà có tất cả các đoạn máy nhắn tin của tôi mở rộng nó. Sau đó setPrimaryitemcó thể gọi các phương thức này một cách thích hợp khi người dùng vuốt sang một trang mới. Điều này có nghĩa là bạn có thể thực hiện chiến lược lười biếng hơn để tải dữ liệu trong các trang thậm chí không được hiển thị. Tuy nhiên, bạn nên nhớ rằng trong quá trình chuyển trang, có vẻ tốt hơn nếu trang tiếp theo đã được điền dữ liệu, do đó, việc lười tải tất cả dữ liệu vào onPageSelectedcó thể không lý tưởng.
JHH

3
Tại sao iftuyên bố? Đoạn chỉ gọi đến equalsphương thức của đối tượng, đó là so sánh nông. Vậy tại sao không chỉ luôn gọi mCurrentFragment = ((Fragment) object);?
Overclover

đã thử và nó hoạt động tốt, chỉ cần sử dụng getCienFragment () cho Fragment cụ thể cần có
PhilipJ

113

Trước hết hãy theo dõi tất cả các trang phân đoạn "hoạt động". Trong trường hợp này, bạn theo dõi các trang phân đoạn trong FragmentStatePagerAd CHƯƠNG, được ViewPager sử dụng.

@Override
public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

Để tránh giữ tham chiếu đến các trang phân đoạn "không hoạt động", bạn cần triển khai phương thức killItem (...) của FragmentStatePagerAd Module: ...

@Override
public void destroyItem (ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    mPageReferenceMap.remove(position);
}

và khi bạn cần truy cập trang hiện đang hiển thị, sau đó bạn gọi:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

Trường hợp phương thức getFragment (int) của MyAdOG trông như thế này:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

Hy vọng nó có thể giúp!


Bạn có thể vui lòng giải thích rõ ràng? Tôi cần giữ lớp FragmentStatePagerAd CHƯƠNG này ở đâu trong mã của mình? BTW Tôi có 3 lớp phân đoạn, không phải MyFragmentClass đơn.
rick

7
Thậm chí tốt hơn nếu bạn cập nhật mPageReferenceMap trong InstantiateItem thay vì getItem vì nó cũng hoạt động sau khi thay đổi hướng. '@Override công khai Đối tượng tức thờiItem (Container Viewgroup, vị trí int) {Fragment Fragment = (Fragment) Super.instantiateItem (container, vị trí); mPageReferenceMap.put (vị trí, đoạn); trả lại mảnh vỡ; } '
pmellaaho

Loại nào là mPageReferenceMap?
DoruAdryan

10
Câu trả lời này thực sự rất tệ! Bạn không nên giữ bộ đệm của ViewPager theo cách thủ công vì nó tự xử lý nó. ViewPager quyết định khi nào phân bổ nên phân bổ hay không, tạm dừng cái gì và khi nào, giữ một tham chiếu trên mỗi phân đoạn sẽ thêm một số chi phí vô dụng và không được tối ưu hóa cho bộ nhớ.
Livio

3
Tôi đã thử phương pháp này nhưng không may là nó không hoạt động khi hoạt động được tạo lại. Trên Android N trở lên, bạn có thể thấy điều này khi sử dụng tính năng multiwindow. Khi ứng dụng của bạn mở, hãy giữ nút 'lõm' (hình vuông). Hoạt động và đoạn được tạo lại từ saveInstanceState, bộ điều hợp được tạo lại (vì vậy mPageReferenceMap hiện trống), nhưng getItem không được gọi lại. Bản đồ vẫn trống nên adapter.getFragment (chỉ mục) sẽ bị sập.
Martin Konicek

102

Đây là cách duy nhất tôi không nhận được NullPulumException cho các biến thể hiện của các lớp phân đoạn cụ thể đó. Điều này có thể hữu ích cho những người khác bị mắc kẹt trong cùng một điều. Trong onOptionsItemSelected (), tôi đã mã hóa theo cách dưới đây:

if(viewPager.getCurrentItem() == 0) {
    FragmentClass1 frag1 = (FragmentClass1)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag1.updateList(text); 
} else if(viewPager.getCurrentItem() == 1) {
    FragmentClass2 frag2 = (FragRecentApps)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag2.updateList(text);
}

3
Tôi nghĩ rằng đây là câu trả lời đúng nhất - phù hợp với thiết kế FragmentStatePagerAdaptermà không ghi đè bất kỳ mã nào. Trong thực tế, nó nên đơn giản như một hàm chỉ cần trả về viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang

39

FragmentStatePagerAd CHƯƠNG có phương thức công khai với tên InstantiateItem trả về đoạn của bạn dựa trên các giá trị tham số đã chỉ định, phương thức này có hai tham số Viewgroup (ViewPager) và vị trí.

public Object instantiateItem(ViewGroup container, int position);

Đã sử dụng phương pháp này để lấy đoạn vị trí đã chỉ định,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);

5
Nhưng điều này không trả lại đoạn đã được khởi tạo hiện tại, nhưng thay vào đó là một đoạn mới, phải không? Do đó, tên "tức thời" ...
Ixx

1
@Ixx Không, nó không tạo ra một đoạn mới. Tôi nghĩ rằng tên phương pháp là không chính xác ở đây.
Lỗi xảy ra vào

15

Tôi biết quá muộn nhưng tôi có những cách thực hiện đơn giản,

// cho đoạn ở 0 sở hữu

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();

10

Có rất nhiều câu trả lời ở đây không thực sự giải quyết được thực tế cơ bản là thực sự KHÔNG CÓ CÁCH để làm điều này có thể dự đoán được, và theo cách mà không có kết quả là bạn sẽ tự bắn vào chân mình vào một lúc nào đó trong tương lai.

FragmentStatePagerAdapterlà lớp duy nhất biết cách truy cập một cách đáng tin cậy các đoạn được theo dõi bởi FragmentManager- mọi nỗ lực để thử và đoán id hoặc thẻ của đoạn đó không đáng tin cậy, lâu dài. Và các nỗ lực theo dõi các trường hợp theo cách thủ công có thể sẽ không hoạt động tốt khi trạng thái được lưu / khôi phục, bởi vìFragmentStatePagerAdapter có thể không gọi các cuộc gọi lại khi nó khôi phục trạng thái.

Về điều duy nhất tôi có thể thực hiện công việc là sao chép mã FragmentStatePagerAdaptervà thêm một phương thức trả về đoạn, được đưa ra một vị trí (mFragments.get(pos) ). Lưu ý rằng phương pháp này giả định rằng đoạn thực sự có sẵn (tức là nó có thể nhìn thấy tại một số điểm).

Nếu bạn đặc biệt thích phiêu lưu, bạn có thể sử dụng sự phản chiếu để truy cập các yếu tố của mFragmentsdanh sách riêng tư , nhưng sau đó chúng tôi sẽ quay lại hình vuông (tên của danh sách không được đảm bảo giữ nguyên).


1
để đối phó với "không hoạt động tốt khi trạng thái được lưu / khôi phục", tôi ghi đè phương thức saveState (). Vì vậy, máy nhắn tin không lưu bất kỳ đoạn nào khi hoạt động bị tạm dừng. nó hoạt động.
AntoineP

2
Điều đó chỉ thêm vào các bản vá, mà không khắc phục vấn đề cơ bản. Tôi không tranh luận rằng nó không hoạt động - chỉ là nó không phải là một triển khai tốt.
Melllvar

8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Truyền ví dụ được lấy lại từ dòng trên đến đoạn bạn muốn làm việc với. Hoạt động hoàn toàn tốt.

viewPager

là ví dụ máy nhắn tin quản lý các mảnh.


Điều này chỉ hoạt động nếu tất cả các trang được tải dưới dạng Fragment. Ví dụ, khi có một tab tabout với nhiều tab / trang thì không phải tất cả chúng đều được tải, do đó, điều này có thể làm tăng ngoại lệ indexoutofbounce.
progNewbie

@progNewbie vâng, điều đó sẽ cần thêm một mã giải pháp.
Gaurav Pangam

@progNewbie Câu trả lời của Evgeny dưới đây sẽ xử lý tình huống đó tôi nghĩ
Gaurav Pangam

7

bằng cách chọn một tùy chọn, tôi cần cập nhật đoạn hiện đang hiển thị.

Để có được một tham chiếu đến đoạn hiện có thể nhìn thấy, giả sử bạn có một tham chiếu đến ViewPagernhư mPager. Sau đó, các bước sau sẽ có được một tham chiếu đến currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

Các diễn viên duy nhất được sử dụng dòng 3 là hợp lệ thường. FragmentStatePagerAdapterlà một bộ chuyển đổi hữu ích cho ViewPager.


7

Cách tốt nhất để làm điều này, chỉ cần gọi CallingFragmentName Fragment = (CallingFragmentName) viewPager .getAd CHƯƠNG () .instantiateItem (viewPager, viewPager.getCienItem ()); Nó sẽ khởi tạo lại đoạn gọi của bạn, để nó không ném ngoại lệ con trỏ null và gọi bất kỳ phương thức nào của đoạn đó.


6

Mảnh vỡ hiện tại:

Điều này hoạt động nếu bạn đã tạo một dự án với mẫu thanh tab mảnh.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Lưu ý rằng điều này hoạt động với việc thực hiện mẫu hoạt động theo thẻ mặc định.


30
Điều này phụ thuộc vào việc bạn thực hiện getItem () - nó có thể trả về một phiên bản mới của đoạn, có thể không phải là điều bạn muốn.
Tom

Đây là cách bạn làm điều đó. nếu bạn vẫn có cấu hình mặc định khi bạn tạo một tabor với dự án phân đoạn. không có giải pháp này Vì vậy, tôi nghĩ rằng nó sẽ giúp.
hasan

3

Tôi đã sử dụng như sau:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);

1
Điều này phụ thuộc vào việc triển khai máy nhắn tin tùy chỉnh từ câu trả lời được tìm thấy ở đây: stackoverflow.com/questions/8785221/ mẹo
Tom Redman

1
Đây chính xác là những gì tôi đã cố gắng thực hiện nhưng không biết phương pháp nào để ghi đè, sẽ lãng phí hàng giờ - cảm ơn!
Bron Davies

2

FragmentStatePagerAdaptercó một biến thể riêng được gọi là mCurrentPrimaryItemkiểu Fragment. Người ta chỉ có thể tự hỏi tại sao các nhà phát triển Android không cung cấp cho nó một getter. Biến này được khởi tạo trong setPrimaryItem()phương thức. Vì vậy, ghi đè phương thức này theo cách để bạn có được tham chiếu đến biến này. Tôi chỉ đơn giản là kết thúc với việc khai báo của riêng tôi mCurrentPrimaryItemvà sao chép nội dung của phần setPrimaryItem()ghi đè của tôi.

Trong việc thực hiện của bạn FragmentStatePagerAdapter:

private Fragment mCurrentPrimaryItem = null;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

public TasksListFragment getCurrentFragment() {
    return (YourFragment) mCurrentPrimaryItem;
}

2

Bạn có thể định nghĩa PagerAdapternhư thế này sau đó bạn sẽ có thể nhận được bất kỳ Fragmenttrong ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

Để có được hiện tại Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());

2

Khi chúng tôi sử dụng viewPager, một cách tốt để truy cập vào thể hiện của đoạn trong hoạt động là InstantiateItem (viewpager, index). // index- index của đoạn mà bạn muốn.

ví dụ: tôi đang truy cập vào ví dụ phân đoạn của 1 chỉ mục-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}

1

Tôi đã có cùng một vấn đề và giải quyết nó bằng cách sử dụng mã này.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Chỉ cần thay thế tên MyFragment bằng tên của đoạn của bạn và thêm id của thùng chứa đoạn của bạn.


1

Đây là bằng chứng trong tương lai nhiều hơn câu trả lời được chấp nhận:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    /* ------------------------------------------------------------------------------------------ */
    // region Private attributes :

    private Context _context;
    private FragmentManager _fragmentManager;
    private Map<Integer, String> _fragmentsTags = new HashMap<>();

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region Constructor :

    public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {

        super(fragmentManager);

        _context = context;
        _fragmentManager = fragmentManager;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region FragmentPagerAdapter methods :

    @Override
    public int getCount() { return 2; }

    @Override
    public Fragment getItem(int position) {

        if(_fragmentsTags.containsKey(position)) {

            return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
        }
        else {

            switch (position) {

                case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
                case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
            }
        }

        return null;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        // Instantiate the fragment and get its tag :
        Fragment result = (Fragment) super.instantiateItem(container, position);
        _fragmentsTags.put(position, result.getTag());

        return result;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */
}

Bạn nên sử dụng WeakHashMap thay thế.
Prakash Nadar

1

Kịch bản trong câu hỏi được phục vụ tốt hơn bởi mỗi Fragment thêm các mục menu riêng và xử lý trực tiếp onOptionsItemSelected (), như được mô tả trong tài liệu chính thức . Tốt hơn là tránh các thủ thuật không có giấy tờ.


Câu trả lời này có thể sử dụng nhiều chi tiết hơn cho cách thực sự làm điều đó. Làm thế nào để thêm một mục menu giải quyết ViewPagervấn đề?
Suragch

Vấn đề @Suragch ViewPager tồn tại nếu các sự kiện menu được xử lý trong Activity lưu trữ các đoạn và không tồn tại nếu các sự kiện được xử lý trong chính đoạn đó. Liên kết cho thấy làm thế nào một mảnh có thể thêm các mục menu riêng của mình.
Y2i

1

Sau khi đọc tất cả các ý kiến ​​và câu trả lời tôi sẽ giải thích một giải pháp tối ưu cho vấn đề này. Tùy chọn tốt nhất là giải pháp của @ rik, vì vậy sự cải thiện của tôi dựa trên cơ sở của anh ấy.

Thay vì phải hỏi từng FragmentClass như

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Tạo giao diện của riêng bạn và tạo các đoạn con bạn thực hiện nó, đại loại như

public interface MyChildFragment {
    void updateView(int position);
}

Sau đó, bạn có thể làm một cái gì đó như thế này để bắt đầu và cập nhật các đoạn bên trong của bạn.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PS Hãy cẩn thận nơi bạn đặt mã đó, nếu bạn gọi insatiateItem trước khi hệ thống thực sự tạo ra nó, savedInstanceStateđoạn con của bạn sẽ không có giá trị

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Sẽ làm hỏng ứng dụng của bạn.

Chúc may mắn


1

Dựa trên những gì anh ấy trả lời @chahat jain:

"Khi chúng tôi sử dụng viewPager, một cách tốt để truy cập vào thể hiện của đoạn trong hoạt động là InstantiateItem (viewpager, index). // index- index của đoạn mà bạn muốn."

Nếu bạn muốn làm điều đó trong kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 đến ví dụ phân đoạn của 0

// ================================================ ========================= // // ###################### ######## Ví dụ về việc sử dụng ################################# // // == ================================================== ===================== //

Dưới đây là một ví dụ đầy đủ để có được một tầm nhìn kém nhất về

đây là veiewPager của tôi trong tệp .xml

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

Và hoạt động gia đình nơi tôi chèn tab

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}

1

Trong lần triển khai trước, tôi đã lưu trữ một danh sách các Mảnh vỡ con để có thể truy cập chúng sau này, nhưng điều này hóa ra là một triển khai sai gây ra rò rỉ bộ nhớ lớn.

Tôi kết thúc bằng cách sử dụng instantiateItem(...)phương thức để có được Fragment hiện tại:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

Hoặc để có được bất kỳ mảnh vỡ nào khác trên vị trí:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

Từ tài liệu :

Tạo trang cho vị trí nhất định. Bộ điều hợp có trách nhiệm thêm chế độ xem vào vùng chứa được cung cấp ở đây, mặc dù nó chỉ phải đảm bảo việc này được thực hiện vào thời điểm nó trả về từ finishUpdate (Viewgroup).


0

Trong hoạt động của tôi, tôi có:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int pos) {
        currentPage = pos;//update current page
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});



@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if(fragment instanceof Fragment1)
        fragments.put(0, fragment);
    if(fragment instanceof Fragment2)
        fragments.put(2, fragment);
    if(fragment instanceof Fragment3)
        fragments.put(3, fragment);
    if(fragment instanceof Fragment4)
        fragments.put(4, fragment);
}

Then I have the following method for getting the current fragment

public Fragment getCurrentFragment() {
    return fragments.get(currentPage);
}

0
final ViewPager.OnPageChangeListener onPageChangeListener =
    new ViewPager.OnPageChangeListener() {
      @Override public void onPageSelected(int position) {
        switch (position) {
          case 0:
            FragmentClass1 frag1 =
                (FragmentClass1) viewPager.getAdapter()
                    .instantiateItem(viewPager, viewPager.getCurrentItem());
            frag1.updateList("Custom text");
            break;
          case 1:
            break;
          case 2:
            break;
        }
      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

      }

      @Override public void onPageScrollStateChanged(int state) {
      }
    };


 viewPager.addOnPageChangeListener(onPageChangeListener);

viewPager.setAdapter(adapter);


viewPager.post(new Runnable() {
  @Override public void run() {
    onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
  }
});

Đôi khi, đoạn có thể gửi một đối tượng null, vì vậy bạn có thể chạy Runnable mới để giải quyết vấn đề ở lần tải đầu tiên.

Cảm ơn bạn


Vui lòng thêm một số văn bản giải thích lý do tại sao mã này sẽ giải quyết vấn đề của OP. Ngoài ra, cho biết có bao nhiêu câu trả lời khác, giải thích tại sao câu trả lời này tốt hơn câu trả lời đã được đưa ra. Giúp người khác hiểu.
APC

0

Ghi đè setPrimaryItem từ FragmentPagerAd CHƯƠNG của bạn: đối tượng là đoạn hiển thị:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }

0

Chỉ cần lấy mục hiện tại từ máy nhắn tin và sau đó yêu cầu bộ điều hợp của bạn đến đoạn của vị trí đó.

 int currentItem = viewPager.getCurrentItem();
    Fragment item = mPagerAdapter.getItem(currentItem);
    if (null != item && item.isVisible()) {
       //do whatever want to do with fragment after doing type checking
        return;
    }

3
Điều gì xảy getItemra nếu tạo một phiên bản mới
Prakash Nadar

0

Để có được đoạn hiện tại - nhận vị trí trong ViewPager ở khoảng trống công khai trênPageSelected (vị trí int cuối cùng) , và sau đó

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

SECTNUM - đối số vị trí được chỉ định trong Placeholder tĩnh công khaiFragment newInstance (int partNumber);của mảnh vỡ

getChildFragmentManager () hoặc getFragmentManager () - phụ thuộc vào cách tạo SectionsPagerAd CHƯƠNG


0

Bạn có thể triển khai BroadcastReceiver trong Fragment và gửi Intent từ bất cứ đâu. Người nhận của đoạn có thể lắng nghe hành động cụ thể và gọi phương thức của cá thể.

Một cảnh báo là đảm bảo thành phần View đã được khởi tạo và (và đối với một số thao tác, chẳng hạn như cuộn danh sách, ListView phải được hiển thị).


0

Đây là cách hack đơn giản nhất:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(mã kotlin)

Chỉ cần gọi instantiateItem(viewPager, viewPager.getCurrentItem()và bỏ nó đến Fragment. Mục của bạn đã được khởi tạo. Để chắc chắn bạn có thể thêm một kiểm tra chogetCount .

Hoạt động với cả FragmentPagerAdapterFragmentStatePagerAdapter!


0

Nếu máy nhắn tin của bạn ở trong Fragment thì hãy sử dụng:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

Trong trường hợp R.id.myViewPagerIdlà id của ViewPager của bạn bên trong xml Layout.


Điều này chỉ hoạt động với FragmentPageAd CHƯƠNG bình thường chứ không hoạt động với FragmentStatePageAd CHƯƠNG.
progNewbie

0

Bạn có thể khai báo một mảng của đoạn là đăng ký đoạn

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Sau đó, bạn có thể sử dụng nó như là

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}

Nếu bạn quyết định đi theo cách đó, bạn cũng nên triển khai hủy bỏItem () và xóa phiên bản đã hủy khỏi đăng ký, các thông minh khác bạn sẽ bị rò rỉ bộ nhớ.
dephinera

Đó là lời khuyên tốt. Bạn được chào đón để thực hiện một chỉnh sửa trong câu trả lời.
Hamza Khan

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.