Lấy một đoạn từ ViewPager


248

Tôi đang sử dụng ViewPagercùng với một FragmentStatePagerAdapterđể lưu trữ ba mảnh khác nhau:

  • [Đoạn1]
  • [Mảnh2]
  • [Mảnh 3]

Khi tôi muốn nhận được Fragment1từ ViewPagertrong FragmentActivity.

Vấn đề là gì, và làm cách nào để khắc phục nó?

Câu trả lời:


504

Câu trả lời chính dựa vào tên được tạo bởi khung. Nếu điều đó thay đổi, thì nó sẽ không còn hoạt động nữa.

Điều gì về giải pháp này, ghi đè instantiateItem()destroyItem()của bạn Fragment(State)PagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();

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

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

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(...); 
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }

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

    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }
}

Điều này dường như làm việc cho tôi khi xử lý các mảnh vỡ có sẵn. Các mảnh chưa được khởi tạo, sẽ trả về null khi gọi getRegisteredFragment. Nhưng tôi đã sử dụng này chủ yếu là để có được hiện tại Fragmentra khỏi ViewPager: adapater.getRegisteredFragment(viewPager.getCurrentItem())và điều này sẽ không trở lại null.

Tôi không biết về bất kỳ nhược điểm nào khác của giải pháp này. Nếu có, tôi muốn biết.


41
Đây là giải pháp tốt nhất tôi có thể nghĩ là tốt. Chỉ có đề xuất là có thể bọc Fragmenttrong một WeakReferenceđể đảm bảo bạn không ngăn chặn một mảnh bị phá hủy khỏi rác được thu thập? Có vẻ như đó là điều đúng đắn ...
Alex Lockwood

7
Điều gì xảy ra khi MyPagerAdapterbị phá hủy do vòng đời (tức là xoay), sẽ không registerdFragmentsbị mất? Liệu Activity/ Fragmentsử dụng MyPagerAdapterphải lưu nó trong onSaveInstanceState, và sau đó cần phải cập nhật nó với các mới FragmentManagerref?
Steven Byle

10
Nếu tôi không nhầm (và bạn nên kiểm tra điều này), phương thức getItem sẽ không được gọi - như bạn biết - nhưng phương thức InstantiateItem được gọi cho mọi Fragment đang được khôi phục bởi khung sau khi xoay.
Đường phố Boston

6
Có, tôi đã xác minh rằng getItemkhông được gọi lại khi xoay (đối với bất kỳ đoạn nào đã được tạo), vì FragmentManagerkhôi phục trạng thái của Fragmentsnó giữ trong máy nhắn tin. Nếu instantiateItemđược gọi khi mỗi cái Fragmentđược khôi phục, thì thực tế giải pháp này an toàn hơn và bằng chứng trong tương lai nhiều hơn so với câu trả lời của tôi hoặc được chấp nhận. Tôi sẽ xem xét thử bản thân mình.
Steven Byle

6
@Dori Tôi không phá vỡ nó. Giải pháp của tôi là không sử dụng kết quả từ cuộc gọi 'getItem ()'. Thay vào đó, nó đang sử dụng kết quả được lưu trữ từ lệnh gọi 'InstantiateItem ()'. Và vòng đời của mảnh vỡ không bị phá vỡ, bởi vì mảnh được lưu trữ sẽ bị xóa khỏi mảng thưa thớt trong lệnh gọi 'killItem ()'.
Đường phố Boston

85

Để lấy các đoạn từ ViewPager, có rất nhiều câu trả lời ở đây và trên các chủ đề / blog SO liên quan khác. Tất cả mọi người tôi đã thấy bị hỏng, và họ thường rơi vào một trong hai loại được liệt kê dưới đây. Có một số giải pháp có giá trị khác nếu bạn chỉ muốn lấy đoạn hiện nay, như này câu trả lời khác về chủ đề này.

Nếu sử dụng FragmentPagerAdapterxem bên dưới. Nếu sử dụng FragmentStatePagerAdaptergiá trị của nó nhìn vào này . Việc lấy các chỉ mục không phải là chỉ số hiện tại trong FragmentStateAdOG không hữu ích vì bản chất của nó sẽ bị phá hủy hoàn toàn khỏi tầm nhìn / ra khỏi giới hạn offScreenLimit.

BỆNH NHÂN UNHAPPY

