ViewPager с границами предыдущей и следующей страницы


144

Я создаю представление с несколькими страницами. Я хочу, чтобы края предыдущей и следующей страниц отображались, как показано ниже, и выполняю движение двумя пальцами для переключения между страницами.

введите описание изображения здесь

Я попытался использовать ViewPagerс отрицательным полем страницы, как предложено здесь, но это показывает только один из краев на экране, а не оба одновременно.

Кроме того, есть ли способ, которым я могу расположить часть моего вида за пределами экрана, а затем анимировать его, придав ему ViewPagerэффект типа.

Как я должен идти об этом? Спасибо !


msgstr "только показывает один из краев на экране, а не оба одновременно." Вы на странице 0 и видите только часть страницы 1? Возможно, вам нужно использовать круговой пейджер, например, а затем всегда устанавливать свою страницу в «среднее» положение. Смотрите этот пост и комментарий: stackoverflow.com/a/8304474/1851478
logray

Ответы:


100

Цитирую себя из поста в блоге на эту тему :

Третий подход исходит от Дейва Смита, соавтора широко известной книги Android Recipes. Он пошел в совершенно ином направлении, используя собственный контейнер, который отключал детское вырезание, чтобы показывать более одной страницы за раз.

Его опубликованный пример кода показывает все в действии. Его контейнер ( com.example.pagercontainer.PagerContainer) оборачивает ViewPagerи вызывает setClipChildren(false);сам себя, поэтому даже если ViewPagerон сфокусирован на одной выбранной странице, другие страницы, имеющие координаты за пределами ViewPagerграниц, все еще видны, пока они вписываются в PagerContainer. Если размер ViewPagerменьше, чем размер PagerContainer, то ViewPagerразмер его страниц может быть увеличен , оставляя место для просмотра других страниц. PagerContainerТем не менее, нужно немного помочь с сенсорными событиями, так как они ViewPagerбудут обрабатывать только события свайпа на своих видимых границах, игнорируя любые страницы, видимые по сторонам.

введите описание изображения здесь


1
с помощью этого я могу показать часть предыдущей и следующей страницы, как показано на рисунке выше, но теперь я не хочу показывать острые края на изображениях. Я хочу, чтобы они размылись по краям. Я использую Z-индекс для достижения того же
Шрути

2
@Shruti - просто добавьте оверлейное изображение с нужным вам эффектом
Daniel L.

2
Я делаю то же самое, но это отключает эффект чрезмерной прокрутки для последнего элемента. Есть какие-либо выводы по этому поводу?
Сваям

1
@CommonsWare: Сэр, я попробовал ваше решение! Это сработало довольно хорошо. Там есть свиток. Единственная проблема сейчас заключается в том, что отображается следующая карта, но не предыдущая. То есть, если я на странице 2, я вижу, что страница 3 выглядывает наружу, но не страница 1. Где я мог пойти не так?
Сваям

2
@Swayam: Понятия не имею.
CommonsWare

110

У меня есть похожее решение:

На панели просмотра установите отступы влево и вправо, например, 20dp. Также установите поле страницы в пейджере, например, половину заполнения пейджера. И не забудьте отключить дополнение клипа.

tilePager.setPadding(defaultGap, 0, defaultGap, 0);
tilePager.setClipToPadding(false);
tilePager.setPageMargin(halfGap);

2
Хорошее решение при условии.
akash89


Это зверь да зверь ответ для рассмотрения именования значений
XD

1
примечание стороны: это не будет работать с пользовательским представлением преобразователя пейджера
voytez

@voytez какое-нибудь решение для трансформатора?
Алекс

76
  1. Установите левый и правый отступ для всего вида элемента. Пример xml (page_item.xml):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"/>
    
    <TextView
        android:id="@+id/text1"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    
    </LinearLayout>
    
  2. Затем установите отрицательное поле страницы PageViewравным 2 * (предыдущий вид)

    int margin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20*2,     getResources().getDisplayMetrics());
    mViewPager.setPageMargin(-margin);
    
  3. По желанию. Установите нулевое левое заполнение для первого элемента и нулевое правое заполнение для последнего элемента, чтобы скрыть пустые края. Вы можете сделать это в классе PageAdapterили Pageфрагменте.


@ Сергей, я не могу заставить это работать с твоим решением, не могли бы вы опубликовать пример? ТНХ
Marckaraujo

