web-dev-qa-db-fra.com

Obtenez une vue ciblée de ViewPager

j'utilise le ViewPager pour changer de vue avec un balayage gauche/droite.

Le ViewPager a besoin d'un adaptateur, j'ai donc construit celui-ci:

public class ListViewPagerAdapter extends PagerAdapter {

protected static final String TAG = "ListViewPagerAdapter";
protected static final int NUM_VIEWS = 3;

protected final Activity mActivity;

public ListViewPagerAdapter(Activity activity) {
    mActivity = activity;
}

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

@Override
public void startUpdate(View container) {}

@Override
public Object instantiateItem(View container, int position) {
    // ViewPager
    ViewPager viewPager = (ViewPager) container;

    // Wird verwendet, um die Views aufzurufen
    LayoutInflater layoutInflater = mActivity.getLayoutInflater();

    // Standardmäßig ist news eingeblendet
    View view = layoutInflater.inflate(R.layout.news_fragment, null);
    // Falls sich die Position verändert, so verändert sich auch die View
    if (position == 0) {
        view = layoutInflater.inflate(R.layout.favorite_fragment, null);
    } else if (position == 2) {
        view = layoutInflater.inflate(R.layout.videos_fragment, null);
    }

    // View einblenden
    viewPager.addView(view, 0);

    return view;
}

@Override
public void destroyItem(View container, int position, Object object) {
    // ViewPager
    ViewPager viewPager = (ViewPager) container;
    // View
    View view = (View) object;

    // View löschen
    viewPager.removeView(view);
}

@Override
public void finishUpdate(View container) {}

@Override
public boolean isViewFromObject(View view, Object object) {
    View _view = (View) object;
    return view == _view;
}

@Override
public Parcelable saveState() {
    return null;
}

@Override
public void restoreState(Parcelable state, ClassLoader loader) {}
 }

Maintenant, je veux obtenir la vue focalisée actuelle par le viseur. J'ai essayé getChildAt (x), mais cela ne fonctionne pas.

Existe-t-il un exemple ou avez-vous une idée de comment obtenir la vue actuelle?

Merci

50
Superroot

Il est possible d'enregistrer l'objet actuellement actif (View, Fragment, ...) en remplaçant la méthode PagerAdapter.setPrimaryItem . Par exemple:

private View mCurrentView;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    mCurrentView = (View)object;
}
88
Michael G.

Vous devez enregistrer un écouteur dans votre ViewPager:

pager.setOnPageChangeListener(new MyPageChangeListener()); 

Vous devez personnaliser l'écouteur en étendant un écouteur de stub:

private int focusedPage = 0;
private class MyPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
    @Override
    public void onPageSelected(int position) {
        focusedPage = position;
    }
}

J'ai trouvé cela en regardant le code source de ViewPager.Java dans bibliothèque de compatibilité . J'ai lu que nous pouvons faire plus, par exemple attraper onPageScrollStateChanged.

Pour construire l'adaptateur, j'ai utilisé le code sur ce billet de blog . Vous voudrez peut-être jeter un œil.

41
Steren

Vous pouvez ajouter une balise à la vue créée dans la méthode instantiateItem:

view.setTag(position);

Plus tard, vous pouvez accéder à la vue actuellement sélectionnée en:

mPager.findViewWithTag(mPager.getCurrentItem());
41
artkoenig

J'ai récemment dû implémenter cette solution exacte. Voici comment je l'ai fait:

Map<Integer, Object> views = Maps.newHashMap();

@Override
public Object instantiateItem(View container, int position) {
  /* Create and add your View here */
  Object result = ???

  views.put(position, result);
  return result;
}

@Override
public void destroyItem(View container, int position, Object object) {
  /** Remove your View here */

  views.remove(position);
}

protected View findViewForPosition(int position) {
  Object object = views.get(position);
  if (object != null) {
    for (int i = 0; i < getChildCount(); i++) {
      View view = getChildAt(i);
      if (isViewFromObject(view, object)) {
        return view;
      }
    }
  }
  return null;
}
4
Mark Renouf

Essaye ça:

public View getCurrentView(ViewPager pager) {
    for (int i = 0; i < pager.getChildCount(); i++) {
        View child = pager.getChildAt(i);
        if (child.getX() <= pager.getScrollX() + pager.getWidth() && 
            child.getX() + child.getWidth() >= pager.getScrollX() + pager.getWidth()) {
            return child;
         }
     }
     return getChildAt(0);
}
2
Arpit

Pour obtenir une vue ciblée, j'utilise de cette façon:

Lorsque je gonfle ma vue avant de l'ajouter sur ViewPager, je lui attribue une balise. Ensuite, je vérifie cette balise.

private View getCurrentView()
{
    for (int i = 0; i < pager.getChildCount(); i++)
    {
        View v = pager.getChildAt(i);
        if (v != null)
        {
            if (v.getTag().equals(pageList.get(pager.getCurrentItem()).getTag())) return v;
            // pageList is a list of pages that I pass to page adapter
        }
    }
    return null;
}
1
Nik

Vous pouvez utiliser ce code

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                Toast.makeText(getContext(), String.valueOf(position), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
0
Diako Hasani

les réponses données ne me convenaient pas vraiment, elles ont toutes des effets secondaires indésirables. Soit je dois ajouter des variables inutiles (j'aime le code propre), soit je dois contourner le Android framework lui-même.

Ma solution est basée sur la réflexion, qui accède à la liste des tableaux de tous les objets dans le ViewPager et renvoie l'objet actuellement sélectionné dans le ViewPager. Il n'a presque pas d'effets secondaires (la réflexion est lente, le sous-classement d'une classe existante) et il maintient le code propre.

public class ViewPagerEx extends ViewPager {

    private static final String TAG = ViewPagerEx.class.getSimpleName();

    public ViewPagerEx(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ViewPagerEx(Context context) {
        super(context);
    }

    public Object getCurrentObject() {
        try {
            final Field itemsField = ViewPager.class.getDeclaredField("mItems");
            itemsField.setAccessible(true);

            final ArrayList<Object> items = (ArrayList<Object>) itemsField.get(this);

            final int currentItemIndex = getCurrentItem();
            if (currentItemIndex < 0 || currentItemIndex >= items.size()) {
                return null;
            }

            final Object infoItem = items.get(getCurrentItem());

            final Class<?> itemInfoClass = findItemInfoClass(ViewPager.class.getDeclaredClasses());

            final Field objectField = itemInfoClass.getDeclaredField("object");
            objectField.setAccessible(true);
            return objectField.get(infoItem);

        } catch (NoSuchFieldException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalArgumentException e) {
            Log.e(TAG, e.toString());
        } catch (IllegalAccessException e) {
            Log.e(TAG, e.toString());
        }

        return null;
    }

    private Class<?> findItemInfoClass(final Class<?>[] classes) throws IllegalArgumentException {
        for (int i = 0; i < classes.length; i++) {
            if (classes[i].getSimpleName().equals("ItemInfo")) {
                return classes[i];
            }
        }

        throw new IllegalArgumentException("cannot find class ItemInfo");
    }
}
0
AZ13

Dans votre FragmentStatePagerAdapter:

    private View mCurrentView;

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment f = (Fragment) object;
        mCurrentView = f.getView();
    }
0
Accollativo