Ответ 1
Наконец-то я нашел ответ, который работал у меня. В принципе, вы можете получить доступ к фрагменту для страницы viewPager с помощью тега "android: switcher:" + R.id.viewpager + ": 0".
У меня есть приложение с ViewPager
и тремя Fragment
s. Я пытаюсь выяснить, как получить текущий Fragment
, чтобы я мог найти его аргументы.
У меня есть OnPageChangeListener
, захватывающий текущий индекс страницы, но
ViewPager.getChildAt(int position);
возвращает a View
. Какая связь между этим View
и текущим Fragment
?
Наконец-то я нашел ответ, который работал у меня. В принципе, вы можете получить доступ к фрагменту для страницы viewPager с помощью тега "android: switcher:" + R.id.viewpager + ": 0".
Я решил эту проблему наоборот. Вместо того, чтобы искать фрагмент из этой активности, я регистрирую фрагмент во время его onAttach() метода при его активности владельца и де-регистрации его в методе onStop(). Основная идея:
Фрагмент:
@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);
}
}
Изменить - не делайте этого. Если вы соблазняетесь, прочитайте комментарии, почему это плохая идея.
По нечетному шансу вы все еще пытаетесь решить эту проблему:
Расширить FragmentPagerAdapter
. В конструкторе создайте нужные фрагменты и сохраните их в списке (массив/ArrayList) фрагментов.
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);
}
Затем для getItem(int position)
вы можете сделать что-то вроде
public Fragment getItem(int position) {
return frags[position];
}
Я не уверен, что это общепринятый способ сделать это, но это сработало для меня.
Edit
Это действительно не лучший способ. Если вы планируете обрабатывать изменения ориентации или приложение переходит в фоновый режим, это, вероятно, нарушит ваш код. Пожалуйста, прочитайте комментарии ниже этого ответа для получения дополнительной информации. Скорее используйте ответ @James
Да, возможно, если вы используете FragmentStatePagerAdapter
.
ViewPager vp;
//...
YourFragment fragment = (YourFragment) adapter.instantiateItem(vp, vp.getCurrentItem());
ПОЖАЛУЙСТА, НЕ ИСПОЛЬЗУЙТЕ ЭТО
Сделайте ваш адаптер расширением следующего класса FragmentStatePagerWithCurrentAdapter
и вместо реализации getItem
реализует один и тот же код в getItemAtIndex
Установите ViewPager
OnPageChangeListener
в экземпляр адаптера.
Когда вам нужно получить доступ к текущему фрагменту, вы просто вызываете 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;
}
}
Я использовал в качестве ссылки следующее сообщение в блоге: http://tamsler.blogspot.com/2011/11/android-viewpager-and-fragments-part-ii.html
Здесь объяснено: http://developer.android.com/guide/topics/fundamentals/fragments.html
В OnCreateView вы должны вернуть представление, чтобы нарисовать пользовательский интерфейс для вашего фрагмента, я думаю, что отношения.
Также этот вопрос может быть похож: Получить целенаправленный вид из ViewPager
Вы можете сделать это: - В классе класса адаптера представления пейджера (например, PagerAdapter, FragmentStatePagerAdapter...) метод переопределения 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;
}
Окончательный ответ, который работает без проблем (но небольшой взлом):
где-то в макете фрагмента страницы:
<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>
в фрагменте onCreateView():
...
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;
и метод для возврата фрагмента из ViewPager, если существует:
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();
}
Jorge Garcia FragmentStatePagerWithCurrentAdapter - очень хорошее решение, но оно нуждается в незначительном улучшении. В случае уничтожения и повторного создания активности в ответ на изменение конфигурации или что-то подобное, getItem не будет вызываться для фрагментов, которые были сохранены и извлечены менеджером фрагментов. Поэтому я переопределяю getItem обычно в моем подклассе, и я помещаю следующее в 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;
}
Функция instantiateItem вызывается каждый раз, когда обращается к фрагменту в этой позиции.
Или просто сохраните все фрагменты на карте:
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);
}
}
Я думаю, что есть лучший способ, используя этот
Log.i(TAG, "getCurrentItem " + mViewPager.getCurrentItem());
Может получить текущую страницу фрагмента дисплея.