ViewPager系列之 仿魅族应用的广告BannerView

作者: 依然范特稀西 | 来源:发表于2017-06-04 16:34 被阅读6863次

    前言

    Banner广告位是APP 中的一个非常重要的位置,为什么呢?因为它能带来money。是一个公司很重要的一个营收点。像那种用户数基数特别大的产品,如facebook、twitter、QQ、微信等等。Banner广告位日营收估计得上千万美刀(猜的,不知道具体数据)。一个漂亮的Banner往往能够吸引用户的眼球,引导用户点击,从而提高转化率。遗憾的是现在的大多数产品的Banner都是千篇一律的,没有什么亮点可言。但是前几天在魅族手机上发现了一个效果不错的Banner,魅族所有自家的APP所用的Banner 引起了我的注意。效果是这样子的:

    meizuapp.gif

    看到这个Banner 第一眼就吸引了我,随后就反复的体验了几次了,感觉这种Banner的效果还不错。最后想着高仿一个和这种效果差不多的BannerView 。那么本文就讲一下如何实现这样一个BannerView。最终实现的效果如下:

    MZBannerView.gif

    目录

    本文会讲实现仿魅族Banner效果所要用到的一些关键知识点,目录如下图所示。所有的效果已经封装成一个库。详细代码请看github: https://github.com/pinguo-zhouwei/MZBannerView

    本文目录.png

    仿魅族Banner 效果

    在开始实现魅族Banner效果之前,我们先来整理一下实现一个BannerView的思路,首先需要用ViewPager,其次让ViewPager无限轮播。其实BannerView就是一个无限轮播的ViewPager,然后做一些封装处理,让使用更加简单就ok。

    现在我们在来看一下魅族的这个Banner。他与普通的banner的区别是当前页显示了前一页和后一页的部分内容。

    ViewPager展示多页.png

    抛开切换时的动画先不说,要实现这个效果的第一步就是要让ViewPager在一个页面显示多页的内容(当前页+前后页部分)。

    1 . ViewPager展示多页
    要让ViewPager页面展示多页的内容,就要用到ViewGroup的一个强大的属性。这个属性虽然强大,但是也不常用,可能有些小伙伴不知道(之前我也没用过...),那就是clipChildren属性。这个属性有什么作用呢,我们看一下它的文档介绍:

    /**
         * By default, children are clipped to their bounds before drawing. This
         * allows view groups to override this behavior for animations, etc.
         *
         * @param clipChildren true to clip children to their bounds,
         *        false otherwise
         * @attr ref android.R.styleable#ViewGroup_clipChildren
         */```
    
    **clipChildren:** 默认值为true, 子View 的大小只能在父View规定的范围之内,比如父View的高为50,子View的高为60 ,那么多处的部分就会被裁剪。如果我们设置这个值为false的话,那么多处的部分就不会被裁剪了。
    
    这里我们就可以利用这个属性来实现了这个效果了,我们设置ViewPager的父布局的`clipChildren`为false。然后设置ViewPager 左右一定的边距,那么左右就空出了一定的区域,利用`clipChildren` 属性,就能让前后页面的部分显示在当前页了。布局如下:
    ```java
    <?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"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:clipChildren="false"
        android:orientation="vertical"
        >
    
    
       <android.support.v4.view.ViewPager
           android:id="@+id/view_pager"
           android:layout_width="match_parent"
           android:layout_height="200dp"
           android:layout_marginLeft="30dp"
           android:layout_marginRight="30dp"
           />
    </LinearLayout>
    

    这样就能实现ViewPager 展示前后页面的部分内容。

    2 . 自定义ViewPager.PageTransformer动画
    上面实现了ViewPager当前页面显示前后页的部分内容,但是从最开始魅族的Banner效果我们可以看出,滑动的时候是有 一个放大缩小的动画的。左右显示的部分有一定比例的缩小。这就要用到ViewPager.PageTransformer了。

    ViewPager.PageTransformer 干什么的呢?ViewPager.PageTransformer 是用来做ViewPager切换动画的,它是一个接口,里面只有一个方法transformPage

     public interface PageTransformer {
            /**
             * Apply a property transformation to the given page.
             *
             * @param page Apply the transformation to this page
             * @param position Position of page relative to the current front-and-center
             *                 position of the pager. 0 is front and center. 1 is one full
             *                 page position to the right, and -1 is one page position to the left.
             */
            void transformPage(View page, float position);
        }
    

    虽然只有一个方法,但是它很强大,它能反映出在ViewPager滑动过程中,各个View的位置变化。我们拿到了这些位置变化,就能在这个过程中对View做各种各样的动画了。

    要自定义动画,我们就来需要知道positon这个值的变化区间。从官方给的ViewPager的两个示例我们知道,position的变换有三个区间,[-Infinity,-1),[-1,1],(1.Infinity)。
    [-Infinity,-1):已经在屏幕之外,看不到了
    (1.Infinity): 已经在屏幕之外,看不到了。
    ** [-1,1]:** 这个区间是我门操作View动画的重点区间。
    我们来看一下官方对于position的解释:

    官方的解释:The position parameter indicates where a given page is located relative to the center of the screen. It is a dynamic property that changes as the user scrolls through the pages. When a page fills the screen, its position value is 0. When a page is drawn just off the right side of the screen, its position value is 1. If the user scrolls halfway between pages one and two, page one has a position of -0.5 and page two has a position of 0.5.

    **根据解释,也就是说当前停留的页面的位置为 0,右边屏幕之外绘制的这个页面位置为 1。那么,A 页面滑到 B 页面有 2 种情况:第一种:左边划出屏幕,那么 A:0 -> -1,B :1 -> 0。第二种:右边划出屏幕,A:0->1, B :-1-> 0 **

    了解了这个方法的变化后,我们就来自定义我们的切换动画,这里很简单,我们只需要一个scale动画。代码如下:

    /**
     * Created by zhouwei on 17/5/26.
     */
    
    public class CustomTransformer implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.9F;
        @Override
        public void transformPage(View page, float position) {
    
            if(position < -1){
                page.setScaleY(MIN_SCALE);
            }else if(position<= 1){
                //
                float scale = Math.max(MIN_SCALE,1 - Math.abs(position));
                page.setScaleY(scale);
                /*page.setScaleX(scale);
    
                if(position<0){
                    page.setTranslationX(width * (1 - scale) /2);
                }else{
                    page.setTranslationX(-width * (1 - scale) /2);
                }*/
    
            }else{
                page.setScaleY(MIN_SCALE);
            }
        }
    
    }
    

    效果图是这样的:

    仿魅族Banner效果图.png

    到此,我们仿魅族Banner的静态效果就实现了。接下来我们就要让Banner动起来,实现无限轮播效果。

    图片轮播

    上面我们已经实现了Bannerd的静态展示和切换动画,那么我们现在就需要让Banner动起来,实现无限轮播。

    ViewPager实现Banner无效轮播效果有2种方案,第一种是:在列表的最前面插入最后一条数据,在列表末尾插入第一个数据,造成循环的假象。第二种方案是:采用getCount 返回 Integer.MAX_VALUE。结下来分别看一下这两种方案。

    1 . 在列表的最前面插入最后一条数据,在列表末尾插入第一个数据,造成循环的假象。

    这种方法是怎么做的呢?,是这样的:假如我们的列表有3条数据,用三个页面展示,分别编号为1,2,3。我们再创建一个新的列表,长度为真实列表的长度+2,也就是5。在最前面插入最后一条数据,然后在末尾插入第一条数据。新列表就变成了这样了,3-1-2-3-1。如果当前滑到的是0位置(页面3),那就通过ViewPager的setCurrentItem(int item, boolean smoothScroll)方法神不知鬼不觉的切换到3位置(页面3),当滑到4的位置时(页面1),也用这个方法滑到1位置(页面1)。这样给我们的感觉就是无限轮播了。来一张图辅助理解一下。

    轮播切换示意图.png

    **2 . 采用getCount 返回 Integer.MAX_VALUE **

    让ViewPager 的Adapter getCount 方法返回一个很大的数(这里用Integer.MAX_VALUE),理论上可以无限滑动。当显示完一个真实列表的周期后,又从真实列表的0位置显示数据,造成无限循环轮播的假象。开始时调用 mViewPager.setCurrentItem(Integer.MAX_VALUE /2)设置选中中间位置,这样最开始就可以向左滑动。关键代码:

     int currentItem = getStartSelectItem();
             
    //设置当前选中的Item
     mViewPager.setCurrentItem(currentItem);
    
     private int getStartSelectItem(){
                // 我们设置当前选中的位置为Integer.MAX_VALUE / 2,这样开始就能往左滑动
                // 但是要保证这个值与getRealPosition 的 余数为0,因为要从第一页开始显示
                int currentItem = Integer.MAX_VALUE / 2;
                if(currentItem % getRealCount()  ==0 ){
                    return currentItem;
                }
                // 直到找到从0开始的位置
                while (currentItem % getRealCount()  != 0){
                    currentItem++;
                }
                return currentItem;
            }
    

    3 . 两种方案选哪一种?

    两种方案我都试了一下,都可以实现轮播,但是第一种 方案在有切换动画的时候是有问题的,因为上面我们说了滑动到最后一页切换到第一页时,用的是ViewPager的setCurrentItem(int item, boolean smoothScroll)方法,smoothScroll 的值为false,这样界面就感觉不到我们偷偷的切换。但是这样切换就没有了动画。这样每次切换就会很生硬,因此就抛弃这种方法。选择第二种方案。

    轮播我们采用Hanlder的postDelayed方法,关键代码如下:

    
        private final Runnable mLoopRunnable = new Runnable() {
            @Override
            public void run() {
                if(mIsAutoPlay){
                    mCurrentItem = mViewPager.getCurrentItem();
                    mCurrentItem++;
                    if(mCurrentItem == mAdapter.getCount() - 1){
                        mCurrentItem = 0;
                        mViewPager.setCurrentItem(mCurrentItem,false);
                        mHandler.postDelayed(this,mDelayedTime);
                    }else{
                        mViewPager.setCurrentItem(mCurrentItem);
                        mHandler.postDelayed(this,mDelayedTime);
                    }
                }else{
                    mHandler.postDelayed(this,mDelayedTime);
                }
            }
        };
    

    在Adapter instantiateItem(ViewGroup container, final int position) 中,现在的这个position是一个很大的数字,我们需要将它转换成一个真实的position,否则会越界报错。

     final int realPosition = position % getRealCount();
    
            /**
             * 获取真实的Count
             * @return
             */
            private int getRealCount(){
                return  mDatas==null ? 0:mDatas.size();
            }
    

    通过以上就实现了仿魅族的BannerView,但是这还没完,虽然功能实现了,要想在任何地方拿来就可以使用,简单方便,我们还需要进一步的封装。

    封装轮子:MZBannerView

    通过上面几步就可以实现仿魅族的BannerView,但是为了使用方便,我们将它封装成一个库,前面一篇文章讲了,如何封装一个通用的ViewPager(文章地址:ViewPager系列之 打造一个通用的ViewPager)。既然要想Banner使用方便,我们也需要封装得通用,可扩展。因为我们的Banner也是用ViewPager 实现的,因此,我们可用上一篇文章的方法,封装一个通用的BannerView。

    MZBannerView 有以下功能:
    1 . 仿魅族BannerView 效果。
    2 . 当普通Banner 使用
    3 . 当普通ViewPager 使用。
    4 . 当普通ViewPager使用(有魅族Banner效果)

    自定义属性

    属性名 属性意义 取值
    open_mz_mode 是否开启魅族模式 true 为魅族Banner效果,false 则普通Banner效果
    canLoop 是否轮播 true 轮播,false 则为普通ViewPager
    indicatorPaddingLeft 设置指示器距离左侧的距离 单位为 dp 的值
    indicatorPaddingRight 设置指示器距离右侧的距离 单位为 dp 的值
    indicatorAlign 设置指示器的位置 有三个取值:left 左边,center 剧中显示,right 右侧显示

    通过open_mz_modecanLoop这两个属性来控制MZBannerView 是用作Banner还是普通ViewPager,有4种组合方式
    1,仿魅族BannerView(默认的模式)

    app:open_mz_mode="true"
    app:canLoop="true"
    

    2, 普通BannerView

    app:open_mz_mode="false"
    app:canLoop="true"
    

    3 ,普通ViewPager (有魅族Banner的切换动画)

    app:open_mz_mode="true"
    app:canLoop="false"
    

    4, 普通ViewPager

    app:open_mz_mode="false"
    app:canLoop="false"
    

    使用方法:
    1 . xml 布局文件

     <com.zhouwei.mzbanner.MZBannerView
           android:id="@+id/banner"
           android:layout_width="match_parent"
           android:layout_height="200dp"
           android:layout_marginTop="10dp"
           app:open_mz_mode="true"
           app:canLoop="true"
           app:indicatorAlign="center"
           app:indicatorPaddingLeft="10dp"
           />
    

    2 . activity中代码:

            mMZBanner = (MZBannerView) view.findViewById(R.id.banner);
           // 设置页面点击事件
            mMZBanner.setBannerPageClickListener(new MZBannerView.BannerPageClickListener() {
                @Override
                public void onPageClick(View view, int position) {
                    Toast.makeText(getContext(),"click page:"+position,Toast.LENGTH_LONG).show();
                }
            });
       
            List<Integer> list = new ArrayList<>();
            for(int i=0;i<RES.length;i++){
                list.add(RES[i]);
            }
           // 设置数据
            mMZBanner.setPages(list, new MZHolderCreator<BannerViewHolder>() {
                @Override
                public BannerViewHolder createViewHolder() {
                    return new BannerViewHolder();
                }
            });
    
     public static class BannerViewHolder implements MZViewHolder<Integer> {
            private ImageView mImageView;
            @Override
            public View createView(Context context) {
                // 返回页面布局文件
                View view = LayoutInflater.from(context).inflate(R.layout.banner_item,null);
                mImageView = (ImageView) view.findViewById(R.id.banner_image);
                return view;
            }
    
            @Override
            public void onBind(Context context, int position, Integer data) {
                // 数据绑定
                mImageView.setImageResource(data);
            }
        }
    

    3 .如果是当Banner使用,注意在onResume 中调用start()方法,在onPause中调用 pause() 方法。如果当普通ViewPager使用,则不需要。

     @Override
        public void onPause() {
            super.onPause();
            mMZBanner.pause();//暂停轮播
        }
    
        @Override
        public void onResume() {
            super.onResume();
            mMZBanner.start();//开始轮播
        }
    

    其他对外API

        /******************************************************************************************************/
        /**                             对外API                                                               **/
        /******************************************************************************************************/
        //开始轮播
         start()
        //停止轮播
         pause()
    
        //设置BannerView 的切换时间间隔
         setDelayedTime(int delayedTime)
        // 设置页面改变监听器
        addPageChangeLisnter(ViewPager.OnPageChangeListener onPageChangeListener)
    
        //添加Page点击事件
         setBannerPageClickListener(BannerPageClickListener bannerPageClickListener)
        //设置是否显示Indicator
        setIndicatorVisible(boolean visible)
        // 获取ViewPager
        ViewPager getViewPager()
        // 设置 Indicator资源
        setIndicatorRes(int unSelectRes,int selectRes)
        //设置页面数据
        setPages(List<T> datas,MZHolderCreator mzHolderCreator)
        //设置指示器显示位置
        setIndicatorAlign(IndicatorAlign indicatorAlign)
        //设置ViewPager(Banner)切换速度
        setDuration(int duration)
    

    因为是对ViewPager的包装,所有要设置某些ViewPager的属性,可以通过getViewPager 获取到ViewPager再设置对应属性

    效果图:
    1, BannerView 轮播效果图:

    仿魅族Banner效果.gif

    2 普通ViewPager效果图:

    MZBanner普通ViewPager效果.gif

    总结

    本文讲了如何实现一个仿魅族Banner效果。其中讲了一些关键的点和关键代码。其实普通的BannerView 是一样的,只是少了动画而已。最后,将这些功能封装成了一个通用的BannerView 控件。这个控件既有仿魅族Banner的效果,又可以当普通Banner使用。而且还可以当作一个普通的ViewPager使用。

    更多详细代码和使用方法请看github:https://github.com/pinguo-zhouwei/MZBannerView

    最后,可能还有不完善的地方,如有问题,欢迎留言和提Issues。如果你觉得不错,欢迎star和 Fxxk 。。。。啊呸。。。是fork。

    相关文章

      网友评论

      • 蜂蜜柚子茶_36b1:您好,请问一下 我在fragment里面当作顶部banner使用;
        @Override
        public void onPause() {
        super.onPause();
        mzBanner.pause();//暂停轮播
        }

        @Override
        public void onResume() {
        super.onResume();
        mzBanner.start();//开始轮播
        }里面也调用了,配置都在setPages 方法之前 ;但实际不会自动轮播,必须手滑动图片才能自动轮播。
      • Mango旺旺:if(mIsOpenMZEffect){
        if(mIsMiddlePageCover){
        // 中间页面覆盖两边,和魅族APP 的banner 效果一样。
        // mViewPager.setPageTransformer(true,new CoverModeTransformer(mViewPager));
        }else{
        // 中间页面不覆盖,页面并排,只是Y轴缩小
        // mViewPager.setPageTransformer(false,new ScaleYTransformer());
        }

        把代码注释掉之还是会产生滑动缩放和放大效果,为什么呢? 我想去掉放大缩放效果
      • f581c38f3029:楼主,请教一下,这个左右两边的图怎么设置显示的宽度。我想让中间的图显示的比重大一点
        f581c38f3029:OK,找到了,在mz_banner_effect_layout布局中将margin设置一下就可以了
      • Joo明:您好;请问如何关闭掉动画,找了很久吧所有缩放相关的都注释了,还是找不到;求告知。谢谢了
        依然范特稀西:@Joo明 不让轮播吗
      • 许久__:你好,我从网络上获取的图片只能在请求成功的回调里调用setPages方法才能将图片渲染进去吗?不能像recyclerView一样暴露个notifyDataSetChanged方法吗? 我compile包进来,修改不了源码
        许久__:mMZBanner.getViewPager().getAdapter().notifyDataSetChanged(); 这样居然实现不了
      • 副业小侦探:作为分页加载的recyclerview头部,翻页就会停止运行,IndexOutOfBoundsException
      • 尉郁陨落星辰:楼主,指示器可以隐藏嘛?
        尉郁陨落星辰:@尉郁陨落星辰 魅族模式下,图片的宽不能改变?
        尉郁陨落星辰:@依然范特稀西谢谢,知道了
        依然范特稀西:@尉郁陨落星辰 可以
      • 啊哟瑞迪:楼主你好,为什么我只是用楼主提供的banner 资源是网络请的url app会非常卡.楼主没有遇到么 这个问题难道只有我自己遇到了? 这不应该吧
      • kim_liu:楼主你好,当banner只有两张图片的时候,魅族效果就没了:joy:
        依然范特稀西:@kim_liu 多谢,有啥修改意见或者需求场景可以给我提,我会尽量完善这个库
        kim_liu:@依然范特稀西 原来是这样 我以为两张图无限轮播的话 未显示的那张图应该在显示的那张图的左右两边显示 不过还是要给楼主赞一个 这个项目真的很棒 :+1: :+1:
        依然范特稀西:@kim_liu 对的,MZ效果一屏至少得三张图啊,两张图你想要什么显示效果呢?
      • 鱼__鱼:大佬,什么时候更新新版,急
      • zoysl:不错,喜欢,fuck一下
        依然范特稀西:@zoysl 调皮
      • 全球顶尖伪极客:楼主可以帮忙看看上个提出的问题吗
      • 全球顶尖伪极客:往里面LinearLayout通过代码动态加上布局的view这种方式加入其中之一的banner,可以自动滚动,但是手指滑动的时候并没有效果啊?没法拖动滑动banner,并且会停止自动滚动一旦触摸后
      • 好久不见_f20e:大神,您写的这个项目太棒了,受益匪浅,不过还想请教您个问题就是我想把指示器圆圆的那个放在在中间和底部,不过距离底部稍微有一点点空隙,该怎么解决
        好久不见_f20e:@依然范特稀西 谢谢大佬您了,多谢,您的这个项目实在太棒了
        依然范特稀西:@好久不见_f20e 有属性可以设置的哈, indicatorAlign 和 indicatorPadding
      • d7dbcce95a67:楼主你好 请问点击使用setBannerPageClickListener无反应是什么原因
        依然范特稀西:@明hao 在setPages 之前设置监听事件哈,readme 有提醒
      • 李睿这样说道:该怎么说爱你呢:joy:
        依然范特稀西:@李睿这样说道 直接了当的说就行:smile:
      • 撸码的皮大叔:你好 博主 我遇到一个问题 进去图片是显示 隔一段时间图片就没有 我用 Glide图片加载框架
        依然范特稀西:@Error_4b46 啊,这么奇怪?
      • Spur2:为什么我获取的网络数据 实现不了魅族的效果
      • Spur2:一张图可以不滚动吗
        Spur2:@依然范特稀西 是滚动的 昨天试了 我是在onResume里判断一下 长度等于1是 pause 就不滚动了
        依然范特稀西:@Spur2 一张图不会滚动啊
      • Spur2:对minSdkVersion有限制 最低16好像 用不了了
      • Jimven:望指教
      • Jimven:引用仓库地址as报错
      • f5c655d33479:多次调用setPages后,setDelayedTime失效了,无法进行自动轮播了
      • 201250f8bdf1:emmmmmmmm,设置Indicator的上下距离的版本没更新到v2.0.0上啊,很多更新的都没有放上去么
        201250f8bdf1:emmmmmmmmmm已经自己手写实现了
        依然范特稀西:@墨檐 只有indicator上下移动这个没更新上去,我check一下代价再更新
      • fbd15cb7c12c:大神这个做的很棒,想问个问题,我在想把项目内的指示器indicator放到banner下方,让他俩不重合的时候一直无法成功,项目里面的setIndicatorAlign也只能让指示器居中或者居左居右,不能让他俩分离吗,我操作布局文件强行让indicator放在banner下方,结果indicator直接不见了..想问问大神.希望解答.谢谢谢谢
        依然范特稀西:@痕迹_2ea0 你是想把indicator 放在哪儿呢?
        fbd15cb7c12c:@依然范特稀西 indicator与banner分开并且放在banner的下方,不与banner有重叠的部分,本来我在学习这个项目的时候,觉得这样做应该很简单就能实现,直接去改视图就行,结果一直都不行indicator和banner分离不开,就想来问问大神
        依然范特稀西:@痕迹_2ea0 你是要把indicator 放在哪儿呢?现在是放在下方,位置的调整后面有空了我加上
      • bb86dae3810e:谢谢楼主!!支持一下
      • codeRL:大佬,我改好了,主要是因为每次setpage都要addOnPageChangeListener,因为现在是add不是set,所以暂停的时候要removeOnPageChangeListener,主要就是给MZBannerView加一个OnPageChangeListener,并且将addOnPageChangeListener方法放入start中,在pause中remove就可以啦。
      • codeRL:您好,发现一个问题,当项目正在轮播时,我需要重新获取数据,于是我再次调用了setPages,和start,这时在onPageScrolled中就会监听到两个同样时间的返回值position等等,您明白我表达的意思么?
        依然范特稀西:@codeRL 好,有空我看一下
        codeRL:@依然范特稀西 嗯,应该是,我现在的需求是当本地一个文件夹里面图片有变化我就需要展示,所以展示的时候我要调用setpage和start,然后就发现了这个问题,你有空确认一下。:grin::grin:
        依然范特稀西:@codeRL 是同时回调了两次吗
      • hesanwei:你好,我从网络获取到数据以后,然后去setPages();总报ANR。请问这个问题如何解决
        依然范特稀西:@hesanwei 使用的最新的版本吗?
      • 0c2c0e6a7a0e:想知道这个banner能否实现轮播的不只是图片?比如有视频有图片的
        0c2c0e6a7a0e:昨天试着参考你的代码重写了个viewHolder,createView时卡住了, 我的想法是直接根据文件后缀名加载不同的布局,但是好像不行
        依然范特稀西:@智商太低会传染 这个确实还没考虑在Banner 上播放视频
      • 正阳Android:你好,我用了git上的,从网络获取到数据进行 展示,但是发现设置了不要mz_mode,也就是设置了false但是无效,还是和魅族banner效果一致
        依然范特稀西:这么奇怪,你看一下demo呢?
      • bde56ab49ac1:我遇到这个问题。是用网络地址请求图片加载的时候出现白图。不显示,我放的数据一共三张图片,往左滑动有三张白图,往右滑动没问题,不过再滑动几下就会出现白图,白图出现一个周期后就正常了。这个是什么原因呢?
        宏光难面:怎么让两边图片的宽度更宽点?
        bde56ab49ac1:@依然范特稀西 已经解决了,换了个图片加载的框架就好了。我现在是用的是Glide了。就OK了
        依然范特稀西:图片用什么框架加载的呢
      • cf6026e1eded:我想问下 为什么加了点击事件没用作用呢

        marketBanner.setBannerPageClickListener(new MZBannerView.BannerPageClickListener() {
        @Override
        public void onPageClick(View view, int positon) {
        Toast.makeText(BeginExamActivity.this,""+positon,Toast.LENGTH_SHORT).show();
        }
        });
        1a7ca2d05391:@依然范特稀西 老哥,这条我建议你更新到github上,找了半天都没找到原因:sweat_smile:
        依然范特稀西:@清幽茗乐 你是不是把点击事件加在 setPages 后面了?,放到setPages 前面去吧
      • 健健简书:我按照这个缩放动画设置,为什么只有一边的进行了缩放?
        mCommonViewPager = (CommonViewPager)findViewById(R.id.activity_common_view_pager);
        // 设置数据
        mCommonViewPager.setPages(mockData(), new ViewPagerHolderCreator<ViewImageHolder>() {
        @Override
        public ViewImageHolder createViewHolder() {
        // 返回ViewPagerHolder
        return new ViewImageHolder();
        }
        });

        mCommonViewPager.setPageTransformer(false, new CustomTramsformer());
      • 武玉树临风:按照你的例子写有个问题,下一个即将进入的页面边缘会不显示!只有滑动一下才会显示出来!不知道其他人有没有这样的问题!
        武玉树临风:@健健简书 我这几天比较忙,还没去追查找个,我下载博主的demo是没有问题的!
        健健简书:我好像也碰到这个问题了,你是怎么解决的
        依然范特稀西:@武玉树临风 没遇到过,你可以跑一下我的Demo看看
      • 技术咸鱼:哈哈,很厉害
        依然范特稀西:@sunho耗子 谢谢哈哈
      • 吾心彳亍:大神,这个可以自定义指示器么
        吾心彳亍:我这边无限轮播的时候有时候会同一时间过去两个页面
        吾心彳亍:@依然范特稀西 嗯,谢了!!!
        依然范特稀西:@没资本别折腾 可以的,有留方法setIndicatorRes
      • gaolhjy:您好.工作中有类似的效果.但好像有几个地方还没封装吧:
        (1)指示器的颜色
        (2)按住图片时,让图片停止轮播(松手后才开始轮播)
        (3)魅族模式时,动画不能取消吧
        望解答,谢谢.
        依然范特稀西:@微不足道5 指示器的更改是可以的,setIndicatorRes,设置选中和未选中的资源图片,按住图片停止轮播这个现在没有,后面会加上,魅族模式动画不能取消?指的是什么动画
      • dididiwd:能用网络的吗 还是我自己去把网络的图片加载下 再存集合?
        Spur2:@依然范特稀西 我这边使用网络地址 没有魅族轮播的效果了 都设置了 除非这样:
        list.add("http://img4.imgtn.bdimg.com/it/u=1088842023,4088486141&fm=27&gp=0.jpg");
        list.add("http://img1.imgtn.bdimg.com/it/u=970483208,2836013513&fm=27&gp=0.jpg");
        。。
        如果是网络返回的list集合 就不行了
        依然范特稀西:@橙子贵 不用下载的,直接加载网络图片链接就ok
      • dididiwd:已成功运行 就是这个Banner不能用网络地址啊
        依然范特稀西:@橙子贵 网络加载你用三方框架,如Picasso,Glide等
        dididiwd:@依然范特稀西 是哪 我没找到接口。。:flushed:
        依然范特稀西:@橙子贵 可以用网路的哟
      • 53a2cd08c793:魅族的在滑动的时候滑进来的page会慢慢变大,但是你的demo里这样写是没有的,我跟着写了一下感觉动画太突兀了,就是滑动完成了page突然变大
        42302eff423c:@Colaman_d7b1 可以请问下怎么解决的吗,我下载了demo看看发现把transformPage方法里的动画全部注释,他依然会缩放动画,是在哪还有这种操作吗
        53a2cd08c793:@听雨RainM 昨天已经解决,但是感觉和魅族的还是有一点点差别。
        RainMi:因为楼主是用float scale = Math.max(MIN_SCALE,1 - Math.abs(position))来计算缩放比例的,只有当position比较接近0的时候才会进行缩放,想要滑进来时就慢慢变大可以改成float scale = 1 - Math.abs(position) / 1 * (1 - MIN_SCALE);
      • dlihasa:感谢作者的分享,可能存在两个小问题,一个是在getStartSelectItem()方法获取初始位置的是时候,while循环应该是取余不为0时进行++吧?另外一个在轮播的runnable里面getcount不需要减一,只有currentitem和数量相等时不存在了才需要立即将crrentitem设置回0,当然因为getcount很大不会出现略过最后一个页面的问题,但是如果getcount不够大就可能出现略过最有一页的问题。
        依然范特稀西:谢谢指出问题,第一个问题已经改正,第二个不会有问题,因为用的Integer.Max_Value,基本到不了最后,如果用本文讲的第一种方式的话,是需要getCount-1的,因为是从0位置开始的,不-1,获取数据会越界
      • 看秋叶一片片飘落:饭依然太稀,吃不饱。。。
        写的真好,所有的文章都看了一遍,不错!!!
        依然范特稀西:@看秋叶一片片飘落 哈哈,谢谢鼓励
      • artshell:"第二种:右边划出屏幕,A:0->1, B :-1-> 0"

        应该是这样表述吧? “第二种:右边划入屏幕,A:-1->0, B :0->1 ”
        大叔top:上面那个地方看着有点晕 幸好看见你 同时也感谢作者
      • 8eab736b49b5:在别的网站看CoordinatorLayout,也指向了你的简书文章。你写的文章真的好实用而且思路很清晰。大神,你做安卓几年啦。
        冰冷的城市:@依然范特稀西 好惭愧 同样是两年 我和你相差也太大了
        依然范特稀西:@小青年_54b9 过奖了,2年多
      • 59014b2c7af8:很棒,
        依然范特稀西:@食指的诗 谢谢

      本文标题:ViewPager系列之 仿魅族应用的广告BannerView

      本文链接:https://www.haomeiwen.com/subject/mtlefxtx.html