ViewPager的一些扩展

ViewPager 是开发中经常用到的控件,这里笔者总结了一些日常开发用到的一些扩展

1.渐变色背景效果

这是一种比较吸引眼球的效果,不过实现原理其实非常简单,就是监听一下 ViewPageronPageScrolled 并动态改变背景色值就可以了。核心代码如下:

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
     int[] bgColors = new int[]{0XFFFF8080,0XFFFFBC00,0XFF199AFE,0XFF00AB96,0XFF5599FF};
     int nextPosition = position + 1 == bgColors.length ? 0 : position + 1;
     // ARGB求值器
     ArgbEvaluator evaluator = new ArgbEvaluator();
     int evaluate =(int) evaluator.evaluate(positionOffset, bgColors[position], bgColors[nextPosition]);
     setBackgroundColor(evaluate);
}

就可以实现下面的效果了:

这里写图片描述

2.一屏内显示多页

一屏内显示多页常见有3种实现方法。

1. setPageMargin

通过 viewpager.setPageMargin(int marginPixels) ,给ViewPager的每页设置一个负数的 margin,然后在每一页的View留足够的空白给这个负值,来达到一屏显示多页的目的。但是此时会出现页面重叠的情况:

这里写图片描述

要解决这个问题也很简单,就要对页面显示内容做显示区域做一些限制,核心代码如下:

viewPager .setPageMargin(-(int) ((1.0 - 0.8) * getResources().getDisplayMetrics().widthPixels));

PagerAdapter 里面处理一下显示区域:

@Override
public Object instantiateItem(ViewGroup container, int position) {
     //获取ViewPager显示的View
     View contentView = getContentView();
     Context context = container.getContext();
     FrameLayout frameLayout = new FrameLayout(context);
     if (contentView.getLayoutParams() != null) {
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                    //限制宽度,相当于设置了 margin
                   (int) (getResources().getDisplayMetrics().widthPixels * 0.8f),
                    ViewGroup.LayoutParams.MATCH_PARENT);

            layoutParams.gravity = Gravity.CENTER;
            contentView.setLayoutParams(layoutParams);
        }
        frameLayout.addView(contentView);
        container.addView(frameLayout);
      return frameLayout;
}

这时候就可以看到下面的效果:

这里写图片描述

存在的问题

使用这个方法会带来一个的体验上的问题,那就是本来向左稍微滑动可以达到的翻页效果,现在要把这一页完全翻过才能达到,给人一种奇怪的感觉。如果无需和用户产生交互,那就不用考虑这个影响。

2. getPageWidth

通过重写 PagerAdaptergetPageWidth 方法,此方法返回的是 ViewPager 中每一页占实际 ViewPager 的宽度百分比,默认是1.f,即100%:

这里写图片描述

现在我们来重写这个方法就可以达到一页多个子item的效果:

@Override
public float getPageWidth(int position) {
  return 0.8f;
}

效果如下:

这里写图片描述

存在的问题

这个方法并没有上个方法那样存在的翻页问题,但是也正如上图所示,ViewPager 的页面始终居左,无法居中,如果需求不是这种样式的话,基本不会用到这个方法。

3. 设置clipChildren为false

我们可以通过将 ViewPager 和其父布局的 android:clipChildren属性为 false

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

<RelativeLayout
    android:id="@+id/viewPager_container"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:clipChildren="false"
    android:layerType="software">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:clipChildren="false" />
</RelativeLayout>
存在的问题

setClipChildren(false) 在3.0以上版本中无法在硬件加速后运行
在开启硬件加速的情况下,需要将其设置软件加速,可以使用 setLayerType(View.LAYER_TYPE_SOFTWARE, null); 开启软件加速,也可以如上所示直接在 xml 布局中添加 android:layerType="software"

3.轮播图组件需要的点

ViewPager 常给封装为轮播图组件,毕竟它有 item 回收的机制,不会浪费太多的资源。

怎么设置一个 timer 计时器任务这里就不提了,网上这方面的资源太多了,这里就提一下回收的问题。

ViewPager 滑出屏幕时需要停止 timer,再次滑入屏幕时需要启动 timer ,例如在 ListViewRecyclerView 中;

这个过程我们可以通过重写 ViewPager 里的一些方法实现:

    @Override
    protected void onAttachedToWindow() {
        //进入屏幕时
        super.onAttachedToWindow();
        startTimer();
    }

    @Override
    protected void onDetachedFromWindow() {
         //离开屏幕时,listView在5.0以下不会回调这个方法
        super.onDetachedFromWindow();
        stopTimer();
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        //控件可见状态改变时
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == View.VISIBLE) {
            startTimer();
        } else {
            stopTimer();
        }
    }

    @Override
    public void onStartTemporaryDetach() {
        //父容器将当前View移出时,listView在5.0以下回调这个方法
        super.onStartTemporaryDetach();
        stopTimer();
    }

    @Override
    public void onFinishTemporaryDetach() {
        //父容器将当前View填充时,listView在5.0以下回调这个方法
        super.onFinishTemporaryDetach();
        startTimer();
    }

上面的方法已经将大部分的情况都兼容到了,目前笔者只有 ViewPager + fragment 的情况下,需要通过 setUserVisibleHint() 方法的回调来手动暂停 timer ,毕竟 ViewPager 是默认持有复数个页面的,上面的方法都是 View 给回收或隐藏时调用的,如果用户只是滑动到傍边的第二个页面,那就自己手动处理一下吧。

猜你喜欢

转载自blog.csdn.net/f409031mn/article/details/79441308