12
просто добавив примечание: с помощью этого решения, когда вы переходите со страницы 1 на страницу 2, страница 3 не в памяти, поэтому она появится с задержкой. чтобы исправить это просто добавьте - yourViewPager.setOffscreenPageLimit (2);
Хосе Барбоза

Я делаю то же самое, но это отключает эффект чрезмерной прокрутки для последнего элемента. Есть какие-либо выводы по этому поводу?
Сваям

Похоже, я не могу заставить это работать ... поля, кажется, отображаются случайным образом, если я использую изображения с масштабом, установленным по центру. У кого-нибудь есть пример рабочего кода, которым они могут поделиться?
кениее

2
Как прикоснуться к первому и последнему пункту? Проверяя индекс страницы в OnPageListener?
Hardik9850

47

Для предварительного просмотра левой и правой страниц установите следующие два значения

viewpager.setClipToPadding(false)
viewpager.setPadding(left,0,right,0)

Если вам нужно пространство между двумя страницами в viewpager, то добавьте viewpager.setPageMargin (int)

Android ViewPager - Показать предварительный просмотр страницы слева и справа


3
Это должен быть правильный ответ. Я думаю, возможно, это не сработало в предыдущих версиях viewpager, но теперь работает.
Грег Эннис

Это добавление одинакового поля на левой стороне первой и правой сторон последней страницы. Любое исправление
Umesh Aawte

1
Краткий и более четкий ответ.
Имран Ахмед

10

если кто-то все еще ищет решение, я настроил ViewPage для его достижения без использования отрицательного поля, найдите образец проекта здесь https://github.com/44kksharma/Android-ViewPager-Carousel-UI, в большинстве случаев он должен работать, но вы все еще можно определить поле страницы с mPager.setPageMargin(margin in pixel);


1

Загрузите исходный код отсюда ( ViewPager с границами предыдущей и следующей страницы )

MainActivity.java

package com.deepshikha.viewpager;

