ViewPager với ranh giới trang trước và trang tiếp theo


144

Tôi đang thiết kế một khung nhìn với nhiều trang. Tôi muốn các cạnh của trang trước và trang tiếp theo được hiển thị như bên dưới và thực hiện thao tác vuốt 2 ngón tay để chuyển giữa các trang.

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

Tôi đã thử sử dụng ViewPagervới lề trang âm như được đề xuất ở đây nhưng điều đó chỉ hiển thị một trong các cạnh trên màn hình, không phải cả hai cùng một lúc.

Ngoài ra, có cách nào tôi có thể định vị một phần của chế độ xem bên ngoài màn hình và sau đó làm động nó để tạo ViewPagerhiệu ứng loại.

Làm thế nào tôi nên đi về nó? Cảm ơn !


"chỉ hiển thị một trong các cạnh trên màn hình, không hiển thị đồng thời cả hai." Bạn đang ở trang 0 và bạn chỉ thấy một phần của trang 1? Có lẽ bạn cần sử dụng một máy nhắn tin tròn, ví dụ và sau đó đặt trang của bạn luôn ở vị trí "giữa". Xem bài đăng này và nhận xét: stackoverflow.com/a/8304474/1851478
logray 20/12/12

Câu trả lời:


100

Trích dẫn bản thân từ một bài đăng trên blog về chủ đề này :

Cách tiếp cận thứ ba đến từ Dave Smith, đồng tác giả của cuốn sách được đánh giá cao Android Recipes. Anh ta đi theo một hướng rất khác, sử dụng một thùng chứa tùy chỉnh khiến trẻ em bị vô hiệu hóa để hiển thị nhiều trang cùng một lúc.

Mã mẫu được công bố của ông cho thấy toàn bộ trong hành động. Container của anh ấy ( com.example.pagercontainer.PagerContainer) bao bọc ViewPagervà gọi setClipChildren(false);chính nó, vì vậy mặc dù ViewPagertập trung vào một trang được chọn, các trang khác có tọa độ nằm ngoài ViewPagergiới hạn vẫn hiển thị, miễn là chúng phù hợp với PagerContainer. Bằng cách định cỡ ViewPagercho nhỏ hơn PagerContainer, ViewPagercó thể kích thước các trang của nó theo kích thước đó, chừa chỗ cho các trang khác được nhìn thấy. PagerContainertuy nhiên, cần phải giúp đỡ một chút với các sự kiện chạm, vì ViewPagersẽ chỉ xử lý các sự kiện vuốt trên giới hạn hiển thị của chính nó, bỏ qua bất kỳ trang nào hiển thị ở hai bên.

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


1
bằng cách sử dụng điều này, tôi có thể hiển thị một phần của trang trước và trang tiếp theo như được hiển thị trong hình trên, nhưng bây giờ tôi không muốn hiển thị các cạnh sắc nét trên hình ảnh. Tôi muốn chúng mờ về phía các cạnh .. xin vui lòng hướng dẫn cho tôi cách có thể tôi sử dụng chỉ số z để đạt được điều tương tự
Shruti

2
@Shruti - chỉ cần thêm một hình ảnh lớp phủ với hiệu ứng bạn muốn
Daniel L.

2
Tôi làm tương tự nhưng nó vô hiệu hóa hiệu ứng cuộn qua cho mục cuối cùng. Bất kỳ dẫn đến đó?
Swayam

1
@CommonsWare: Thưa ông, tôi đã thử giải pháp của bạn! Nó hoạt động khá tốt. Các overscroll là ở đó. Vấn đề duy nhất bây giờ là thẻ tiếp theo hiển thị, nhưng không phải thẻ trước đó. Đó là, nếu tôi ở trang 2, tôi có thể thấy trang 3 nhìn trộm, nhưng không phải trang 1. Tôi có thể đã sai ở đâu?
Swayam

2
@Swayam: Tôi không có ý kiến.
CommonsWare

