Android ViewPager - Hiển thị bản xem trước của trang ở bên trái và bên phải


107

Tôi đang sử dụng Android ViewPager. Những gì tôi muốn làm là hiển thị bản xem trước của trang ở cả bên trái và bên phải. Tôi đã thấy nơi tôi có thể sử dụng âm bản pageMarginđể hiển thị bản xem trước của mặt phải.

setPageMargin(-100);

Có cách nào mà tôi có thể hiển thị bản xem trước của phía bên trái không? Về cơ bản nó tương tự như widget thư viện mà tôi đang tìm kiếm.


Câu hỏi hay! Gần đây tôi đã kiểm tra nguồn và tôi cảm thấy không có cách nào tốt hơn nếu bạn không muốn sửa đổi mã src. Làm setPageMargin(-100)việc có chính xác không?
Macarse

GalleryView sẽ thực hiện công việc tốt hơn, trừ khi bạn đang sử dụng ViewPger với các phân đoạn.
Ali AlNoaimi

Tôi đã có thể làm điều này bằng cách sử dụng chế độ xem thư viện. giống như viewpager theo bất kỳ cách nào. không biết tại sao thư viện không được dùng nữa
WillingLearner

Câu hỏi này kể từ đó đã được đề cập rộng rãi trong [bài đăng ở đây] [1] [1]: stackoverflow.com/questions/13914609/…
Ben Pearson

Tôi đang sử dụng Vierpager với các phân đoạn. Vậy tôi có thể sử dụng phương pháp tương tự không?
asliyanage

Câu trả lời:


206

Để hiển thị bản xem trước của các trang bên trái và bên phải, hãy đặt hai giá trị sau

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

Nếu bạn cần khoảng cách giữa hai trang trong viewpager thì hãy thêm

viewpager.setPageMargin(int);

2
Có, tôi đồng ý với bạn Jiju Induchoodan .. Để biết thêm thông tin, vui lòng tham khảo blog.neteril.org/blog/2013/10/14/…stackoverflow.com/questions/13914609/…
Sripathi

Thật tuyệt, thật đơn giản :) Có thể thay đổi kích thước bản xem trước ở kích thước bên phải và bên trái trên chuyển đổi các trang của chế độ xem không? Ví dụ - nếu phân mảnh nằm ngoài tiêu điểm - tỷ lệ của nó sẽ là ~ 0,8, nhưng khi chúng ta kéo nó vào trung tâm - tỷ lệ sẽ tăng lên 1 và phân đoạn trước đó từ chế độ xem trung tâm sẽ thay đổi tỷ lệ thành 0,8 khi ra ngoài màn hình?
iamthevoid

Điều này đang hoạt động! Nhưng khi tôi cố gắng thu phóng bố cục trung tâm, việc thu phóng của nó lên trên và dưới. Bên trái và bên phải không được nhìn thấy do đệm. Vui lòng xem câu hỏi stackoverflow.com/questions/52710076/…
Anooj Krishnan G

không hoạt động với viewpager 2
hamiid reza Gholami

73

Câu trả lời của @JijuInduchoodan là hoàn hảo và hiệu quả. Tuy nhiên, vì tôi còn tương đối mới với Android, tôi đã mất một thời gian để hiểu và thiết lập nó đúng cách. Vì vậy, tôi đăng câu trả lời này để tham khảo trong tương lai và giúp đỡ bất kỳ ai khác có cùng hoàn cảnh với tôi.

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

Không cần đặt bất kỳ chiều rộng nào cho ViewPager'strang trong bộ điều hợp. Không cần mã bổ sung để xem trang trước và trang tiếp theo ViewPager. Tuy nhiên, nếu bạn muốn thêm khoảng trống ở đầu và cuối mỗi trang, bạn có thể đặt mã sau thành ViewPager'sbố cục mẹ của trang con.

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

Xem cuối cùng

Đây sẽ là giao diện cuối cùng của ViewPager.


62

Giải pháp với ViewPager2 mới

Ngày nay, bạn nên xem xét sử dụng ViewPager2 đó "thay thế ViewPager, giải quyết đa số người tiền nhiệm của nó của đau-điểm" :

  • Dựa trên RecyclerView
  • Hỗ trợ bố cục RTL (từ phải sang trái)
  • Hỗ trợ định hướng dọc
  • Hỗ trợ Fragment đáng tin cậy (bao gồm xử lý các thay đổi đối với tập hợp Fragment cơ bản)
  • Hoạt ảnh thay đổi tập dữ liệu (bao gồm cả DiffUtilhỗ trợ)

Kết quả

nhập mô tả hình ảnh ở đây

Mật mã

Trong Activity / Fragment của bạn, hãy thiết lập 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)

