ViewPager实现炫酷的滑动缩放广告页

来源:互联网 发布:工作督促软件 编辑:程序博客网 时间:2024/04/24 02:33

ViewPager是Android开发中一个重要的控件,其轻量级的多页展示功能简化了开发过程,使我们能够快速构建一个App的引导页。但是,如果只是用来做引导页,那就太浪费了,其实我们可以将它打造的更炫酷一点。

效果图

(制作的gif图不知道为什么不能显示,所以只能用一张静态图片代替了)

需求分析

  1. 页面滑动过程中,中间页向两边滑动的过程中进行缩小,两边页面向中间滑动的过程中进行放大,
  2. 页面滑动过程中底部显示选中页标志;
  3. 页面范围内都可以滑动;

实现

通过对上面的需求进行分析,我们先确定要实现的位置,需求一要求在缩放过程中进行缩放,那只能在ViewPager的滑动监听过程中实现了。

 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {    @Override    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {    }    @Override    public void onPageSelected(int position) {    }    @Override    public void onPageScrollStateChanged(int i) {    }});

ViewPager的滑动监听中有三个方法, onPageScrolled在滑动过程中被调用,onPageSelected当一个新的页面被选中时被调用(注意:动画此时不一定结束),onPageScrollStateChanged在滑动状态改变时被调用(i==1表示开始滑动,i==2表示当前页被选中,i==0表示滑动和动画都已结束,注意:i==2的状态后会迅速调用i==0的状态,所以滑动过程中i的变化过程为:i=1 --> i=2 –> i=0)。了解了滑动监听的过程,我们很容易看出,滑动过程的动画只能在onPageScrolled进行实现了。

onPageScrolled函数原型中的参数说明:

  • position:当前选中页的index, 当posistionOffset为非零时position++;
  • positionOffset:当前选中页的位置偏移量,取值范围[0, 1)。
  • positionOffsetPixels:当前选中页的偏移距离, 取值范围[0, viewpager的宽度+ViewPager中页面的间距)。

滑动过程中参数的变化:

  • 左滑过程中positionOffset和positionOffsetPixels逐渐变大,变到 最大后都又变成0,此时position++;
  • 右滑过程中positionOffset和positionOffsetPixels从最大值逐渐变为0,此过程中position始终是当前选中页的前一页的index;

了解了上面函数的参数含义后开始实现我们的需求一:

@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {    // 虽然一屏只显示三页,但是当我们滑动的过程中需要设置四页的缩放效果,因为左边的页面被滑出去之后,页面上将显示的是后面的三页    View leftImage = activityMap.get(position - 1);    View currentImage = activityMap.get(position);    View rightImage = activityMap.get(position + 1);    View rightImage2 = activityMap.get(position + 2);    if (positionOffset > 0) {        float scaleAlpha1 = 1 - positionOffset / 4.0f;        float scaleAlpha2 = 0.75f + positionOffset / 4.0f;        // 设置页面滑动过程中的缩放效果        currentImage.setAlpha(scaleAlpha1);        currentImage.setScaleX(scaleAlpha1);        currentImage.setScaleY(scaleAlpha1);        if (leftImage != null) {            leftImage.setAlpha(scaleAlpha2);            leftImage.setScaleX(scaleAlpha2);            leftImage.setScaleY(scaleAlpha2);        }        if (rightImage != null) {            rightImage.setAlpha(scaleAlpha2);            rightImage.setScaleX(scaleAlpha2);            rightImage.setScaleY(scaleAlpha2);        }        if (rightImage2 != null) {            rightImage2.setAlpha(scaleAlpha1);            rightImage2.setScaleX(scaleAlpha1);            rightImage2.setScaleY(scaleAlpha1);        }    } else {        // 设置页面初次启动时的缩放效果        if (leftImage != null && currentImage.getAlpha() == 1) {            leftImage.setAlpha(0.75f);            leftImage.setScaleX(0.75f);            leftImage.setScaleY(0.75f);        }        if (rightImage != null && currentImage.getAlpha() == 1) {            rightImage.setAlpha(0.75f);            rightImage.setScaleX(0.75f);            rightImage.setScaleY(0.75f);        }    }}

需求二其实简单,只需要在onPageSelected重新设置选中状态即可:

 @Overridepublic void onPageSelected(int position) {    selectCurrentDot(position);}/** * 设置当前选中页的选中状态(只有一页时不显示选中状态) * @param position 当前选中页的index */private void selectCurrentDot(int position) {    if (imageList.size() > 1) {        for (int i = 0; i < indicatorIcon.length; i++) {            if (i == position) {                indicatorIcon[i].setBackgroundResource(R.drawable.indicator_selected);            } else {                indicatorIcon[i].setBackgroundResource(R.drawable.indicatorunselect);            }        }    }}

到这一步,我们的滑动缩放广告栏看起来已经完成了,但是滑动的过程中发现只有ViewPager页面范围内可以滑动,两边的位置都不能滑动,看了下ViewPager的源码, 发现它重写了ViewGroup的dispatchTouchEvent函数,并且也是是公开的,那我们在ViewPager的父View的onTouch事件中返回ViewPager的dispatchTouchEvent应该就可以像ViewPager一样滑动了。

containLayout.setOnTouchListener(new View.OnTouchListener() {    @Override    public boolean onTouch(View v, MotionEvent event) {        return viewPager.dispatchTouchEvent(event);    }});

再次运行发现可以在ViewPager的父View范围内滑动了。至此,整个滑动过程就完成了。下面贴一下ViewPagerAdapter的代码:

 private class MyPagerAdapter extends PagerAdapter {    @Override    public int getCount() {        return imageList.size();    }    @Override    public boolean isViewFromObject(View view, Object obj) {        return view == obj;    }    @Override    public Object instantiateItem(ViewGroup container, final int position) {        RoundImageView imageView = new RoundImageView(context);        ViewGroup.LayoutParams params = container.getLayoutParams();        params.width = getScreenWidth() - dpToPx(140);        params.height = (int)(params.width * H_W);        imageView.setLayoutParams(params);        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);        imageView.setImageDrawable(imageList.get(position));        imageView.setTag(position);        container.addView(imageView);        activityMap.put(position, imageView);        imageView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(context, "触发了点击事件", Toast.LENGTH_SHORT).show();            }        });        return imageView;    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {    }}

源码

源码下载:可滑动缩放的ViewPager

遇到的问题

  1. ViewPager一屏不能显示三页;
  2. 只有ViewPager的位置可以滑动,两边不能滑动;
  3. ViewPager滑动过程中出现卡顿,多次滑动后App卡死;

解决方案

  1. 在ViewPager,ViewPager的父布局和ViewPager的根布局中添加属性android:clipChildren=”false”(注意:ViewPager不加此属性时有些手机会显示异常);
  2. 重写ViewPager父布局的onTouch事件;
  3. 先读取所有的图片内容,得到drawable或bitmap, 然后设置给ViewPager中的图片,同时设置ViewPager的预加载时需要预加载所有的Item,只有这样ViewPager滑动过程中才不会出现卡顿(具体原因有待进一步深究)。通过这种方案,加载了30页1080*540大小的图片没有出现卡顿情况。

如果有什么错误之处,欢迎指正!顺便问一下,你们都用什么软件来做gif截屏,尝试了一下感觉很麻烦,而且还不理想。

0 0
原创粉丝点击