ViewPager ที่มีขอบเขตหน้าก่อนหน้าและถัดไป


145

ฉันกำลังออกแบบมุมมองที่มีหลายหน้า ฉันต้องการให้ขอบของหน้าก่อนหน้าและหน้าถัดไปแสดงแบบด้านล่างและใช้การปัดสองนิ้วเพื่อสลับระหว่างหน้า

ป้อนคำอธิบายรูปภาพที่นี่

ฉันลองใช้โดยViewPagerมีขอบหน้าติดลบตามที่แนะนำที่นี่แต่แสดงให้เห็นเพียงหนึ่งในขอบบนหน้าจอไม่ใช่ทั้งสองอย่างพร้อมกัน

อีกวิธีหนึ่งคือมีวิธีใดที่ฉันสามารถวางตำแหน่งส่วนหนึ่งของมุมมองของฉันนอกหน้าจอแล้วเคลื่อนไหวมันให้ViewPagerผลชนิด

ฉันจะไปเกี่ยวกับมันได้อย่างไร ขอบคุณมาก!


"แสดงเพียงหนึ่งในขอบบนหน้าจอไม่ใช่ทั้งสองอย่างพร้อมกัน" คุณอยู่ในหน้า 0 และคุณเห็นเพียงบางส่วนของหน้า 1 บางทีคุณอาจต้องใช้เพจเจอร์แบบวงกลมยกตัวอย่างเช่นจากนั้นตั้งค่าเพจของคุณให้อยู่ในตำแหน่ง "กลาง" เสมอ ดูโพสต์นี้และความคิดเห็น: stackoverflow.com/a/8304474/1851478
logray

คำตอบ:


100

อ้างตัวเองจากโพสต์บล็อกในเรื่องนี้ :

วิธีที่สามมาจาก Dave Smith ผู้เขียนร่วมของตำรับตำรา Android ที่มีชื่อเสียง เขาไปในทิศทางที่แตกต่างกันมากโดยใช้คอนเทนเนอร์แบบกำหนดเองที่ปิดใช้งานเด็ก ๆ การตัดเพื่อแสดงมากกว่าหนึ่งหน้าในแต่ละครั้ง

โค้ดตัวอย่างที่เผยแพร่ของเขาแสดงให้เห็นถึงการดำเนินการทั้งหมด ภาชนะของพระองค์ ( com.example.pagercontainer.PagerContainer) ห่อViewPagerและบริการโทรsetClipChildren(false);ในตัวเองดังนั้นแม้ว่าจะViewPagerมุ่งเน้นไปที่หน้าเลือกหนึ่งในหน้าอื่น ๆ ที่มีพิกัดเกินขอบเขตยังคงมองเห็นตราบใดที่พวกเขาพอดีภายในViewPager PagerContainerโดยการปรับขนาดViewPagerจะมีขนาดเล็กกว่าPagerContainerที่ViewPagerขนาดกระป๋องหน้าเว็บของตนให้มีขนาดที่ออกจากห้องสำหรับหน้าอื่น ๆ ที่จะเห็น PagerContainerอย่างไรก็ตามต้องการความช่วยเหลือเล็กน้อยเกี่ยวกับกิจกรรมการสัมผัสเช่นเดียวกับที่ViewPagerจะจัดการเหตุการณ์ปัดบนขอบเขตที่มองเห็นได้ของตัวเองโดยไม่สนใจหน้าใด ๆ ที่มองเห็นได้จากด้านข้าง

ป้อนคำอธิบายรูปภาพที่นี่


1
ด้วยการใช้สิ่งนี้ฉันสามารถแสดงส่วนหนึ่งของหน้าก่อนหน้าและหน้าถัดไปตามที่แสดงในภาพด้านบน แต่ตอนนี้ฉันไม่ต้องการแสดงขอบที่คมชัดบนภาพฉันต้องการให้พวกเขาเบลอไปทางขอบ ฉันใช้ z-index เพื่อบรรลุเป้าหมายเดียวกัน
Shruti

2
@Shruti - เพียงแค่เพิ่มภาพซ้อนทับที่มีเอฟเฟกต์ที่คุณต้องการ
Daniel L.

