2011-12-21 36 views
69

Tôi có một ứng dụng có số ViewPager và ba Fragment s. Tôi đang cố gắng tìm ra cách để có được Fragment hiện tại đang được xem để tôi có thể nhận được các đối số của nó.Có thể truy cập Fragment hiện tại đang được xem bởi một ViewPager không?

Tôi có một OnPageChangeListener grabbing chỉ số trang hiện tại, nhưng

ViewPager.getChildAt(int position); 

trả về một View. Mối quan hệ giữa số này View và số Fragment hiện tại là gì?

Trả lời

46

cuối cùng tôi đã tìm thấy an answer mà làm việc cho tôi. Về cơ bản, bạn có thể truy cập phân đoạn cho trang viewPager bằng cách sử dụng thẻ "android: switcher:" + R.id.viewpager + ": 0".

+27

Phương thức trong câu trả lời được liên kết không hoạt động với FragmentStatePagerAdapter, nhưng [câu trả lời thứ hai] (http://stackoverflow.com/a/8886019/237820) cho cùng một câu hỏi được liên kết có một phương thức thực hiện. –

+4

Trong khi điều này về lý thuyết có thể trả lời câu hỏi, [nó sẽ là thích hợp hơn] (http://meta.stackoverflow.com/q/8259) để bao gồm các phần thiết yếu của câu trả lời ở đây, và cung cấp liên kết để tham khảo. – Keelan

1

Nó được giải thích ở đây: http://developer.android.com/guide/topics/fundamentals/fragments.html

Trong OnCreateView bạn phải trả lại một cái nhìn để vẽ một giao diện người dùng cho mảnh của bạn, tôi nghĩ đó là mối quan hệ.

Cũng câu hỏi này có thể là tương tự: Get focused View from ViewPager

+0

Xin chào Dante, vâng, tôi hiểu điều đó, nhưng tôi đang cố lấy Fragment, cho Chế độ xem. – MitchellSalad

+0

Ok, điều gì về 'getFragmentManager(). FindFragmentById (R.id.fragment_container);' sau đó? Bạn sẽ nhận được mảnh vỡ hiện tại trong container mà tôi nghĩ. – Dante

+1

Tìm thấy trang này vì tôi có cùng một vấn đề. findFragmentById không hoạt động đối với tôi. – James

1

Bạn có thể làm như vậy: - Trên phạm vi lớp học của một bộ chuyển đổi xem pager (như PagerAdapter, FragmentStatePagerAdapter ...) phương pháp ghi đè instantiateItem:

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
     final Fragment frag = (Fragment) super.instantiateItem(container, position); 
     if(frag instanceof ListNoteOfTypeFragment){     
      final ListNoteOfTypeFragment listNoteOfTypeFragment = (ListNoteOfTypeFragment) frag; 
      //do whatever you want with your fragment here 
      listNoteOfTypeFragment.setNoteChangeListener(mListener); 
     } 
     return frag; 
    }  
5

Edit - Đừng làm điều này. Nếu bạn bị cám dỗ, hãy đọc nhận xét vì sao đó là một ý tưởng tồi.

Trên lẻ cơ hội bạn vẫn đang cố gắng để giải quyết vấn đề này:

Mở rộng FragmentPagerAdapter. Trong constructor, xây dựng Fragments bạn cần và lưu trữ chúng trong một List (array/ArrayList) của Fragments.

private final int numItems = 3; 
Fragment[] frags; 

public SwipeAdapter (FragmentManager fm) { 
    super(fm); 

    //Instantiate the Fragments 
    frags = new Fragment[numItems]; 

    Bundle args = new Bundle(); 
    args.putString("arg1", "foo"); 

    frags[0] = new MyFragment(); 
    frags[1] = new YourFragment(); 
    frags[2] = new OurFragment(); 
    frags[2].setArguments(args); 
} 

Sau đó cho getItem(int position), bạn có thể làm điều gì đó như

public Fragment getItem(int position) { 
    return frags[position]; 
} 

Tôi không chắc chắn nếu điều này là cách được chấp nhận chung để làm việc đó nhưng nó làm việc cho tôi.

Sửa

Điều này thực sự không phải là một cách tốt để đi. Nếu bạn có kế hoạch xử lý các thay đổi định hướng hoặc ứng dụng của bạn đi vào nền, thì điều này có thể sẽ phá vỡ mã của bạn. Vui lòng đọc các nhận xét bên dưới câu trả lời này để biết thêm thông tin. Thay vì sử dụng câu trả lời của @James

+0

giải pháp của bạn là tốt nếu tạo trước mọi đoạn không phải là một phản đối. đừng đánh giá thấp cách mà các mảnh vỡ của bạn tốn kém. – Rene

+1

Điểm tốt. Tôi cũng đã có vấn đề xấu với cách này khi các hoạt động khởi động lại, và fragments ''getActivity()' không trả về hoạt động hiện tại, nhưng một số trường hợp trước đó đã bị phá hủy –

+2

Điều này làm việc cho đến khi bạn xoay thiết bị. Sau đó, các mảnh sẽ tồn tại luân phiên, nhưng bộ nhớ cache của bộ điều hợp của bạn sẽ không. Bây giờ khi bạn yêu cầu đoạn hiện được hiển thị, bạn sẽ tạo ra một đoạn mới không được sử dụng chút nào. –

18

Tôi đã giải quyết vấn đề này theo cách khác. Thay vì tìm kiếm đoạn từ hoạt động, tôi đăng ký Fragment trong phương thức onAttach() của nó tại hoạt động của chủ sở hữu và hủy đăng ký nó trong phương thức onStop(). Idea cơ bản:

Fragment:

@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    try{ 
     mActivity = (IMyActivity)activity; 
    }catch(ClassCastException e){ 
     throw new ClassCastException(activity.toString() +" must be a IMyActivity"); 
    } 

    mActivity.addFragment(this); 
} 