110

Tôi có một giải pháp tương tự:

Trên chế độ xem, đặt phần đệm bên trái và bên phải, ví dụ 20dp. Cũng đặt lề trang trên chế độ xem, ví dụ: một nửa phần đệm máy nhắn tin. Và đừng quên tắt clip đệm.

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

2
Giải pháp tốt được cung cấp.
akash89

Cách dễ nhất và tốt nhất
HannahCarney

Đây là câu trả lời con thú có con thú để xem xét đặt tên giá trị xd
silentsudo

1
lưu ý phụ: điều này sẽ không hoạt động với một biến áp máy nhắn tin xem tùy chỉnh
Voytez

@voytez giải pháp nào cho máy biến áp?
Alex

76
  1. Đặt phần đệm bên trái và bên phải cho toàn bộ mục xem. Ví dụ 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. Sau đó đặt lề trang âm cho PageViewbằng 2 * (phần đệm xem trước đó)

    int margin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20*2,     getResources().getDisplayMetrics());
    mViewPager.setPageMargin(-margin);
  3. Không bắt buộc. Đặt phần đệm bên trái bằng không cho mục đầu tiên và phần đệm bên phải bằng 0 cho mục cuối cùng để ẩn các cạnh trống. Bạn có thể làm điều này trong lớp PageAdapterhoặc Pageđoạn.


@Sergey, tôi không thể thực hiện công việc này với giải pháp của bạn, bạn có thể gửi một ví dụ không? thx
Marckaraujo

12
chỉ cần thêm một ghi chú: với giải pháp này khi bạn trượt từ trang 1 sang trang 2, trang 3 không có trong bộ nhớ, vì vậy nó sẽ xuất hiện với độ trễ. để khắc phục điều này, chỉ cần thêm - yourViewPager.setPackscreenPageLimit (2);
Jose Barbosa

Tôi làm tương tự nhưng nó vô hiệu hóa hiệu ứng cuộn qua cho mục cuối cùng. Bất kỳ dẫn đến đó?
Swayam

Tôi dường như không thể làm cho điều này hoạt động được ... lề dường như hiển thị ngẫu nhiên nếu tôi sử dụng hình ảnh được đặt ở tỷ lệ trung tâm. Bất cứ ai có một ví dụ mã làm việc họ có thể chia sẻ?
kenyee

2
Làm thế nào để chạm vào mục đầu tiên và cuối cùng? Bằng cách kiểm tra chỉ mục trang trong OnPageListener?
Hardik9850

47

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

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

Nếu bạn cần khoảng trống giữa hai trang trong chế độ xem, hãy thêm viewpager.setPageMargin (int)

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


3
Điều này nên được trả lời đúng. Tôi nghĩ có lẽ điều này không hoạt động trong các phiên bản trước của viewpager nhưng nó hoạt động ngay bây giờ.
Greg Enni

Nó cũng thêm cùng một lề ở bên trái của bên đầu tiên và bên phải của trang cuối cùng. Bất kỳ sửa chữa
Umesh Aawte

1
Câu trả lời ngắn gọn và rõ ràng hơn.
Imran Ahmed

10

Nếu ai đó vẫn đang tìm giải pháp, tôi đã tùy chỉnh ViewPage để đạt được nó mà không sử dụng lề â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);


1

Tải xuống mã nguồn từ đây ( ViewPager với các ranh giới trang trước và tiếp theo )

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
Mã này không hoạt động chính xác, nó hiển thị trang bên trái lớn hơn một chút so với bên phải
Chirag Joshi

1

Cách đây không lâu, tôi cần tính năng như vậy và đã chuẩn bị một thư viện nhỏ sử dụng RecyclerViewvới PagerSnapHelper (được thêm vào trong phiên bản 25.1.0 của thư viện hỗ trợ v7) thay vì cổ điển ViewPager:

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

Chủ yếu 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 được ai đó :)

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.