Sai: Duy trì danh sách các đoạn nội bộ của riêng bạn, được thêm vào khi FragmentPagerAdapter.getItem()được gọi

  • Thường sử dụng một SparseArrayhoặcMap
  • Không phải là một trong nhiều ví dụ tôi đã thấy các tài khoản cho các sự kiện vòng đời nên giải pháp này rất mong manh. Như getItemchỉ được gọi lần đầu tiên một trang được cuộn đến (hoặc thu được nếu ViewPager.setOffscreenPageLimit(x)> 0) của bạn trong ViewPager, nếu lưu trữ Activity/ Fragmentbị giết hoặc khởi động lại thì nội bộ SpaseArraysẽ bị xóa khi FragmentPagerActivity tùy chỉnh được tạo lại, nhưng đằng sau hậu trường Các đoạn nội bộ của ViewPager sẽ được tạo lại và getItemsẽ KHÔNG được gọi cho bất kỳ chỉ mục nào, vì vậy khả năng lấy một đoạn từ chỉ mục sẽ bị mất vĩnh viễn. Bạn có thể giải thích điều này bằng cách lưu và khôi phục các tham chiếu đoạn này qua FragmentManager.getFragment()putFragmentđiều này bắt đầu khiến IMHO lộn xộn.

Sai: Xây dựng id thẻ của riêng bạn khớp với nội dung được sử dụng trong trình duyệtFragmentPagerAdapter và sử dụng thẻ này để truy xuất trang Fragment từ trangFragmentManager

  • Điều này tốt hơn khi nó đối phó với vấn đề tham chiếu mất đoạn trong giải pháp mảng bên trong đầu tiên, nhưng như đã chỉ ra một cách đúng đắn trong các câu trả lời ở trên và ở nơi khác trên mạng - nó cảm thấy khó chịu vì đây là một phương thức riêng tưViewPager có thể thay đổi bất cứ lúc nào hoặc cho bất kỳ phiên bản hệ điều hành.

Phương pháp được tạo lại cho giải pháp này là

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

MỘT CON NGƯỜI HẠNH PHÚC: ViewPager.instantiateItem()

Một cách tiếp cận tương tự như getItem()trên nhưng không phá vỡ vòng đời là để nối vào instantiateItem()thay vì getItem()như trước đây sẽ được gọi mỗi khi chỉ mục được tạo / truy cập. Xem câu trả lời này

MỘT CON NGƯỜI HẠNH PHÚC: Xây dựng của riêng bạn FragmentViewPager

Xây dựng FragmentViewPagerlớp của riêng bạn từ nguồn lib hỗ trợ mới nhất và thay đổi phương thức được sử dụng trong nội bộ để tạo các thẻ phân đoạn. Bạn có thể thay thế nó bằng dưới đây. Điều này có lợi thế là bạn biết việc tạo thẻ sẽ không bao giờ thay đổi và việc bạn không dựa vào một phương pháp / api riêng tư, điều này luôn nguy hiểm.

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

Như tài liệu đã nói, khi bạn muốn lấy một đoạn được sử dụng cho một chỉ mục, chỉ cần gọi một cái gì đó giống như phương thức này (mà bạn có thể đặt trong tùy chỉnh FragmentPagerAdapterhoặc một lớp con) nhận thức được kết quả có thể là null nếu getItem chưa được gọi cho trang đó tức là chưa được tạo.

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

Đây là một giải pháp đơn giản và giải quyết các vấn đề trong hai giải pháp khác được tìm thấy ở mọi nơi trên web


6
Điều này sẽ hoạt động, nhưng nó yêu cầu sao chép lớp ViewPager vào mã nguồn của riêng bạn. Dựa vào 'InstantiateItem ()' và 'hủyItem ()' của trình điều khiển máy nhắn tin của ViewPager sẽ hoạt động và sẽ tôn vinh vòng đời của các mảnh vỡ (2 phương thức này cũng được gọi khi các đoạn được tạo từ trạng thái đã lưu). Bạn đã đúng, việc dựa vào 'getItem ()' được gọi không phải là một ý tưởng hay và sử dụng API riêng cũng không.
Đường phố Boston

