zed13
zed13

Reputation: 387

Custom ViewPager center current item with a custom getPageWidth in Adapter

I have a Custom ViewPager which act like a Carousel, the thing is I want to be able to show multiple page on one. To do so we have 2 solutions :

The first solution is working great but I want to be able to precise exactly the percentage of my current page. The thing is with the getPageWidth solution my current page is shifting at the left. It's logical because she only takes 80% of her previous size. So I tried to override the scrollTo function of my custom ViewPager like this :

 @Override
    public void scrollTo(int x, int y) {
        x = (int) (x - (getWidth() - getWidth()*getAdapter().getPageWidth(getCurrentItem()))/2);
        super.scrollTo(x, y);
    }

It's working but I can't scroll as before, it's just acting really weird, don't go in the good direction, don't follow the finger... Is there any solution which allow me to have a working scroll and a centered current page ?

Here is my adapter :

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

import java.util.ArrayList;

public class CarouselAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener {
    private ArrayList<Entity> mData = new ArrayList<>();
    private ScaledRelativeLayout cur = null, next = null;

    private float scale;
    private MainActivity context;
    private FragmentManager fragmentManager;

    public CarouselAdapter(MainActivity context, FragmentManager fragmentManager, ArrayList<Entity> mData) {
        super(fragmentManager);
        this.fragmentManager = fragmentManager;
        this.context = context;
        this.mData = mData;
    }

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

    @Override
    public Fragment getItem(int position) {
        if (position == MainActivity.FIRST_PAGE) {
            scale = MainActivity.BIG_SCALE;
        } else {
            scale = MainActivity.SMALL_SCALE;
        }

        position = position % mData.size();

        Fragment fragment = CarouselFragment.newInstance(context, mData.get(position), position, scale);
        return fragment;
    }

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

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (positionOffset >= 0f && positionOffset <= 1f) {
            cur = getRootView(position);
            cur.setScaleBoth(MainActivity.BIG_SCALE - MainActivity.DIFF_SCALE * positionOffset);

            if (position < mData.size()-1) {
                next = getRootView(position +1);
                next.setScaleBoth(MainActivity.SMALL_SCALE + MainActivity.DIFF_SCALE * positionOffset);
            }
        }
    }

    @Override
    public void onPageSelected(int position) {}

    @Override
    public void onPageScrollStateChanged(int state) {}

    private ScaledRelativeLayout getRootView(int position) {
        return (ScaledRelativeLayout) fragmentManager.findFragmentByTag(this.getFragmentTag(position)).getView().findViewById(R.id.rootItem);
    }

    private String getFragmentTag(int position) {
        return "android:switcher:" + context.carousel.getId() + ":" + position;
    }
}

More useless but here is my MainActivity :

import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;

import java.util.ArrayList;

public class MainActivity  extends FragmentActivity {
    public static int FIRST_PAGE;
    public final static float BIG_SCALE = 1.0f;
    public final static float SMALL_SCALE = 0.85f;
    public final static float DIFF_SCALE = BIG_SCALE - SMALL_SCALE;

    public CarouselViewPager carousel;
    private CarouselAdapter carouselAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FIRST_PAGE = mData.size()/2;
        carouselAdapter = new CarouselAdapter(this, this.getSupportFragmentManager(), mData);
        carousel = (CarouselViewPager) findViewById(R.id.carousel);
        carousel.setAdapter(carouselAdapter);
        carousel.addOnPageChangeListener(carouselAdapter);
        carousel.setCurrentItem(Math.round(FIRST_PAGE));
        carousel.setOffscreenPageLimit(3);
        carousel.setClipToPadding(false);
        carousel.setScrollDurationFactor(2.5f);
    }
}

Edit :

 root.post(new Runnable() {
            @Override
            public void run() {
                int width = root.getWidth();
                Log.w("Post", "Width : " + width + ", newWidth : " + (width * 0.8));
                // root.setPadding((int) (width * 0.125), 0, (int) (width * 0.125), 0);

                ViewPager.LayoutParams params = (ViewPager.LayoutParams) root.getLayoutParams();
                params.width = (int) (width * 0.8);
                root.setLayoutParams(params);
                root.requestLayout();
                root.forceLayout();
                root.invalidate();
            }
        });

Regards

Upvotes: 2

Views: 5177

Answers (1)

Sourabh
Sourabh

Reputation: 8502

Instead of setPageMargin or getPageWidth You can just set padding to your ViewPager.

<android.support.v4.view.ViewPager
    android:id="@+id/main_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:clipToPadding="false" />

Notice the clipToPadding part, it is important to show other pages.

If you want to show your width as x% of the screen, you can do this in Java

mRootView.post(new Runnable() {
    @Override
    public void run() {
        int w = mRootView.getWidth();
        mViewPager.setPadding(w * 0.25, 0, w * 0.25, 0);
        // 25% padding on either side so pages takes exactly 50% space
    }
});

Upvotes: 10

Related Questions