Get focused View from ViewPager

AndroidViewPagerAndroid ViewpagerViewpage

Android Problem Overview


i use the ViewPager for switching views with left/right swipe.

The ViewPager needs an Adapter, so I've built this one:

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

Now, i want to get the current focused view by the viewpager. I tried getChildAt(x), but it does not work.

Are there some example, or do you have any idea how to get the current view?

Thanks

Android Solutions


Solution 1 - Android

It is possible to save the currently active object (View, Fragment, ...) by overriding PagerAdapter.setPrimaryItem method. For example:

private View mCurrentView;

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

Solution 2 - Android

You have to register a listener to your ViewPager :

pager.setOnPageChangeListener(new MyPageChangeListener()); 

You have to customize the listener by extending a stub listener:

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

I found this by looking at the ViewPager.java source code in the compatibility library. I read that we can do more, for example catch onPageScrollStateChanged.

To build the adapter, I used the code on this blog post. You might want to have a look.

Solution 3 - Android

You can add a tag to the created view in the instantiateItem method:

view.setTag(position);

Later you can access the current selected view by:

mPager.findViewWithTag(mPager.getCurrentItem());

Solution 4 - Android

I recently needed to implement this exact solution. Here's the way I did it:

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

Solution 5 - Android

Try this:

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

Solution 6 - Android

To get focused view I use this way:

When I inflate my view before add it on ViewPager I set tag to it. Then I check this tag.

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

Solution 7 - Android

the given answers were not really suitable for me, they all have unwanted side effects. Either I have to add unnecessary variables (I like clean code) or I have to work around the Android framework itself.

My solution is based on reflection, which accesses the array list of all objects within the ViewPager and returns the current selected object in the ViewPager. It has almost no side effects (reflection is slow, subclassing of an existing class) and it keeps the code clean.

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

Solution 8 - Android

Inside your FragmentStatePagerAdapter:

    private View mCurrentView;

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

Solution 9 - Android

You can use:

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

        @Override
        public void onPageSelected(int position) {
            Log.i("maylonsales", "onPageSelected position " + position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

Solution 10 - Android

If you examine carefully, there are at most 3 views saved by ViewPager. You can easily get the current view by

view     = MyActivity.mViewPager.getChildAt(1);

Solution 11 - Android

Am I missing something? There's only ever 3 children inside the ViewGroup, so it boils down to:

int current = viewPager.getCurrentItem();
int childCount = viewPager.getChildCount();
// If there's a single page or we're at the beginning, return the first view
if (childCount == 1 || current == 0) {
  return viewPager.getChildAt(0);
} else { //For any other case, we want the second child. This is either the last page or the page in the middle for any other case.
  return viewPager.getChildAt(1);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSuperrootView Question on Stackoverflow
Solution 1 - AndroidMichael G.View Answer on Stackoverflow
Solution 2 - AndroidSterenView Answer on Stackoverflow
Solution 3 - AndroidartkoenigView Answer on Stackoverflow
Solution 4 - AndroidMark RenoufView Answer on Stackoverflow
Solution 5 - AndroidArpitView Answer on Stackoverflow
Solution 6 - AndroidNikView Answer on Stackoverflow
Solution 7 - AndroidAZ13View Answer on Stackoverflow
Solution 8 - AndroidAccollativoView Answer on Stackoverflow
Solution 9 - AndroidMaylon SalesView Answer on Stackoverflow
Solution 10 - AndroidAkshay VatsView Answer on Stackoverflow
Solution 11 - AndroiddmonView Answer on Stackoverflow