Android · 2017年8月29日 0

Android 使用ViewPager实现类似gallery画廊的效果(画廊效果之ViewPager显示多个图片)

这个画廊的效果利用到了View的clipChildren属性,我们在这里要把ViewPager以及它的父窗体都设置为false,如下:

Android:clipChildren=”false”

因为如果clipChildren属性设置为true,就表明我们要将children给clip掉,就是说对于子元素来说,超出当前view的部分都会被切掉,那我们在这里把它设置成false,就表明超出view的部分,不要切掉,依然显示。

xml代码部分:

<!– 配置Container和pager的clipChildren=false, 并且指定marginLeft 和 marginRight 的值–>

<LinearLayout
android:id=”@+id/container”
android:layout_width=”match_parent”
android:layout_height=”100dp”
android:clipChildren=”false”
android:gravity=”center_horizontal”
android:layerType=”software”
android:orientation=”horizontal” >

<android.support.v4.view.ViewPager
android:id=”@+id/viewpager”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_marginLeft=”110dp”
android:layout_marginRight=”110dp”
android:clipChildren=”false” >
</android.support.v4.view.ViewPager>
</LinearLayout>

Java代码部分:

// 1.设置幕后item的缓存数目
mViewPager.setOffscreenPageLimit(3);
// 2.设置页与页之间的间距
mViewPager.setPageMargin(10);
// 3.将父类的touch事件分发至viewPgaer,否则只能滑动中间的一个view对象
container.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return mViewPager.dispatchTouchEvent(event);
}
});

参考效果图(上面代码并不能实现效果图,仅供参考):

 

 

正常情况下, ViewPager  一页只能显示一项数据,
但是如果需求是,  除了小显示本页数据, 还有包 左右两半的数据 也都露出一点来呢?
这该怎么处理?
后面在网上了搜了一下, 发现有不少这样得到文章, 这里自己也写一篇总结一下.
其实 主要就是用到 View 的 android:clipChildren 属性.
简单来说这个属性,  就是 父View 是否 束缚 子View 的显示范围.
如果 父View  有 padding , 那么 子View 则在 padding区域是不能显示内容的,
但是如果 设置 android:clipChildren 为 false 时, 则子View 就可以在 父View 的padding屈戌显示内容了.
ok 基本了解了 android:clipChildren  那么来处理一下  ViewPager吧

先看一下我做的demo:

基本就是上面那样, 除了可以显示 当先项的内容, 还可以显示 左右两边的内容.
下面贴一下主要代码:
布局文件:

[html] view plain copy

  1. <?xml version=“1.0” encoding=“utf-8”?>
  2. <RelativeLayout
  3.     android:id=“@+id/view_pager_box”
  4.     xmlns:android=“http://schemas.android.com/apk/res/android”
  5.     android:layout_width=“match_parent”
  6.     android:layout_height=“360dp”
  7.     android:layout_marginTop=“30dp”
  8.     android:clipChildren=“false”
  9.     >
  10.     <android.support.v4.view.ViewPager
  11.         android:id=“@+id/view_pager”
  12.         android:layout_width=“match_parent”
  13.         android:layout_height=“match_parent”
  14.         android:layout_marginLeft=“50dp”
  15.         android:layout_marginRight=“50dp”
  16.         android:clipChildren=“false”
  17.         />
  18. </RelativeLayout>

 

可以在看到
外层的 RelativeLayout 设置了android:clipChildren 为false
ViewPager 同样页设置了 android:clipChildren 为false
需要两个都设置, 不然会出问题
activity 相关代码

