具有上一页和下一页边界的 ViewPager
Posted
技术标签:
【中文标题】具有上一页和下一页边界的 ViewPager【英文标题】:ViewPager with previous and next page boundaries 【发布时间】:2012-12-04 13:48:34 【问题描述】:我正在设计一个包含多个页面的视图。我希望上一页和下一页的边缘如下所示,并实现两指滑动以在页面之间切换。
我尝试按照here 的建议使用带有负页边距的ViewPager
,但它只显示屏幕上的一个边缘,而不是同时显示两个。
或者,有什么方法可以将我的视图的一部分放置在屏幕外,然后对其进行动画处理,使其具有ViewPager
类型的效果。
我应该怎么做?谢谢!
【问题讨论】:
"只在屏幕上显示一个边缘,而不是同时显示两个。"您在第 0 页上,而您只看到第 1 页的一部分吗?也许您需要使用循环寻呼机,例如,然后将您的页面始终设置为“中间”位置。看到这篇文章和评论:***.com/a/8304474/1851478 【参考方案1】:我有类似的解决方案:
在 viewpager 上设置左右填充,例如20dp。还要在 viewpager 上设置页边距,例如寻呼机填充的一半。并且不要忘记禁用剪辑填充。
tilePager.setPadding(defaultGap, 0, defaultGap, 0);
tilePager.setClipToPadding(false);
tilePager.setPageMargin(halfGap);
【讨论】:
提供了很好的解决方案。 最简单最好的方法 这是考虑命名值 xd 的野兽是野兽的答案 旁注:这不适用于自定义视图寻呼机转换器 @voytez 变压器的任何解决方案?【参考方案2】:从a blog post on this subject引用我自己的话:
第三种方法来自著名书籍 android 食谱的合著者 Dave Smith。他采用了一个非常不同的方向,使用了一个自定义容器,该容器禁止儿童剪辑以一次显示多个页面。
他的published sample code 展示了整个过程。他的容器 (
com.example.pagercontainer.PagerContainer
) 包装了ViewPager
并在其自身上调用setClipChildren(false);
,因此即使ViewPager
专注于一个选定的页面,坐标超出ViewPager
边界的其他页面仍然可见,所以只要它们适合PagerContainer
。通过将ViewPager
的大小设置为小于PagerContainer
,ViewPager
可以将其页面调整为该大小,从而为其他页面留出空间。不过,PagerContainer
需要在触摸事件方面提供一些帮助,因为ViewPager
只会在其可见范围内处理滑动事件,而忽略任何侧面可见的页面。
【讨论】:
通过使用它,我可以显示上一页和下一页的一部分,如上图所示,但现在我不想在图像上显示锐利的边缘。我希望它们向边缘模糊..请指导我如何使用 z-index 来实现同样的目标 @Shruti - 只需添加具有您想要的效果的叠加图像 我也这样做,但它禁用了最后一项的过度滚动效果。有什么线索吗? @CommonsWare :先生,我尝试了您的解决方案!它工作得很好。过度滚动在那里。现在唯一的问题是下一张卡片显示,而不是前一张卡片。也就是说,如果我在第 2 页,我可以看到第 3 页向外窥视,但看不到第 1 页。我哪里出错了? @Swayam:我不知道。【参考方案3】:为整个项目视图设置左右填充。示例 xml (page_item.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"/>
<TextView
android:id="@+id/text1"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
然后将PageView
的负页边距设置为等于 2*(上一个视图填充)
int margin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20*2, getResources().getDisplayMetrics());
mViewPager.setPageMargin(-margin);
可选。为第一项设置零左填充,为最后一项设置零右填充以隐藏空白边缘。您可以在 PageAdapter
或 Page
片段类中执行此操作。
【讨论】:
@Sergey,我无法使用您的解决方案进行此操作,您可以发布一个示例吗?谢谢 只是添加一个注释:使用此解决方案,当您从第 1 页滑到第 2 页时,第 3 页不在内存中,因此会延迟显示。要解决这个问题,只需添加 - yourViewPager.setOffscreenPageLimit(2); 我也这样做,但它禁用了最后一项的过度滚动效果。有什么线索吗? 我似乎也无法使其正常工作...如果我使用带有比例设置为中心裁剪的图像,边距似乎随机显示。谁有可以分享的工作代码示例? 如何触摸第一项和最后一项?通过检查 OnPageListener 中的页面索引?【参考方案4】:要显示左右页面的预览,请设置以下两个值
viewpager.setClipToPadding(false)
viewpager.setPadding(left,0,right,0)
如果您需要在 viewpager 中的两个页面之间留出空间,则添加 viewpager.setPageMargin(int)
Android ViewPager - Show preview of page on left and right
【讨论】:
这应该是正确的答案。我想也许这在以前版本的 viewpager 中不起作用,但现在可以了。 它在第一页的左侧和最后一页的右侧添加相同的边距。任何修复 简短而清晰的答案。【参考方案5】:如果有人还在寻找解决方案,我已经自定义了 ViewPage 以在不使用负边距的情况下实现它,请在此处找到示例项目 https://github.com/44kksharma/Android-ViewPager-Carousel-UI
它应该在大多数情况下工作,但您仍然可以定义页边距
mPager.setPageMargin(margin in pixel);
【讨论】:
谢谢。如何增加页面间距? mPager.setPageMargin(margin in pixel);【参考方案6】:从这里下载源代码(ViewPager with previous and next page boundaries)
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;
【讨论】:
这段代码不能正常工作,它显示的左边页面比右边大一点【参考方案7】:前段时间我需要这样的功能并准备了一个小型库,它使用 RecyclerView
和 PagerSnapHelper(在 v7 支持库的 25.1.0 版本中添加)而不是经典的 ViewPager
:
MetalRecyclerPagerView - 您可以在此处找到所有代码以及示例。
主要由一个类文件组成:MetalRecyclerViewPager.java(和两个 xml:attrs.xml 和 ids.xml)。
希望它可以帮助某人:)
【讨论】:
【参考方案8】:轮播 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);
【讨论】:
以上是关于具有上一页和下一页边界的 ViewPager的主要内容,如果未能解决你的问题,请参考以下文章