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

107

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

setPageMargin(-100);

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

Брайан Бойл
источник
Хороший вопрос! Я недавно проверил исходный код и считаю, что нет лучшего способа, если вы не хотите изменять код src. setPageMargin(-100)Правильно ли работает?
Macarse
GalleryView справится с этой задачей лучше, если вы не используете ViewPger с фрагментами.
Али Аль-Ноайми 01
Я смог сделать это, используя вид галереи. так же, как вьюпейджер. не знаю, почему галерея устарела
WillingLearner
С тех пор этот вопрос был подробно рассмотрен в [сообщении здесь] [1] [1]: stackoverflow.com/questions/13914609/…
Бен Пирсон
Я использую Vierpager с фрагментами, могу ли я использовать тот же подход?
asliyanage

Ответы:

206

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

  1. viewpager.setClipToPadding(false);
  2. viewpager.setPadding(left,0,right,0);

Если вам нужно пространство между двумя страницами в окне просмотра, добавьте

viewpager.setPageMargin(int);
Джиджу Индукхудан
источник
2
Да, я согласен с вами, Джиджу Индукхудан .. Для получения дополнительной информации, пожалуйста, обратитесь к blog.neteril.org/blog/2013/10/14/… и stackoverflow.com/questions/13914609/…
Sripathi
Круто, это так просто :) Есть ли возможность изменять размеры превью справа и слева при переключении страниц просмотра пейджера? Например - если фрагмент не в фокусе - его масштаб будет ~ 0,8, но когда мы перетащим его в центр - масштаб увеличится до 1, а предыдущий фрагмент из центра изменит масштаб на 0,8 при выходе за пределы экрана?
iamthevoid
Это работает! Но когда я пытаюсь увеличить центральный макет, он увеличивается вверх и вниз. Левая и правая не видны из-за заполнения. См. Вопрос stackoverflow.com/questions/52710076/…
Anooj Krishnan G
не работает с viewpager 2
hamiid reza Gholami
73

Ответ @JijuInduchoodan идеален и работает. Однако, поскольку я относительно новичок в Android, мне потребовалось время, чтобы понять и правильно его настроить. Итак, я отправляю этот ответ для использования в будущем и помогаю всем, кто находится на том же уровне, что и я.

if (viewPager == null) 
        {

            // Initializing view pager
            viewPager = (ViewPager) findViewById(R.id.vpLookBook);

            // Disable clip to padding
            viewPager.setClipToPadding(false);
            // set padding manually, the more you set the padding the more you see of prev & next page
            viewPager.setPadding(40, 0, 40, 0);
            // sets a margin b/w individual pages to ensure that there is a gap b/w them
            viewPager.setPageMargin(20);
        }

Нет необходимости устанавливать ширину ViewPager'sстраницы в адаптере. Дополнительный код не требуется для просмотра предыдущей и следующей страницы в ViewPager. Однако, если вы хотите добавить пустое пространство вверху и внизу каждой страницы, вы можете установить следующий код для ViewPager'sродительского макета дочерней страницы.

android:paddingTop="20dp"
android:paddingBottom="20dp"

Окончательный ViewPager

Это будет окончательный вид ViewPager.

Рохан Кандвал
источник
64

Решение с новым ViewPager2

В настоящее время вам следует подумать об использовании ViewPager2, который «заменяет ViewPager, устраняя большинство болевых точек своего предшественника» :

  • На основе RecyclerView
  • Поддержка макета RTL (справа налево)
  • Поддержка вертикальной ориентации
  • Надежная поддержка фрагментов (включая обработку изменений в базовой коллекции фрагментов)
  • Анимация изменения набора данных (включая DiffUtilподдержку)

Результат

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

Код

В вашем Activity / Fragment настройте ViewPager2:

// MyRecyclerViewAdapter is an standard RecyclerView.Adapter :)
viewPager2.adapter = MyRecyclerViewAdapter() 

// You need to retain one page on each side so that the next and previous items are visible
viewPager2.offscreenPageLimit = 1

// Add a PageTransformer that translates the next and previous items horizontally
// towards the center of the screen, which makes them visible
val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
val currentItemHorizontalMarginPx = resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
val pageTransformer = ViewPager2.PageTransformer { page: View, position: Float ->
    page.translationX = -pageTranslationX * position
    // Next line scales the item's height. You can remove it if you don't want this effect
    page.scaleY = 1 - (0.25f * abs(position))
    // If you want a fading effect uncomment the next line:
    // page.alpha = 0.25f + (1 - abs(position))
}
viewPager2.setPageTransformer(pageTransformer)

// The ItemDecoration gives the current (centered) item horizontal margin so that
// it doesn't occupy the whole screen width. Without it the items overlap
val itemDecoration = HorizontalMarginItemDecoration(
    context,
    R.dimen.viewpager_current_item_horizontal_margin
)
viewPager2.addItemDecoration(itemDecoration)

Добавьте HorizontalMarginItemDecoration, что тривиально ItemDecoration:

/**
 * Adds margin to the left and right sides of the RecyclerView item.
 * Adapted from https://stackoverflow.com/a/27664023/4034572
 * @param horizontalMarginInDp the margin resource, in dp.
 */
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
    RecyclerView.ItemDecoration() {

    private val horizontalMarginInPx: Int =
        context.resources.getDimension(horizontalMarginInDp).toInt()

    override fun getItemOffsets(
        outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
    ) {
        outRect.right = horizontalMarginInPx
        outRect.left = horizontalMarginInPx
    }

}

