7

I have developed a kind of rolling mechanism for choosing staff in the application. It's Custom View Pager that allows to present more then one item on screen at each time (3 in my case) and surrounded with shadow from both sides.

Here is how it should look and works like this on devices like the Nexus 5, Nexus 4, Galaxy S3:

enter image description here

But on some devices like (Sony Xperia, and different kinds of Motorola) the rendering looks bad, here is the result:

enter image description here

Regarding the code I refereed to this blog post by @Commonsware:

http://commonsware.com/blog/2012/08/20/multiple-view-viewpager-options.html

And the third option there which code you could find here.

Here is my relevant code:

PagerContainer:

    public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener {

    private ViewPager mPager;
    boolean mNeedsRedraw = false;

    public PagerContainer(Context context) {
        super(context);
        init();
    }

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

    public PagerContainer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        //Disable clipping of children so non-selected pages are visible
        setClipChildren(false);

        //Child clipping doesn't work with hardware acceleration in Android 3.x/4.x
        //You need to set this value here if using hardware acceleration in an
        // application targeted at these releases.
        if (Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT < 19)
        {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
    }

    @Override
    protected void onFinishInflate() {
        try {
            mPager = (ViewPager) getChildAt(0);
            mPager.setOnPageChangeListener(this);
        } catch (Exception e) {
            throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
        }
    }

    public ViewPager getViewPager() {
        return mPager;
    }

    private Point mCenter = new Point();
    private Point mInitialTouch = new Point();

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCenter.x = w / 2;
        mCenter.y = h / 2;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //We capture any touches not already handled by the ViewPager
        // to implement scrolling from a touch outside the pager bounds.
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mInitialTouch.x = (int)ev.getX();
                mInitialTouch.y = (int)ev.getY();
            default:
                ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
                break;
        }

        return mPager.dispatchTouchEvent(ev);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        //Force the container to redraw on scrolling.
        //Without this the outer pages render initially and then stay static
        if (mNeedsRedraw) invalidate();
    }

    @Override
    public void onPageSelected(int position) { 
        invalidate();
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
    }
}

Init part:

  //Size View Pager:
    //========================================
    pagerSize = mContainerSize.getViewPager();
    adapter = new MySizePagerAdapter();
    pagerSize.setAdapter(adapter);
    //Necessary or the pager will only have one extra page to show  make this at least however many pages you can see
    pagerSize.setOffscreenPageLimit(adapter.getCount());
    //A little space between pages
    pagerSize.setPageMargin(15);
    //If hardware acceleration is enabled, you should also remove  clipping on the pager for its children.
    pagerSize.setClipChildren(false);

More research brought me to understand that this problem has something to do with the Hardware acceleration or the lack of it in some devices. But disabling it via code didn't helped me either.

halfer
  • 19,471
  • 17
  • 87
  • 173
Emil Adz
  • 39,787
  • 36
  • 133
  • 182

2 Answers2

2

I would try setting the layerType of the ViewPager and it's children to software render, instead of the parent frame layout.

You also might want to check out this blog post: http://udinic.wordpress.com/2013/09/16/viewpager-and-hardware-acceleration/

dandc87
  • 1,096
  • 5
  • 7
  • Thanks for your answer, now I have more clear idea why this is happening, but your solution and the solution in the blog post, still didn't helped me. but +1 for effort. – Emil Adz Feb 01 '14 at 14:19
0

I have ended up using another implementation of a ViewPager that gave me the same result but the rendering problem was no where to be seen there, this is the code:

  private class MyTypePagerAdapter extends PagerAdapter {

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        TextView view = new TextView(getActivity());
        view.setText(mTempBeverageList.get(position).getName().toUpperCase());
        if (!wasTypeChanged && (!isLocaleHebrew  && position == 1))
        {
            view.setTypeface(null, Typeface.BOLD);
            view.setTextSize(19);
        }
        else
        {
            view.setTextSize(16);
        }
        view.setSingleLine();
        view.setGravity(Gravity.CENTER);
        view.setTextColor(getResources().getColor(R.color.cups_black));
        view.setBackgroundColor(getResources().getColor(R.color.cups_cyan));
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
      container.removeView((View)object);
    }

    @Override
    public int getCount() {
      return mTempBeverageList.size();
    }

    @Override
    public float getPageWidth(int position) {
      return (0.33333f);
    }

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

And the initialization part:

pagerType= (ViewPager) view.findViewById(R.id.pagerType);   
pagerType.setAdapter(new MyTypePagerAdapter());
pagerType.setOffscreenPageLimit(6);
Emil Adz
  • 39,787
  • 36
  • 133
  • 182