[java] view plain copy

  1. public class MainActivity extends AppCompatActivity {
  2.     ViewPager mViewPager;
  3.     RelativeLayout mViewPagerBox;
  4.     private ViewPagerAdapter1 mViewPagerAdapter1;
  5.     @Override
  6.     protected void onCreate(Bundle savedInstanceState) {
  7.         super.onCreate(savedInstanceState);
  8.         setContentView(R.layout.activity_main);
  9.         mViewPager = (ViewPager) findViewById(R.id.view_pager);
  10.         mViewPagerBox = (RelativeLayout) findViewById(R.id.view_pager_box);
  11.         mViewPager.setOffscreenPageLimit(3);
  12.         mViewPagerAdapter1 = new ViewPagerAdapter1(this);
  13.         mViewPager.setAdapter(mViewPagerAdapter1);
  14.         mViewPagerBox.setOnTouchListener(new View.OnTouchListener() {
  15.             @Override
  16.             public boolean onTouch(View v, MotionEvent event) {
  17.                 return mViewPager.dispatchTouchEvent(event);
  18.             }
  19.         });
  20.     }
  21. }

 

可以看到 和使用普通的 Viewpager 没有任何的区别,
需要注意的是, 为了能够滑动 左右漏出的两边时,  也能滑动 ViewPager
需要吧 Viewpager 的 父View收到的事件 传递给 viewpager
我们在使用Viewpager 的时候, 经常 会加入一些好看的滑动效果这个是怎么实现的呢?
其实很简单,  google 以及为我提供了相应的方法.
通过 setPageTransformer 就可以设置 Viewpager的滑动效果.
Android 官方文档 已经提供了两种 滑动效果:

ZoomOutPageTransformer:

  1. public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
  2. private static final float MIN_SCALE = 0.85f;
  3. private static final float MIN_ALPHA = 0.5f;
  4. public void transformPage(View view, float position) {
  5. int pageWidth = view.getWidth();
  6. int pageHeight = view.getHeight();
  7. if (position < –1) { // [-Infinity,-1)
  8. // This page is way off-screen to the left.
  9.             view.setAlpha(0);
  10.         } else if (position <= 1) { // [-1,1]
  11. // Modify the default slide transition to shrink the page as well
  12. float scaleFactor = Math.max(MIN_SCALE, 1 – Math.abs(position));
  13. float vertMargin = pageHeight * (1 – scaleFactor) / 2;
  14. float horzMargin = pageWidth * (1 – scaleFactor) / 2;
  15. if (position < 0) {
  16.                 view.setTranslationX(horzMargin – vertMargin / 2);
  17.             } else {
  18.                 view.setTranslationX(-horzMargin + vertMargin / 2);
  19.             }
  20. // Scale the page down (between MIN_SCALE and 1)
  21.             view.setScaleX(scaleFactor);
  22.             view.setScaleY(scaleFactor);
  23. // Fade the page relative to its size.
  24.             view.setAlpha(MIN_ALPHA +
  25.                     (scaleFactor – MIN_SCALE) /
  26.                     (1 – MIN_SCALE) * (1 – MIN_ALPHA));
  27.         } else { // (1,+Infinity]
  28. // This page is way off-screen to the right.
  29.             view.setAlpha(0);
  30.         }
  31.     }
  32. }

DepthPageTransformer:

  1. public class DepthPageTransformer implements ViewPager.PageTransformer {
  2. private static final float MIN_SCALE = 0.75f;
  3. public void transformPage(View view, float position) {
  4. int pageWidth = view.getWidth();
  5. if (position < –1) { // [-Infinity,-1)
  6. // This page is way off-screen to the left.
  7.             view.setAlpha(0);
  8.         } else if (position <= 0) { // [-1,0]
  9. // Use the default slide transition when moving to the left page
  10.             view.setAlpha(1);
  11.             view.setTranslationX(0);
  12.             view.setScaleX(1);
  13.             view.setScaleY(1);
  14.         } else if (position <= 1) { // (0,1]
  15. // Fade the page out.
  16.             view.setAlpha(1 – position);
  17. // Counteract the default slide transition
  18.             view.setTranslationX(pageWidth * -position);
  19. // Scale the page down (between MIN_SCALE and 1)
  20. float scaleFactor = MIN_SCALE
  21.                     + (1 – MIN_SCALE) * (1 – Math.abs(position));
  22.             view.setScaleX(scaleFactor);
  23.             view.setScaleY(scaleFactor);
  24.         } else { // (1,+Infinity]
  25. // This page is way off-screen to the right.
  26.             view.setAlpha(0);
  27.         }
  28.     }
  29. }