+1 tôi đồng ý rằng đó cũng là một giải pháp và đã chỉnh sửa ở trên. Sự khác biệt duy nhất là ở trên hoạt động trong một trường hợp sử dụng nhiều hơn instantiateItem(), đó là khi bạn muốn truy cập vào một đoạn chưa được truy cập sau khi một sự kiện vòng đời đã diễn ra và được truy cập trước sự kiện vòng đời. Một sự khác biệt nhỏ mà tôi biết nhưng đó là một lỗi dẫn đến một lỗi nhỏ trong chương trình của tôi do đó tôi xem xét vấn đề này.
Dori

Nếu setPackscreenPageLimit = 1 (mặc định), FragmentStatePageAd CHƯƠNG sẽ bắt đầu hoán đổi các đoạn trong và ngoài bộ nhớ khi các trang xem được truy cập. Bằng một cuộc gọi đến getItem (), một phiên bản mới của các trang / đoạn được xem lại sau đó sẽ được tạo. Khi xem xét lại như vậy, có cách nào để hướng dẫn hệ thống tiếp tục các trường hợp đã tạo trước đó, thay vì tạo một trường hợp mới không?
carl

nếu ngoài giới hạn trang, nó sẽ phải tạo một cái mới - nhưng chuyển qua trạng thái đã lưu. Nếu muốn giữ những cái cũ xung quanh thì bạn có thể tăng giới hạn trang
Dori

@Dori không có getItemId(pos)bên trongFragmentStatePagerAdapter
Jemshit Iskenderov

70

Thêm các phương thức tiếp theo vào FragmentPagerAdOG của bạn:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

getActiveFragment (0) phải hoạt động.

Đây là giải pháp được triển khai trong ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Nếu một cái gì đó thất bại, bạn sẽ thấy nhật ký sự cố tốt.


Cảm ơn rất nhiều:) . Thông qua tôi đã xử lý nó theo một cách khác mà tôi sử dụng một trình xử lý để đăng đoạn. Điều này không phù hợp lắm nhưng cuối cùng nó cũng giải quyết được vấn đề. Nhân tiện, bạn thật tuyệt :)
Qun Qin

12
Tôi đã sử dụng phương pháp này, nhưng tôi tin rằng nó đã ngừng hoạt động khi tôi chuyển sang API 17 (?). Tôi sẽ đề xuất một phương pháp khác và sẽ thích nó hơn nếu Google chỉ xuất bản một API để lấy một mảnh từ ViewPager, với vị trí của nó.
gcl1

Tôi gặp vấn đề khi gọi đoạn thứ hai, phương thức tạo một đoạn mới
Vasil Valchev

2
Vì một số phiên bản API phương thức makeFragmentName đã được thay đổi thành chuỗi tĩnh riêng makeFragmentName (int viewId, id dài) {return "android: switcher:" + viewId + ":" + id; } vì vậy phương thức getActiveFragment bây giờ sẽ giống như thế này (sử dụng getItemId thay cho vị trí cho đối số thứ hai) trả về mFragmentManager.findFragmentByTag (tên); }
Eugene Popovich

1
Nó thực sự hoạt động nhưng nó thực sự nguy hiểm vì nó tiếp tục triển khai bên trong máy nhắn tin xem và nếu google sẽ thay đổi việc triển khai (và họ có thể) những điều xấu sẽ xảy ra. Tôi thực sự hy vọng goole sẽ làm cho nó có sẵn để có được mảnh vỡ trực tiếp
shem

38

Một giải pháp đơn giản khác:

    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);
        }
    }

1
Điều này có vẻ hoàn hảo cho nhu cầu mảnh hiện tại của tôi.
danny117

Nếu tất cả những gì bạn cần làm là lấy Fragment hiện được chọn, thì đây là tất cả những gì bạn cần - phương thức setPrimaryItem được thiết lập trên tệp đính kèm và cũng được cập nhật vào tập nội bộ của Fragment như mục hiện tại.
Graeme

1
Điều này nghe có vẻ là một giải pháp tốt nhưng như setPrimaryItem()được gọi sau khi ViewPager.OnPageChangeListener#onPageSelected() tôi không thể sử dụng nó :-(
hardysim

21

