Пользовательский центр текущего элемента ViewPager с пользовательским getPageWidth в адаптере

У меня есть пользовательский ViewPager, который действует как карусель, дело в том, что я хочу иметь возможность отображать несколько страниц на одной. Для этого у нас есть 2 решения:

  • Использование метода полей setPageMargin()
  • Или мы можем использовать Override метод getPageWidth адаптера моего ViewPager.

Первое решение отлично работает, но я хочу точно указать процент моей текущей страницы. Дело в том, что с решением getPageWidth моя текущая страница смещается влево. Это логично, потому что она занимает только 80% своего прежнего размера. Поэтому я попытался переопределить функцию scrollTo моего пользовательского ViewPager следующим образом:

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

Он работает, но я не могу прокручивать, как раньше, он просто ведет себя очень странно, не идите в правильном направлении, не следуйте за пальцем... Есть ли какое-либо решение, которое позволит мне иметь рабочий прокрутку и центрированный текущая страница ?

Вот мой адаптер:

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

Более бесполезно, но вот моя 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);
    }
}

Редактировать :

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

С уважением


person zed13    schedule 30.03.2016    source источник
comment
проверьте этот stackoverflow.com/a/53031553/4797289   -  person Rasoul Miri    schedule 28.10.2018


Ответы (1)


Вместо setPageMargin или getPageWidth вы можете просто установить отступы в свой 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" />

Обратите внимание на часть clipToPadding, важно показать другие страницы.

Если вы хотите показать свою ширину как x% экрана, вы можете сделать это в 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
    }
});
person Sourabh    schedule 30.03.2016
comment
Ваше решение отлично работает, спасибо! У меня просто вопрос, действительно ли уместно использовать поток для этого? Я имею в виду, чтобы установить отступ, мы можем сделать это в основном потоке или это ужасно? - person zed13; 31.03.2016
comment
mRootView.getWidth(); не будет работать, если представление уже не создано и его ширина не рассчитывается Android. Это не отдельный поток, он возвращается в поток пользовательского интерфейса, но просто задерживается до тех пор, пока mRootView не будет полностью создан. Вы можете использовать screenWidth вместо этого, если хотите - person Sourabh; 31.03.2016
comment
Ах да, вы правы, я забыл, еще раз спасибо за информацию. Хорошего дня. - person zed13; 31.03.2016