Thêm dấu HorizontalMarginItemDecoration, đó là một điều tầm thường 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
    }

}

Thêm các thứ nguyên kiểm soát mức độ hiển thị của mục trước / sau và lề ngang của mục hiện tại:

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

nhập mô tả hình ảnh ở đây

Cuối cùng thêm ViewPager2vào bố cục của bạn:

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

Một điều quan trọng: một ViewPager2mục phải có layout_height="match_parent"(nếu không nó sẽ ném ra IllegalStateException), vì vậy bạn nên làm điều gì đó như:

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

Ví dụ về PageTransformer

Google đã thêm một hướng dẫn về ViewPager2 có 2 cách PageTransformertriển khai mà bạn có thể sử dụng làm nguồn cảm hứng: https://developer.android.com/training/animation/screen-slide-2

Giới thiệu về ViewPager2 mới


Vấn đề tương tự trên các thiết bị oreo, phần đệm bắt đầu và kết thúc hoạt động như mong đợi trên các thiết bị khác nhưng oreo sau ViewPager2. PageTransformer giải quyết vấn đề này, miếng đệm không vẫn còn đó và tôi đã phải thêmviewpager.setPageTransformer { page, position -> page.translationX = -1 * position }
zgr

Tôi phải di chuyển một chút trang của máy nhắn tin xem để có được hiệu ứng này
Muhammad Saqib

setOffscreenPageLimit(1)
Muhammad Saqib

Đây là giải pháp tốt nhất mà tôi từng tìm thấy. Nó hoạt động hoàn hảo nhưng có ĐỪNG QUÊN thiết lập chiều rộng, chiều cao của mục ViewPager2 thành MATCH_PARENT.
khushbu

26

Trong năm 2017, hành vi này cũng có thể dễ dàng đạt được bằng cách sử dụng RecyclerViewvới PagerSnapHelper (được bổ sung trong phiên bản 25.1.0 của thư viện hỗ trợ v7): 

nhập mô tả hình ảnh ở đây

Trước đây, tôi cần tính năng giống như viewpager như vậy và đã chuẩn bị một thư viện nhỏ:

MetalRecyclerPagerView - bạn có thể tìm thấy tất cả mã cùng với các ví dụ ở đó.

Về cơ bản, nó bao gồm một tệp lớp duy nhất: MetalRecyclerViewPager.java (và hai xmls: attrs.xmlids.xml ).

Hy vọng nó sẽ giúp ai đó và sẽ tiết kiệm được vài giờ :)


Lạc đề, vì đôi khi chỉ cần máy nhắn tin nhưng Rất vui được biết! Cám ơn vì đã chia sẻ!
sud007

Điều này thật tuyệt. Tôi đã có hàng tấn mã trình trợ giúp RecyclerView. Chỉ cần thêm một đơn giản new PagerSnapHelper().attachToRecyclerView(recyclerView)và tôi đã chụp trang.
Steve

9

nếu ai đó vẫn đang tìm kiếm giải pháp, tôi đã tùy chỉnh ViewPage để đạt được nó mà không sử dụng lợi nhuận âm, hãy tìm một dự án mẫu tại đây https://github.com/44kksharma/Android-ViewPager-Carousel-UI, nó sẽ hoạt động trong hầu hết các trường hợp nhưng bạn vẫn có thể xác định lề trang với mPager.setPageMargin(margin in pixel);


7

Bạn có thể thực hiện việc này trong tệp xml, chỉ cần sử dụng mã dưới đây:

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

Ví dụ:

<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" />

Lưu ý: Nếu bạn cần khoảng cách giữa các trang, hãy đặt đệm / lề thành các đoạn con


3
Tôi đã phản đối. xin lỗi anh bạn. Lần này nó đã hoạt động !! Bình chọn một lần nữa
shikhar bannsal

1

Đối với những người đang đấu tranh để có điều này trên các màn hình khác nhau,

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

Lưu ý rằng khi không đặt không có đệm nào cho một máy ngắm, vị trí đặt cạnh của máy ngắm sẽ bị lộn xộn, đây là một lỗi của máy xem, xem tại đây: lỗi edgeeffect của máy xempager

Bạn có thể vô hiệu hóa hiệu ứng cạnh bằng cách đặt android:overScrollMode="never"thành máy ngắm hoặc bạn có thể sửa lỗi bằng phiên bản sửa đổi một chút của lớp EdgeEffect: Sửa lỗi ViewPagerEdgeEffect


-10

Sử dụng lớp và bộ điều hợp phân đoạn này để xem khung nhìn trong cuộn sang trái và phải. Thêm các lớp cần thiết để cuộn để xem các trang tiếp theo.

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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.