@Override 
public void onStop() { 
    mActivity.removeFragment(this); 
    super.onStop(); 
} 

IMyActivity:

public interface IFriendActivity { 
    public void addFragment(Fragment f); 
    public void removeFragment(Fragment f); 
} 

MyActivity:

public class MyActivity implements IMyActivity{ 

    [...] 

    @Override 
    public void addFragment(Fragment f) { 
     mFragments.add(f); 
    } 

    @Override 
    public void removeFragment(Fragment f) { 
     mFragments.remove(f); 
    } 

} 
+1

Khi bạn đã đăng ký các mảnh vỡ của mình, làm thế nào để bạn tìm thấy nó theo vị trí của nó? –

3

VUI LÒNG KHÔNG SỬ DỤNG NÀY

Hãy adapter của bạn mở rộng các lớp FragmentStatePagerWithCurrentAdapter sau và thay vì thực hiện getItem thực hiện cùng mã vào getItemAtIndex

Đặt ViewPagerOnPageChangeListener, đến trường hợp của adapter.

Khi bạn cần truy cập Fragment hiện tại, bạn chỉ cần gọi adapter.getCurrentItem().

package your.package; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentStatePagerAdapter; 
import android.support.v4.view.ViewPager.OnPageChangeListener; 
import android.util.SparseArray; 
import android.view.ViewGroup; 

public abstract class FragmentStatePagerWithCurrentAdapter 
extends FragmentStatePagerAdapter 
implements OnPageChangeListener { 
    int currentPage = 0; 

    private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>(); 

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

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

    public abstract Fragment getItemAtIndex(int index); 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 

     super.destroyItem(container, position, object); 

     mPageReferenceMap.remove(Integer.valueOf(position)); 
    } 

    public Fragment getCurrentItem() { 
     return mPageReferenceMap.get(currentPage); 
    } 

    @Override 
    public void onPageScrollStateChanged(int arg0) { 

    } 

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

    } 

    @Override 
    public void onPageSelected(int newPageIndex) { 
     currentPage = newPageIndex; 
    } 

} 

tôi sử dụng như tài liệu tham khảo các bài viết trên blog sau đây: http://tamsler.blogspot.com/2011/11/android-viewpager-and-fragments-part-ii.html

+2

Điều này không đúng. Trong trường hợp xoay thiết bị, hệ thống sẽ tạo lại đoạn bằng cách gọi hàm tạo của đoạn đó mà không qua PagerAdapter.getItem. Cách thay thế khả thi duy nhất là lưu đối tượng phân đoạn trong Fragment.onAttach như các chương trình sdl. –

+0