2
ฉันทำเช่นเดียวกัน แต่จะปิดการใช้งานเอฟเฟกต์โอเวอร์ - สโครลสำหรับรายการสุดท้าย มีโอกาสในการขายอะไรบ้าง
Swayam

1
@CommonsWare: ท่านฉันลองใช้วิธีแก้ปัญหาของคุณ! มันใช้งานได้ดีทีเดียว โอเวอร์ครอลอยู่ตรงนั้น ปัญหาเฉพาะตอนนี้คือบัตรใบถัดไปแสดง แต่ไม่ใช่บัตรใบก่อนหน้า นั่นคือถ้าฉันอยู่ในหน้า 2 ฉันจะเห็นหน้า 3 โผล่ออกมา แต่ไม่ใช่หน้า 1 ฉันจะไปไหนผิด
Swayam

2
@Samam: ฉันไม่มีความคิด
CommonsWare

111

ฉันมีทางออกที่คล้ายกัน:

ใน viewpager กำหนดซ้ายและขวา padding เช่น 20dp อย่าตั้งค่าระยะขอบหน้าบน viewpager เช่นครึ่งหนึ่งของการ pager padding และอย่าลืมปิดการใช้งานการขยายคลิป

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

2
ทางออกที่ดีให้
akash89

วิธีที่ง่ายที่สุดและดีที่สุด
HannahCarney

นี่คือสัตว์ร้ายใช่คำตอบของสัตว์ร้ายเพื่อพิจารณาการตั้งชื่อค่า xd
silentsudo

1
หมายเหตุข้างต้น: สิ่งนี้จะใช้งานไม่ได้กับหม้อแปลงเพจเจอร์ที่กำหนดเอง
voytez

@voytez วิธีแก้ปัญหาสำหรับหม้อแปลงใด ๆ
Alex

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ส่วน


@ Sergey ฉันไม่สามารถใช้งานโซลูชันของคุณได้คุณช่วยโพสต์ตัวอย่างได้ไหม? ขอบคุณ
Marckaraujo

12
เพียงแค่เพิ่มบันทึกย่อ: ด้วยโซลูชันนี้เมื่อคุณเลื่อนจากหน้า 1 ถึงหน้า 2 หน้า 3 ไม่ได้อยู่ในหน่วยความจำดังนั้นจึงจะปรากฏพร้อมหน่วงเวลา เพื่อแก้ไขปัญหานี้เพียงแค่เพิ่ม - yourViewPager.setOffscreenPageLimit (2);
José Barbosa

ฉันทำเช่นเดียวกัน แต่จะปิดการใช้งานเอฟเฟกต์โอเวอร์ - สโครลสำหรับรายการสุดท้าย มีโอกาสในการขายอะไรบ้าง
Swayam

ฉันไม่สามารถทำให้สิ่งนี้ทำงานได้ ... ขอบดูเหมือนจะแสดงแบบสุ่มถ้าฉันใช้รูปภาพที่มีการตั้งค่าระดับการครอบตัดตรงกลาง ใครมีตัวอย่างรหัสที่ใช้งานได้ที่พวกเขาสามารถแชร์ได้
kenyee

2
วิธีการสัมผัสรายการแรกและสุดท้าย? โดยการตรวจสอบดัชนีหน้าใน OnPageListener?
Hardik9850

48

หากต้องการแสดงตัวอย่างหน้าซ้ายและขวาให้ตั้งค่าสองค่าต่อไปนี้

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

หากคุณต้องการช่องว่างระหว่างสองหน้าใน viewpager ให้เพิ่ม viewpager.setPageMargin (int)

Android ViewPager - แสดงตัวอย่างของหน้าทางซ้ายและขวา


3
นี่ควรเป็นคำตอบที่ถูกต้อง ฉันคิดว่านี่อาจใช้ไม่ได้กับวิวเวอร์เพจเจอร์เวอร์ชันก่อนหน้า
เกร็กเอนนิส

การเพิ่มระยะขอบเดียวกันที่ด้านซ้ายของหน้าแรกและด้านขวาของหน้าสุดท้ายเช่นกัน การแก้ไขใด ๆ
Umesh Aawte

1
คำตอบที่สั้นและชัดเจนมากขึ้น
Imran Ahmed

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 )

หวังว่าจะช่วยใครซักคน :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.