import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends FragmentActivity {

    ViewPager pager;
    MyPageAdapter obj_adapter;
    String str_device;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();


    }

    private void init() {
        pager = (ViewPager) findViewById(R.id.viewpager);
        differentDensityAndScreenSize(getApplicationContext());
        List<Fragment> fragments = getFragments();
        pager.setAdapter(obj_adapter);
        pager.setClipToPadding(false);


        if (str_device.equals("normal-hdpi")){
            pager.setPadding(160, 0, 160, 0);
        }else if (str_device.equals("normal-mdpi")){
            pager.setPadding(160, 0, 160, 0);
        }else if (str_device.equals("normal-xhdpi")){
            pager.setPadding(160, 0, 160, 0);
        }else if (str_device.equals("normal-xxhdpi")){
            pager.setPadding(180, 0, 180, 0);
        }else if (str_device.equals("normal-xxxhdpi")){
            pager.setPadding(180, 0, 180, 0);
        }else if (str_device.equals("normal-unknown")){
            pager.setPadding(160, 0, 160, 0);
        }else {

        }

        obj_adapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
        pager.setPageTransformer(true, new ExpandingViewPagerTransformer());
        pager.setAdapter(obj_adapter);
    }

    class MyPageAdapter extends FragmentPagerAdapter {

        private List<Fragment> fragments;

        public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {

            super(fm);

            this.fragments = fragments;

        }

        @Override

        public Fragment getItem(int position) {

            return this.fragments.get(position);

        }

        @Override

        public int getCount() {

            return this.fragments.size();

        }

    }

    private List<Fragment> getFragments() {

        List<Fragment> fList = new ArrayList<Fragment>();

        fList.add(MyFragment.newInstance("Fragment 1",R.drawable.imags));
        fList.add(MyFragment.newInstance("Fragment 2",R.drawable.image1));
        fList.add(MyFragment.newInstance("Fragment 3",R.drawable.image2));
        fList.add(MyFragment.newInstance("Fragment 4",R.drawable.image3));
        fList.add(MyFragment.newInstance("Fragment 5",R.drawable.image4));

        return fList;

    }

    public int differentDensityAndScreenSize(Context context) {
        int value = 20;
        String str = "";
        if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    str = "small-ldpi";
                    // Log.e("small 1","small-ldpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    str = "small-mdpi";
                    // Log.e("small 1","small-mdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    str = "small-hdpi";
                    // Log.e("small 1","small-hdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    str = "small-xhdpi";
                    // Log.e("small 1","small-xhdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    str = "small-xxhdpi";
                    // Log.e("small 1","small-xxhdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    str = "small-xxxhdpi";
                    //Log.e("small 1","small-xxxhdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    str = "small-tvdpi";
                    // Log.e("small 1","small-tvdpi");
                    value = 20;
                    break;
                default:
                    str = "small-unknown";
                    value = 20;
                    break;
            }

        } else if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    str = "normal-ldpi";
                    // Log.e("normal-ldpi 1","normal-ldpi");
                    str_device = "normal-ldpi";
                    value = 82;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    // Log.e("normal-mdpi 1","normal-mdpi");
                    str = "normal-mdpi";
                    value = 82;
                    str_device = "normal-mdpi";
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    // Log.e("normal-hdpi 1","normal-hdpi");
                    str = "normal-hdpi";
                    str_device = "normal-hdpi";
                    value = 82;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    //Log.e("normal-xhdpi 1","normal-xhdpi");
                    str = "normal-xhdpi";
                    str_device = "normal-xhdpi";
                    value = 90;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    // Log.e("normal-xxhdpi 1","normal-xxhdpi");
                    str = "normal-xxhdpi";
                    str_device = "normal-xxhdpi";
                    value = 96;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    //Log.e("normal-xxxhdpi","normal-xxxhdpi");
                    str = "normal-xxxhdpi";
                    str_device = "normal-xxxhdpi";
                    value = 96;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    //Log.e("DENSITY_TV 1","normal-mdpi");
                    str = "normal-tvdpi";
                    str_device = "normal-tvmdpi";
                    value = 96;
                    break;
                default:
                    // Log.e("normal-unknown","normal-unknown");
                    str = "normal-unknown";
                    str_device = "normal-unknown";
                    value = 82;
                    break;
            }
        } else if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    str = "large-ldpi";
                    // Log.e("large-ldpi 1","normal-ldpi");
                    value = 78;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    str = "large-mdpi";
                    //Log.e("large-ldpi 1","normal-mdpi");
                    value = 78;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    //Log.e("large-ldpi 1","normal-hdpi");
                    str = "large-hdpi";
                    value = 78;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    // Log.e("large-ldpi 1","normal-xhdpi");
                    str = "large-xhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    //Log.e("large-ldpi 1","normal-xxhdpi");
                    str = "large-xxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    // Log.e("large-ldpi 1","normal-xxxhdpi");
                    str = "large-xxxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    //Log.e("large-ldpi 1","normal-tvdpi");
                    str = "large-tvdpi";
                    value = 125;
                    break;
                default:
                    str = "large-unknown";
                    value = 78;
                    break;
            }

        } else if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    // Log.e("large-ldpi 1","normal-ldpi");
                    str = "xlarge-ldpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    // Log.e("large-ldpi 1","normal-mdpi");
                    str = "xlarge-mdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    //Log.e("large-ldpi 1","normal-hdpi");
                    str = "xlarge-hdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    // Log.e("large-ldpi 1","normal-hdpi");
                    str = "xlarge-xhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    // Log.e("large-ldpi 1","normal-xxhdpi");
                    str = "xlarge-xxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    // Log.e("large-ldpi 1","normal-xxxhdpi");
                    str = "xlarge-xxxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    //Log.e("large-ldpi 1","normal-tvdpi");
                    str = "xlarge-tvdpi";
                    value = 125;
                    break;
                default:
                    str = "xlarge-unknown";
                    value = 125;
                    break;
            }
        }

        return value;
    }
}

1
Этот код не работает должным образом, его левая боковая страница немного больше правой
Chirag Joshi

1

Некоторое время назад мне нужна такая особенность и подготовил крошечную библиотеку , которая использует RecyclerViewс PagerSnapHelper (добавлено в версии 25.1.0 библиотеки поддержки v7) вместо классического ViewPager:

MetalRecyclerPagerView - вы можете найти весь код вместе с примерами там.

В основном он состоит из одного файла класса: MetalRecyclerViewPager.java (и двух xmls: attrs.xml и ids.xml ).

Надеюсь, это кому-нибудь поможет :)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.