@StephenCheng Bạn nói đúng. Tôi đã có một ứng dụng bức chân dung cố định khi tôi sử dụng, nhưng sau đó phát hiện ra vấn đề bạn đề cập khi hoạt động đã bị giết do áp lực bộ nhớ và sau đó trạng thái được nạp lại. Tôi đã kết thúc viết lại mã này cho một mã phức tạp hơn để xử lý tất cả các kịch bản mà chúng tôi cần bao gồm cả kịch bản này. –

0

Jorge Garcia's FragmentStatePagerWithCurrentAdapter là một giải pháp rất tốt nhưng nó cần một sự cải thiện đáng kể. Trong trường hợp hoạt động bị hủy và được tạo lại để thay đổi cấu hình hoặc một thứ gì đó giống như getItem sẽ không được gọi cho các đoạn được lưu và truy xuất bởi trình quản lý phân đoạn. Vì vậy, tôi ghi đè GetItem bình thường trong lớp con của tôi và tôi đặt sau trong FragmentStatePagerWithCurrentAdapter

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
    Object item = super.instantiateItem(container, position); 
    if (item instanceof Fragment) { 
     pageReferenceMap.put(position, (Fragment)item); 
    } 
    return item; 
} 

Các instantiateItem được gọi mỗi khi đoạn ở vị trí đó được truy cập.

-2

Tôi nghĩ rằng đó là cách tốt hơn bằng cách sử dụng này

Log.i(TAG, "getCurrentItem " + mViewPager.getCurrentItem());

có thể nhận được các trang hiển thị đoạn hiện nay.

1

câu trả lời dứt khoát rằng làm việc liên tục (nhưng Hack nhỏ):

đâu đó trong cách bố trí trang fragment của:

<FrameLayout android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone" android:id="@+id/fragment_reference"> 
    <View android:layout_width="0dp" android:layout_height="0dp" android:visibility="gone"/> 
</FrameLayout> 

trong onCreateView đoạn của():

... 
View root = inflater.inflate(R.layout.fragment_page, container, false); 
ViewGroup ref = (ViewGroup)root.findViewById(R.id.fragment_reference); 
ref.setTag(this); 
ref.getChildAt(0).setTag("fragment:" + pageIndex); 
return root; 

và phương pháp để trở Fragment từ ViewPager, nếu tồn tại:

public Fragment getFragment(int pageIndex) {   
     View w = mViewPager.findViewWithTag("fragment:" + pageIndex); 
     if (w == null) return null; 
     View r = (View) w.getParent(); 
     return (Fragment) r.getTag(); 
} 
0

Hoặc chỉ cần lưu tất cả các mảnh vỡ trong một bản đồ:

public class MyFragment extends Fragment implements OnPageChangeListener { 

    private ViewPager viewPager; 
    private FragmentStatePagerAdapter viewAdapter; 
    private View rootView; 
    private Map<Integer, Fragment> fragments = new HashMap<Integer, Fragment>(); 

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

     rootView = inflater.inflate(R.layout.introdution, container, false); 

     viewPager = (ViewPager) rootView.findViewById(R.id.pager); 
     viewAdapter = new ViewAdapter(getFragmentManager()); 
     viewPager.setAdapter(viewAdapter); 
     viewPager.addOnPageChangeListener(this); 

     return rootView; 

    } 

    private class ViewAdapter extends FragmentStatePagerAdapter { 

     public ViewAdapter(FragmentManager fragmentManager) { 
      super(fragmentManager); 
     } 

     @Override 
     public Fragment getItem(int position) { 

      Fragment result = null; 

      switch (position) { 
       case 0: result = Fragment1.newInstance(); break; 
       case 1: result = Fragment2.newInstance(); break; 
      } 

      if (result != null) 
       fragments.put(position, result); 

      return result; 

     } 

     @Override 
     public int getCount() { 

      return 2; 
     } 

    } 

    @Override 
    public void onPageScrollStateChanged(int arg0) { 
    } 

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

    @Override 
    public void onPageSelected(int position) { 

     Fragment currentFragment = fragments.get(position); 

    } 

} 
5

Có, đó là có thể nếu bạn đang sử dụng FragmentStatePagerAdapter.

ViewPager vp; 
//... 
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem()); 
Các vấn đề liên quan