Tôi biết điều này có một vài câu trả lời, nhưng có lẽ điều này sẽ giúp được ai đó. Tôi đã sử dụng một giải pháp tương đối đơn giản khi tôi cần lấy Fragmenttừ tôi ViewPager. Trong Activityhoặc Fragmentgiữ ViewPager, bạn có thể sử dụng mã này để duyệt qua mọi Fragmentmã giữ.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • Nếu bạn biết vị trí của bạn Fragmenttrong ViewPager, bạn chỉ có thể gọi getItem(knownPosition).

  • Nếu bạn không biết vị trí của bạn Fragmenttrong ViewPager, bạn có thể cho con bạn Fragmentsthực hiện một giao diện với một phương thức như thế getUniqueId(), và sử dụng nó để phân biệt chúng. Hoặc bạn có thể chuyển qua tất cả Fragmentsvà kiểm tra loại lớp, chẳng hạn nhưif(viewPagerFragment instanceof FragmentClassYouWant)

!!! BIÊN TẬP !!!

Tôi đã phát hiện ra rằng getItemchỉ được gọi FragmentPagerAdapterkhi mỗi lần Fragmentcần được tạo lần đầu tiên , sau đó, nó xuất hiện cái Fragmentsđược tái chế bằng cách sử dụng FragmentManager. Bằng cách này, nhiều triển khai FragmentPagerAdaptertạo s mới . Sử dụng phương pháp trên của tôi, điều này có nghĩa là chúng tôi sẽ tạo s mới mỗi lần được gọi khi chúng tôi đi qua tất cả các mục trong . Do đó, tôi đã tìm thấy một cách tiếp cận tốt hơn, sử dụng để lấy từng cái thay thế (sử dụng câu trả lời được chấp nhận). Đây là một giải pháp đầy đủ hơn, và đã làm việc tốt cho tôi.FragmentgetItemFragmentgetItemFragmentPagerAdapterFragmentManagerFragment

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

Và bạn sẽ cần phương pháp này.

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}

1
Bạn chỉ cần tìmFragmentByTag (), nhưng chúng ta có thể đặt TAG ở đâu với phân đoạn ??
VinceStyling

@vince Chính ViewPagernó đặt các thẻ đó. Giải pháp này rất mong manh vì nó dựa vào việc biết quy ước đặt tên "ẩn" của ViewPager. Câu trả lời của Streets of Boston là một giải pháp toàn diện hơn nhiều, hiện tôi đang sử dụng trong dự án của mình (thay vì phương pháp này).
Steven Byle

Điều này làm việc tuyệt vời! Nhưng tôi đã xóa điều kiện "if (viewPagerFragment.isResumed ())" vì tôi cần cập nhật các trang ListFragment ngoài màn hình. Sau đó, khi người dùng quay lại trang ListFragment, tất cả sẽ được cập nhật với dữ liệu mới.
JDJ

10

Đối với trường hợp của tôi, không có giải pháp nào ở trên hoạt động.

Tuy nhiên, vì tôi đang sử dụng Trình quản lý phân đoạn trẻ em trong một phân đoạn, nên sau đây đã được sử dụng:

Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());

Điều này sẽ chỉ hoạt động nếu các đoạn của bạn trong Trình quản lý tương ứng với mục trình xem.


Đây là câu trả lời hoàn hảo để có được các đoạn cũ từ chế độ xem khi hoạt động hoặc đoạn được tạo lại.
Smeet

7

Để có được đoạn hiển thị hiện tại từ ViewPager . Tôi đang sử dụng tuyên bố đơn giản này và nó hoạt động tốt.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }

3

Tôi đã xử lý nó bằng cách đầu tiên lập danh sách tất cả các mảnh (List<Fragment> fragments; ) mà tôi sẽ sử dụng sau đó thêm chúng vào máy nhắn tin để dễ dàng xử lý đoạn hiện đang xem.

Vì thế:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

Vì vậy, điều này có thể được gọi là:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

vì vậy sau đó tôi có thể tặc lưỡi trong một câu lệnh if sẽ chỉ chạy nếu nó nằm trên đoạn đúng

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

nhưng đó chỉ là cách tiếp cận hack và slash của tôi nhưng nó hiệu quả với tôi, tôi sử dụng nó để thay đổi liên quan đến đoạn hiện đang hiển thị của tôi khi nhấn nút quay lại.


1
câu trả lời hay nhất cho tôi
Sonu Kumar

3

Điều này dựa trên câu trả lời của Steven ở trên. Điều này sẽ trả về ví dụ thực tế của đoạn đã được gắn vào hoạt động cha.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }

2

