Viewpager: Too small indicator or too much tabs?
<p>Im using a ViewPager to show Images. The ViewPager is working correctly but there is an error with the indicator. When i swipe to the very last entry the indicator is only at round about 70% of the way. See the screen:</p>
<p><a href="https://i.stack.imgur.com/UI11w.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/UI11w.png" alt="enter image description here" /></a></p>
<p>That is the problem. I dont know if the indicator is just too small, moving to slow or there are another hidden entries in the viewpager but since i cant swipe any further to the right i guess there is a bug with the indicator size or moving or something like that.</p>
<p>This is how i initializ my viewpager:</p>
<pre><code>this.viewPager.setId(R.id.image_inspiration_pager);
this.viewPager.setClipToPadding(false);
this.viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(this.getContext(), 48)), 0);
this.viewPager.setAdapter(adapter);
this.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

    private static final float thresholdOffset = 0.5f;
    private boolean scrollStarted = false;
    private boolean checkDirection = false;

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (position == 0) {
            viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0);

            return;
        } else if (position == (adapter.getCount() - 1)) {
            viewPager.setPadding(((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0, 0, 0);

            return;
        }

        if (this.checkDirection) {
            if (thresholdOffset &gt; positionOffset) {
                viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0);
            } else {
                viewPager.setPadding(((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0, 0, 0);
            }

            this.checkDirection = false;
        }
    }

    @Override
    public void onPageSelected(int position) {}

    @Override
    public void onPageScrollStateChanged(int state) {
        if (!this.scrollStarted &amp;&amp; state == ViewPager.SCROLL_STATE_DRAGGING) {
            this.scrollStarted = true;
            this.checkDirection = true;
        } else {
            this.scrollStarted = false;
        }
    }
});
</code></pre>
<p>Implementation of TabLayout:</p>
<pre><code>public class TabsSlidingLayout extends HorizontalScrollView {
    private static final int TITLE_OFFSET_DIPS = 24;
    private static final int TAB_VIEW_PADDING_DIPS = 16;
    private static final int TAB_VIEW_TEXT_SIZE_SP = 14;
    private int titleOffset;
    private int tabViewLayoutId;
    private int tabViewTextViewId;
    private ViewPager viewPager;
    private ViewPager.OnPageChangeListener pageChangeListener;
    private final TabsSlidingStrip tabStrip;

    public TabsSlidingLayout(Context context) {
        this(context, null);
    }

    public TabsSlidingLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TabsSlidingLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        this.setHorizontalScrollBarEnabled(false);
        this.setFillViewport(true);
        this.titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
        this.tabStrip = new TabsSlidingStrip(context);

        this.addView(this.tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    }

    public void setCustomBackgroundColor(int color) {
        this.tabStrip.setBackgroundColor(color);
    }

    public void setCustomTabColorizer(TabColorizer tabColorizer) {
        this.tabStrip.setCustomTabColorizer(tabColorizer);
    }

    public void setSelectedIndicatorColors(int... colors) {
        this.tabStrip.setSelectedIndicatorColors(colors);
    }

    public void setDividerColors(int... colors) {
        this.tabStrip.setDividerColors(colors);
    }

    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
        this.pageChangeListener = listener;
    }

    public void setCustomTabView(int layoutResId, int textViewId) {
        this.tabViewLayoutId = layoutResId;
        this.tabViewTextViewId = textViewId;
    }

    public void setViewPager(ViewPager viewPager) {
        this.tabStrip.removeAllViews();

        this.viewPager = viewPager;

        if (this.viewPager != null) {
            this.viewPager.addOnPageChangeListener(new InternalViewPagerListener());
            this.populateTabStrip();
        }
    }

    protected TextView createDefaultTabView(Context context) {
        TextView textView = new TextView(context);
        textView.setGravity(Gravity.CENTER);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
        textView.setTypeface(Typeface.DEFAULT_BOLD);
        textView.setTextColor(ContextCompat.getColor(context, R.color.white));

        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB) {
            TypedValue outValue = new TypedValue();

            this.getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);

            textView.setBackgroundResource(outValue.resourceId);
        }

        if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            textView.setAllCaps(true);
        }

        int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);

        textView.setPadding(padding, padding, padding, padding);

        return textView;
    }

    private void populateTabStrip() {
        final PagerAdapter adapter = this.viewPager.getAdapter();
        final View.OnClickListener tabClickListener = new TabClickListener();

        for (int i = 0; i &lt; adapter.getCount(); i++) {
            View tabView = null;
            TextView tabTitleView = null;

            if (this.tabViewLayoutId != 0) {
                tabView = LayoutInflater.from(this.getContext()).inflate(this.tabViewLayoutId, this.tabStrip, false);
                tabTitleView = (TextView) tabView.findViewById(this.tabViewTextViewId);
            }

            if (tabView == null) {
                tabView = createDefaultTabView(this.getContext());
            }

            if (tabTitleView == null &amp;&amp; TextView.class.isInstance(tabView)) {
                tabTitleView = (TextView) tabView;
            }

            tabTitleView.setText(adapter.getPageTitle(i));
            tabView.setOnClickListener(tabClickListener);

            this.tabStrip.addView(tabView);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        if (this.viewPager != null) {
            this.scrollToTab(this.viewPager.getCurrentItem(), 0);
        }
    }

    private void scrollToTab(int tabIndex, int positionOffset) {
        final int tabStripChildCount = this.tabStrip.getChildCount();

        if (tabStripChildCount == 0 || tabIndex &lt; 0 || tabIndex &gt;= tabStripChildCount) {
            return;
        }

        View selectedChild = this.tabStrip.getChildAt(tabIndex);

        if (selectedChild != null) {
            int targetScrollX = selectedChild.getLeft() + positionOffset;

            if (tabIndex &gt; 0 || positionOffset &gt; 0) {
                targetScrollX -= this.titleOffset;
            }

            this.scrollTo(targetScrollX, 0);
        }
    }

    public interface TabColorizer {

        int getIndicatorColor(int position);

        int getDividerColor(int position);
    }

    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
        private int scrollState = -1;

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            int tabStripChildCount = tabStrip.getChildCount();

            if ((tabStripChildCount == 0) || (position &lt; 0) || (position &gt;= tabStripChildCount)) {
                return;
            }

            tabStrip.onViewPagerPageChanged(position, positionOffset);

            View selectedTitle = tabStrip.getChildAt(position);
            int extraOffset = (selectedTitle != null) ? (int) (positionOffset * selectedTitle.getWidth()) : 0;

            scrollToTab(position, extraOffset);

            if (pageChangeListener != null) {
                pageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            this.scrollState = state;

            if (pageChangeListener != null) {
                pageChangeListener.onPageScrollStateChanged(state);
            }
        }

        @Override
        public void onPageSelected(int position) {
            if (this.scrollState == ViewPager.SCROLL_STATE_IDLE) {
                tabStrip.onViewPagerPageChanged(position, 0f);
                scrollToTab(position, 0);
            }

            if (pageChangeListener != null) {
                pageChangeListener.onPageSelected(position);
            }
        }

    }

    private class TabClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            for (int i = 0; i &lt; tabStrip.getChildCount(); i++) {
                if (view == tabStrip.getChildAt(i)) {
                    viewPager.setCurrentItem(i);

                    return;
                }
            }
        }
    }
}
</code></pre>
<p>TabSlidingStrip implementation:</p>
<pre><code>class TabsSlidingStrip extends LinearLayout {
    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;
    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 2;
    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFFFFFFFF;
    private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 0;
    private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
    private static final float DEFAULT_DIVIDER_HEIGHT = 0.0f;
    private final int bottomBorderThickness;
    private final Paint bottomBorderPaint;
    private final int selectedIndicatorThickness;
    private final Paint selectedIndicatorPaint;
    private final Paint dividerPaint;
    private final float dividerHeight;
    private int selectedPosition;
    private float selectionOffset;
    private TabsSlidingLayout.TabColorizer customTabColorizer;
    private final SimpleTabColorizer defaultTabColorizer;

    public TabsSlidingStrip(Context context) {
        this(context, null);
    }

    public TabsSlidingStrip(Context context, AttributeSet attrs) {
        super(context, attrs);

        this.setWillNotDraw(false);

        final float density = getResources().getDisplayMetrics().density;

        TypedValue outValue = new TypedValue();

        context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);

        final int themeForegroundColor = outValue.data;

        this.setBackgroundColor(ContextCompat.getColor(context, R.color.primaryColor));
        this.defaultTabColorizer = new SimpleTabColorizer();
        this.defaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
        this.defaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA));
        this.bottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
        this.bottomBorderPaint = new Paint();
        this.bottomBorderPaint.setColor(setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA));
        this.selectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
        this.selectedIndicatorPaint = new Paint();
        this.dividerHeight = DEFAULT_DIVIDER_HEIGHT;
        this.dividerPaint = new Paint();
        this.dividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
    }

    void setCustomTabColorizer(TabsSlidingLayout.TabColorizer customTabColorizer) {
        this.customTabColorizer = customTabColorizer;

        this.invalidate();
    }

    void setSelectedIndicatorColors(int... colors) {
        this.customTabColorizer = null;
        this.defaultTabColorizer.setIndicatorColors(colors);

        this.invalidate();
    }

    void setDividerColors(int... colors) {
        this.customTabColorizer = null;
        this.defaultTabColorizer.setDividerColors(colors);

        this.invalidate();
    }

    void onViewPagerPageChanged(int position, float positionOffset) {
        this.selectedPosition = position;
        this.selectionOffset = positionOffset;

        this.invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        final int height = this.getHeight();
        final int childCount = this.getChildCount();
        final int dividerHeightPx = (int) (Math.min(Math.max(0f, this.dividerHeight), 1f) * height);
        final TabsSlidingLayout.TabColorizer tabColorizer = this.customTabColorizer != null ? this.customTabColorizer : this.defaultTabColorizer;

        if (childCount &gt; 0) {
            View selectedTitle = getChildAt(this.selectedPosition);
            int left = selectedTitle.getLeft();
            int right = selectedTitle.getRight();
            int color = tabColorizer.getIndicatorColor(this.selectedPosition);

            if (this.selectionOffset &gt; 0f &amp;&amp; this.selectedPosition &lt; (getChildCount() - 1)) {
                int nextColor = tabColorizer.getIndicatorColor(this.selectedPosition + 1);
                if (color != nextColor) {
                    color = blendColors(nextColor, color, this.selectionOffset);
                }

                View nextTitle = getChildAt(this.selectedPosition + 1);

                left = (int) (this.selectionOffset * nextTitle.getLeft() + (1.0f - this.selectionOffset) * left);
                right = (int) (this.selectionOffset * nextTitle.getRight() + (1.0f - this.selectionOffset) * right);
            }

            this.selectedIndicatorPaint.setColor(color);

            canvas.drawRect(left, height - this.selectedIndicatorThickness, right, height, this.selectedIndicatorPaint);
        }

        canvas.drawRect(0, height - this.bottomBorderThickness, this.getWidth(), height, this.bottomBorderPaint);

        int separatorTop = (height - dividerHeightPx) / 2;

        for (int i = 0; i &lt; childCount - 1; i++) {
            View child = getChildAt(i);

            this.dividerPaint.setColor(tabColorizer.getDividerColor(i));

            canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, this.dividerPaint);
        }
    }

    private static int setColorAlpha(int color, byte alpha) {
        return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
    }

    private static int blendColors(int color1, int color2, float ratio) {
        final float inverseRation = 1f - ratio;
        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);

        return Color.rgb((int) r, (int) g, (int) b);
    }

    private static class SimpleTabColorizer implements TabsSlidingLayout.TabColorizer {
        private int[] indicatorColors;
        private int[] dividerColors;

        @Override
        public final int getIndicatorColor(int position) {
            return this.indicatorColors[position % this.indicatorColors.length];
        }

        void setIndicatorColors(int... colors) {
            this.indicatorColors = colors;
        }

        @Override
        public final int getDividerColor(int position) {
            return this.dividerColors[position % this.dividerColors.length];
        }

        void setDividerColors(int... colors) {
            this.dividerColors = colors;
        }
    }
}
</code></pre>
<p>The first screenshot is from a tablet. Here is a screen from my smartphone:</p>
<p><a href="https://i.stack.imgur.com/V8csk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/V8csk.png" alt="enter image description here" /></a></p>
<p>As you can see for the smartphone the gap is much smaller than on the tablet.
Any idea what could be the problem?</p>