Добавьте размеры, которые контролируют, насколько предыдущий / следующий элемент виден, и горизонтальное поле текущего элемента:

<dimen name="viewpager_next_item_visible">26dp</dimen>
<dimen name="viewpager_current_item_horizontal_margin">42dp</dimen>

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

Наконец, добавьте в ViewPager2свой макет:

<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

Одна важная вещь: ViewPager2элемент должен иметь layout_height="match_parent"(иначе возникает исключение IllegalStateException), поэтому вы должны сделать что-то вроде:

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" <-- this!
    app:cardCornerRadius="8dp"
    app:cardUseCompatPadding="true">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="280dp">

        <!-- ... -->

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

Примеры PageTransformer

Google добавил руководство по ViewPager2, в котором есть 2 PageTransformerреализации, которые вы можете использовать в качестве вдохновения: https://developer.android.com/training/animation/screen-slide-2

О новом ViewPager2

Альберт Вила Кальво
источник
Та же проблема на устройствах oreo, начало и конец заполнения работают должным образом на других устройствах, но oreo после ViewPager2. PageTransformer решил проблему, отступы остались прежними, и мне пришлось добавитьviewpager.setPageTransformer { page, position -> page.translationX = -1 * position }
zgr
Мне нужно немного переместить страницу пейджера просмотра, чтобы получить этот эффект
Мухаммад Сакиб
неважно, я забыл добавить эту строчку setOffscreenPageLimit(1):)
Мухаммад Сакиб
Это лучшее решение, которое я когда-либо находил. Он работает отлично, но да, НЕ ЗАБЫВАЙТЕ установить для ViewPager2 Item width, height значение MATCH_PARENT.
хушбу
26

В 2017 году такого поведения дополнительно может быть легко достигнут путем использования RecyclerViewс PagerSnapHelper (добавлено в версии 25.1.0 библиотеки поддержки v7): 

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

Некоторое время назад мне понадобилась такая функция, как вьюпейджер, и я подготовил крошечную библиотеку:

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

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

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

Александр Бильчук
источник
Не по теме, потому что иногда нужен только пейджер, но это приятно! Спасибо, что поделился!
sud007
Это круто. У меня уже было много вспомогательного кода RecyclerView. Просто добавив простой, у new PagerSnapHelper().attachToRecyclerView(recyclerView)меня есть привязка к странице.
Стив
9

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

44kksharma
источник
7

Вы можете сделать это в файле xml, просто используйте приведенный ниже код:

 android:clipToPadding="false"
 android:paddingLeft="XX"
 android:paddingRight="XX"

Например:

<androidx.viewpager.widget.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:paddingLeft="30dp"
        android:paddingRight="30dp" />

Примечание: если вам нужно пространство между страницами, установите отступы / поля для дочерних фрагментов.

sma6871
источник
3
Я проголосовал против. Извини брат. На этот раз сработало !! Проголосовали снова
бансал шихара
1

Для тех, кто изо всех сил пытается отобразить это на разных экранах,

mPager.setClipToPadding(false);
DisplayMetrics displayMetrics = new DisplayMetrics();
self.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int paddingToSet = width/4; //set this ratio according to how much of the next and previos screen you want to show.
mPager.setPadding(paddingToSet,0,paddingToSet,0);
Саураб Верма
источник
0

Обратите внимание, что при установке нулевого заполнения для окна просмотра, размещение эффекта края окна просмотра искажается, это ошибка окна просмотра, см. Здесь: ошибка пограничного эффекта окна просмотра

Вы можете отключить краевой эффект, установив android:overScrollMode="never"окно просмотра, или исправить ошибку с помощью слегка измененной версии класса EdgeEffect : исправление ViewPagerEdgeEffect

ssynhtn
источник
-10

Используйте этот адаптер фрагмента и класс для просмотра окна просмотра в левой и правой прокрутке. Добавьте необходимые классы для прокрутки для просмотра следующих страниц.

package com.rmn.viewpager;

import java.util.List;

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

/**
 * The <code>PagerAdapter</code> serves the fragments when paging.
 * @author mwho
 */
public class PagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments;
    /**
     * @param fm
     * @param fragments
     */
    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }
    /* (non-Javadoc)
     * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
     */
    @Override
    public Fragment getItem(int position) {
        return this.fragments.get(position);
    }

    /* (non-Javadoc)
     * @see android.support.v4.view.PagerAdapter#getCount()
     */
    @Override
    public int getCount() {
        return this.fragments.size();
    }
}



package com.manishkpr.viewpager;


import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {
    private Context _context;

    public ViewPagerAdapter(Context context, FragmentManager fm) {
        super(fm);  
        _context=context;

        }
    @Override
    public Fragment getItem(int position) {
        Fragment f = new Fragment();
        switch(position){
        case 0:
            f=LayoutOne.newInstance(_context);  
            break;
        case 1:
            f=LayoutTwo.newInstance(_context);  
            break;
        }
        return f;
    }
    @Override
    public int getCount() {
        return 2;
    }

}
Veerababu Medisetti
источник