Tôi không thể tìm thấy một cách đơn giản, sạch sẽ để làm điều này. Tuy nhiên, tiện ích ViewPager chỉ là một Viewgroup khác, nơi lưu trữ các đoạn của bạn. ViewPager có những mảnh vỡ này ngay lập tức. Vì vậy, bạn chỉ có thể lặp lại chúng (sử dụng .getChildCount () và .getChildAt ()) và xem liệu phiên bản phân đoạn mà bạn đang tìm kiếm hiện đang được tải vào ViewPager và có được tham chiếu đến nó không. Ví dụ: bạn có thể sử dụng một số trường ID duy nhất tĩnh để phân tách các mảnh.

Lưu ý rằng ViewPager có thể không tải đoạn bạn đang tìm vì nó là một thùng chứa ảo hóa như ListView.


1
Cảm ơn bạn đã trả lời, tôi lấy nó bằng adpter.getItem (); Tôi là sinh viên năm nhất lập trình Android. thực sự đánh giá cao bạn rất nhiều. Bây giờ tôi có thể truy xuất ListFragment và tôi muốn thêm footerView vào nó, Trong khi tôi thực hiện điều này trong Hoạt động của mình thì bản in logcat: "java.lang.IllegalStateException: Chế độ xem nội dung chưa được tạo." Tôi biết tại sao nhưng tôi gặp khó khăn khi xử lý với nó.
Qun Qin

1
FragmentActivity có phương thức onAttachFragment (), liều lượng công việc này cho nội dung phân đoạn ViewPager whit?
Vasil Valchev

2

FragmentPagerAdOG là nhà máy của các mảnh vỡ. Để tìm một đoạn dựa trên vị trí của nó nếu vẫn còn trong bộ nhớ, hãy sử dụng:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Mã mẫu cho api hỗ trợ v4.


Nó đang trả về null trong onresume (). Bất cứ ý tưởng tại sao và cuốc để sửa chữa nó?
seema

2

Bạn không cần phải gọi getItem()hoặc một số phương pháp khác ở giai đoạn sau để có được tham chiếu của một máy Fragmentchủ lưu trữ bên trong ViewPager. Nếu bạn muốn cập nhật một số dữ liệu bên trong Fragmentthì hãy sử dụng phương pháp này: Cập nhật ViewPager một cách linh hoạt?

Điều quan trọng là thiết lập dữ liệu mới bên trong Adapervà gọi notifyDataSetChanged()lần lượt sẽ gọi getItemPosition(), chuyển cho bạn một tham chiếu của bạn Fragmentvà cho bạn cơ hội cập nhật dữ liệu đó. Tất cả các cách khác yêu cầu bạn tiếp tục tham khảo chính mình hoặc một số hack khác không phải là một giải pháp tốt.

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}

Tôi không hiểu ở đây, bạn cần một tham chiếu của Fragment để sử dụng getItemPocation (), vì vậy bạn cũng có thể không sử dụng getItemPocation, eh?

getItemPosition()là một phương pháp trong bộ chuyển đổi của bạn. Bạn sẽ không gọi nó trực tiếp. Bạn có một tham chiếu về bộ điều hợp của mình để bạn gọi adapter.notifyDataSetChanged()lần lượt sẽ gọi getItemPosition()bộ điều hợp của bạn bằng cách chuyển tham chiếu của Fragments. Bạn có thể thấy một triển khai đầy đủ trong hành động tại đây stackoverflow.com/questions/19891828/
Kẻ

Tôi đã đọc nó và tôi vẫn không hiểu. Bạn vẫn cần một tài liệu tham khảo trực tiếp đến những mảnh vỡ đó để thực hiện các cuộc gọi chống lại chúng, phải không? Bạn đề cập rằng đó là một hack nhưng tôi không thấy một sự thay thế; adapter.getItem (i) rõ ràng là không hoạt động.

2
Ok tôi đã cập nhật câu trả lời của tôi để làm rõ hơn. Tất nhiên một tài liệu tham khảo là cần thiết để cập nhật một Fragmentnhưng làm thế nào để có được một tài liệu tham khảo là có thể tranh luận. Các giải pháp khác có được tham chiếu từ FragmentManagerviệc sử dụng một chuỗi tương tự "android:switcher:"+idhoặc quay trở lại POSITION_NONEtừ việc getItemosition()gây ra tất cả các đoạn để tự tạo lại.
M-WaJeEh

Cảm ơn, điều này có ý nghĩa hơn nhiều và phù hợp với kinh nghiệm của tôi (vì vậy tôi có thể không làm điều gì sai, ha).

2

Phải mở rộng FragmentPagerAdaptervào lớp bộ điều hợp ViewPager của bạn.
Nếu bạn sử dụng FragmentStatePagerAdapterthì bạn sẽ không thể tìm thấy bạn Fragmentbằng cách của mìnhID

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

Cách sử dụng phương pháp này: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;

2

Này tôi đã trả lời câu hỏi này ở đây . Về cơ bản, bạn cần ghi đè

đối tượng công khai tức thìItem (thùng chứa Viewgroup, vị trí int)

phương thức của FragmentStatePagerAd CHƯƠNG.


1

Giải pháp tốt nhất là sử dụng tiện ích mở rộng mà chúng tôi đã tạo tại CodePath có tên SmartFragmentStatePagerAd CHƯƠNG . Theo hướng dẫn đó, điều này làm cho việc truy xuất các đoạn và đoạn hiện được chọn từ ViewPager dễ dàng hơn đáng kể. Nó cũng thực hiện công việc quản lý bộ nhớ của các đoạn được nhúng trong bộ điều hợp tốt hơn.


0

Cách dễ nhất và ngắn gọn nhất. Nếu tất cả các mảnh của bạn ViewPagerthuộc các lớp khác nhau, bạn có thể truy xuất và phân biệt chúng như sau:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}

Điều này cũng sai, vì có nhiều đoạn được đính kèm khi bạn sử dụng ViewPager. có đoạn trang hiện tại, và có một bên trái và một bên phải. Điều này cho phép người dùng trượt giữa chúng mà không phải khởi tạo chúng chỉ khi người dùng tiếp cận chúng.
nhà phát triển Android

0

Tôi thực hiện điều này dễ dàng với một cách tiếp cận khác nhau.

Phương thức FragmentAd Module.getItem tùy chỉnh của tôi trả về không phải MyFragment () mới, mà là ví dụ của MyFragment đã được tạo trong hàm tạo của FragmentAd CHƯƠNG.

Trong hoạt động của mình, sau đó tôi đã nhận được đoạn từ bộ điều hợp, kiểm tra xem nó có phải là Fragment hay không, sau đó sử dụng và sử dụng các phương thức cần thiết.


0

Tạo id tài nguyên số nguyên trong /values/integers.xml

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

Sau đó, trong hàm getagerem của PagerAdOG:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

Sau đó, trong hoạt động viết hàm này để có được tham chiếu đoạn:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

Lấy tham chiếu đoạn bằng cách gọi hàm trên và sau đó chuyển nó tới đoạn tùy chỉnh của bạn:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }

0

Cách dễ dàng để lặp lại các đoạn trong trình quản lý đoạn. Tìm viewpager, có đối số vị trí phần, được đặt trong Placeholder tĩnh tĩnh công khai newInstance (int partNumber) .

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

0

Trong mảnh vỡ

public int getArgument(){
   return mPage;
{
public void update(){

}

Trong FragmentActivity

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}

0

trong TabLayout có nhiều tab cho Fragment. bạn có thể tìm thấy đoạn bằng Thẻ bằng cách sử dụng chỉ mục của đoạn.

Dành cho người cũ chỉ mục cho Fragment1 là 0, vì vậy, trong findFragmentByTag()phương thức, hãy chuyển thẻ cho Viewpager. sau khi sử dụng FragmentTransaction bạn có thể thêm, thay thế đoạn.

String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);


-1

Ok cho bộ chuyển đổi FragmentStatePagerAdapter tôi tài trợ một giải pháp:

trong FragmentActivity của bạn:

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

và tạo một metode trong lớp FragmentActivity của bạn - Vì vậy, phương thức đó cho phép bạn truy cập vào Fragment của mình, bạn chỉ cần cung cấp cho nó vị trí của đoạn bạn muốn:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

trong Bộ chuyển đổi của bạn:

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}

}

-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

indexlà vị trí của đoạn trong bộ điều hợp như bạn đã thêm fragment1trước tiên, vì vậy, retreive fragment1pass indexlà 0 và cứ thế cho phần còn lại

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.