其实从google 给的两个demo 的注释中可以看出一些端倪.
在 transformPage 方法中, 会传递两个参数,
且 该View  对应 当前的 position
从注释中可以看到,
position 有一下几个区间:
[-∞ , -1)  :
     表示左边 的View 且已经看不到了
[-1 ,   0]  :
     表示左边的 View ,且可以看见
( 0 ,   1]  :
     表示右边的VIew , 且可以看见了
( 1 , -∞)  :
     表示右边的 View 且已经看不见了
上面讲的有些模糊,  举个例子
a 是第一页
b 是第二页
当前页为 a, 当  a  向左滑动,  直到滑到 b 时:
a 的position变化是  [-1 ,   0]   由  0  慢慢变到 -1
b 的position变化是  ( 0 ,   1]   由  1  慢慢变到  0
当前页为b,  当 b 向右滑动, 直到滑到a 时:
a 的position变化是  [-1 ,   0]   由  -1  慢慢变到 0
b 的position变化是  ( 0 ,   1]   由   0   慢慢变到 1
了解了这些后, 那么其他的事情 就是在更具position 来写不同的动画了
ok  之前有一篇博客 是写到 关于 Viewpager 来实现 画廊效果, 但是 没有滑动效果.
这里自定义一个  PageTransformer 来实现滑动效果:
先看图


可以看到 较 之前那篇博客 好看了很多, 下面上代码:

  1. private static float defaultScale = (float14 / (float15;
  2. public class MyPageTransformer implements ViewPager.PageTransformer {
  3. @Override
  4. public void transformPage(View view, float position) {
  5.         View cardView = view.findViewById(R.id.img_box);
  6.         View img = view.findViewById(R.id.img);
  7. int diffWidth = (cardView.getWidth() – img.getWidth()) / 2;
  8. if (position < –1) { // [-Infinity,-1)
  9.             cardView.setScaleX(defaultScale);
  10.             cardView.setScaleY(defaultScale);
  11.             img.setTranslationX(diffWidth);
  12.         } else if (position <= 0) { // [-1,0]
  13.             cardView.setScaleX((float1 + position / (float15);
  14.             cardView.setScaleY((float1 + position / (float15);
  15.             img.setTranslationX((0 – position) * diffWidth);
  16.         } else if (position <= 1) { // (0,1]
  17.             cardView.setScaleX((float1 – position / (float15);
  18.             cardView.setScaleY((float1 – position / (float15);
  19.             img.setTranslationX((0 – position) * diffWidth);
  20.         } else { // (1,+Infinity]
  21.             cardView.setScaleX(defaultScale);
  22.             cardView.setScaleY(defaultScale);
  23.             img.setTranslationX(-diffWidth);
  24.         }
  25.     }
  26. }
其实很简单, 就是更具 position 处理向右的属性动画
当处于 [-Infinity,-1) 时,  是左边的看不见的, 则设在 scaleXY 缩小
当处于 [-Infinity,-1) 时,  是右边的看不见的, 则设在 scaleXY 缩小
当处于 [-Infinity,-1) 时,  是右边的看不见的, 则设在 scaleXY (float) 1 + position / (float) 15 更具 position来变化
需要注意的是,  除了设在 scaleXY  我还设置了 translationX
这是因为, 没 Item里面的土坯那 是wrap_content 且剧中
所以如果是长条状的图,  那么即使设在 android:clipChildren = false  页还是看不到 那张图,
这里 设在 setTranslationX 就是 吧 处于中间的长条状的图, 移到边上来,
这样即使 左右两面 是 长条状的图, 也能看到了

Share this: