具有上一页和下一页边界的ViewPager

问题描述 投票:0回答:9

我正在设计一个包含多个页面的视图。我希望上一页和下一页的边缘显示如下,并实现两根手指滑动以在页面之间切换。

enter image description here

我尝试按照

here
的建议使用带有负页边距的ViewPager,但这仅显示屏幕上的一个边缘,而不是同时显示两个边缘。

或者,有什么方法可以将我的视图的一部分定位在屏幕之外,然后对其进行动画处理,使其具有

ViewPager
类型的效果。

我该怎么办?谢谢!

android android-viewpager viewflipper viewanimator
9个回答
118
投票

我有一个类似的解决方案:

在viewpager上设置左右填充,例如20dp。还要在 viewpager 上设置页边距,例如寻呼机填充的一半。并且不要忘记禁用剪辑填充。

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

102
投票

引用我自己的有关此主题的博客文章

第三种方法来自 Dave Smith,他是广受好评的《Android Recipes》一书的合著者。他走向了一个非常不同的方向,使用了一个自定义容器,该容器禁用子项剪辑以一次显示多个页面。

他的发布的示例代码展示了整个过程。他的容器 (

com.example.pagercontainer.PagerContainer
) 包装了
ViewPager
并在其自身上调用
setClipChildren(false);
,因此即使
ViewPager
集中在一个选定的页面上,坐标超出
ViewPager
边界的其他页面仍然可见,因此只要它们适合
PagerContainer
内即可。通过将
ViewPager
调整为小于
PagerContainer
ViewPager
可以将其页面调整为该大小,从而为其他页面留出查看空间。不过,
PagerContainer
需要在触摸事件方面提供一些帮助,因为
ViewPager
只会处理其自身可见边界上的滑动事件,忽略侧面可见的任何页面。

enter image description here


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
    片段类中执行此操作。


49
投票

要显示左右页预览,请设置以下两个值

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

如果 viewpager 中的两个页面之间需要空间,请添加 viewpager.setPageMargin(int)

Android ViewPager - 在左侧和右侧显示页面预览


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

不久前,我需要这样的功能,并准备了一个小型库,它使用

RecyclerView
PagerSnapHelper(在 v7 支持库的 25.1.0 版本中添加)而不是经典的
ViewPager

MetalRecyclerPagerView - 您可以在那里找到所有代码以及示例。

它主要由一个类文件:MetalRecyclerViewPager.java(和两个xml:attrs.xmlids.xml)组成。

希望它对某人有帮助:)


0
投票

轮播ViewPager片段

    ViewPager viewPager = findViewById(R.id.viewPager);
    TabPagerAdapter tabPagerAdapter = new TabPagerAdapter(this,getSupportFragmentManager());
    viewPager.setAdapter(tabPagerAdapter);
    // 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);


0
投票

如果有人想要实现第一个项目仅在右侧有空格而最后一个项目仅在左侧有空格的情况,请添加到上述答案。

将此代码应用到您的viewpager2

viewPagerPhotos.apply {
    adapter = photosAdapter

    clipToPadding = false
    clipChildren = false
    offscreenPageLimit = 3

    val pageMargin = 16.dpToPx(this@MaintenanceCenterDetailsActivity)
    val offset = 24.dpToPx(this@MaintenanceCenterDetailsActivity)
    setPageTransformer { page, position ->
        val pageOffset = position * -(2 * offset + pageMargin)
        if (viewPagerPhotos.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
            if (ViewCompat.getLayoutDirection(viewPagerPhotos) == ViewCompat.LAYOUT_DIRECTION_RTL) {
                page.translationX = -pageOffset
            } else {
                page.translationX = pageOffset
            }
        } else {
            page.translationY = pageOffset
        }
    }
}

然后在你的视图持有者中你需要执行以下操作

fun bind(photoUrl: String) {
    with(binding.root) {
        if (itemCount > 1) {
            updateLayoutParams<ViewGroup.MarginLayoutParams> {
                when (layoutPosition) {
                    0 -> {
                        marginStart = 0
                        marginEnd = marginValue
                    }
                    itemCount - 1 -> {
                        marginStart = marginValue
                        marginEnd = 0
                    }
                    else -> {
                        marginStart = marginValue
                        marginEnd = marginValue
                    }
                }
            }
        }

        load(photoUrl) {
            crossfade(true)
        }
    }
}

这是将 dp 转换为 px 的扩展函数

fun Int.dpToPx(context: Context): Int {
    val resources = context.resources
    val scale = resources.displayMetrics.density
    return (this * scale).toInt()
}
© www.soinside.com 2019 - 2024. All rights reserved.