用ViewPager写一个Banner

来源:互联网 发布:淘宝联盟机器人免费版 编辑:程序博客网 时间:2024/06/01 09:20

Banner没少用,记得第一次用banner的时候,是找一个大神要的一个自定义的banner,就一个java文件,觉得超级厉害;后来又一直用的convenientbanner,觉得这个很不错,就一直用的这个,压根就没想要自己写一个;首先,不造重复的轮子;其次,不会。
今天在鸿洋大神公众号上看到了有人讲用ViewPager写一个Banner,讲了一下思想和简单实现,所以我想着我也试一下呗!
下面的代码和讲解没有多大的用途,只是简单的实现了一下形式,没有具体的优化,(其实个人只是想看一下实现的效果)。
这里写图片描述

被压缩的有点严重,将就看看

先给个布局代码吧:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="200dip">    <android.support.v4.view.ViewPager        android:id="@+id/viewPager"        android:layout_width="match_parent"        android:layout_height="200dip" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_gravity="bottom"        android:orientation="vertical">        <LinearLayout            android:id="@+id/ll"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:gravity="center"            android:orientation="horizontal" />        <TextView            android:id="@+id/title"            android:layout_width="match_parent"            android:layout_height="30dip"            android:layout_gravity="bottom"            android:background="#30000000"            android:gravity="center_vertical"            android:paddingLeft="10dip"            android:text="今日安卓"            android:textColor="#ffffff" />    </LinearLayout></FrameLayout>

一个ViewPager,然后是指示器和标题栏
我实现这个效果是一遍在网上找,一遍敲,前后花了几个小时,所以之间也失败了好几次,失败的就不放代码了。
1、我最开始做的是普通的手动从头滑到尾,因为开始 看到介绍FragmentPagerAdapter,所以就用Fragment,里面就放置一个ImageView;
普通的adapter,普通的设置,开始没去管指示器和title,我本以为只是显示图片应该是一件很简单的事,但是我失算了,在写那个item,也就是Fragment的时候,我加载那个图片始终是失败:1、不能在主线程中加载(给自己一巴掌);2、AsyncTask加载图片,但是当我加载多张的时候就有问题了;3、放弃吧,用Glide,最终出现可以手动滑动的banner

开始添加指示器和title,这个直接在滑动监听器中去监听就可以了。
由于Fragment中只有一个ImageView,所以我弃用了,直接用PageAdapter,在代码中创建ImageView

2、但是,作为一个好banner,怎么能要去手动滑动呢,的自己动才行啊,于是添加了一个Handler

private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            viewPager.setCurrentItem((viewPager.getCurrentItem() + 1));            this.sendEmptyMessageDelayed(MSG_WHAT, 3000);        }    };

当然你要先发送

mHandler.sendEmptyMessageDelayed(MSG_WHAT, 3000);

来触发它,嗯,这样就很不错了,可以自己动。

3、不行不行,动一圈就不想动了怎么行,你得无限动起来才行啊,你可是banner啊
这个怎么办,我不会啊,放弃吧!
在网上找了找,有一个公认方法,就是说的夸张一点,我这个只有3张图片,播完就没了,我可以加长啊,给他一万张图片,先从1播到3,到4的时候,图片的资源又从1到3
只有3张

1->2->3 没了

给你10000张

1->2->3->1->2->3->1->2->3->………………很多张……………………->1

这样就可以播放很久了,但是这是往前播放,也就是从左往右,那要是从右往左呢,怎么办?那我就把起始位置放到5002这个位置,这就处于中间了,这样往左往右就可以播放很久了,当然,网上的建议是Integer.MAX_VALUE,一个超大值,中间嘛就不好确定了,给他个10000什么的,难道你还能往左划个10000张?

我能
。。。

卧槽,你是段友吗?

既然有那么无聊的人存在,我们就得放弃这种方法。

4、在图片数组的前后各加一个图片

7->1->2->3->4->5->6->7->1

就是在1前面加个最后一张7,在最后一张7的后面加个一张1,搞一个偷梁换柱;
说的可能不好理解,咱们走一个流程:

肯定是从1开始的,也就是下标为1的地方开始为默认位置,然后往前走,一直走到7,然后走到最后一个1,当走的1的动画停止之后,我们瞬间将位置移到开始的那个1(说的悬一点,就是当最后一个1结束后,时间静止,然后这个1跑到第一个1的位置上和他重合,然后时间恢复,下一个就是正常流程了),当返过来滑动也是一样,就是第一个7和最后一个7的互动了,这里主要用到了:

public void setCurrentItem(int item)

大家看到这个,肯定觉得我在骗人,没错:

public void setCurrentItem(int item, boolean smoothScroll)

其实是这个,当我们用第一个的时候,从1到3,总是呼啸而过,中间夹杂的2,我们都能看的见,都说要事件静止了,这么大动静可不行啊;
所以我们用第二个,第二个参数传入false,秒到。

@Override    public Object instantiateItem(ViewGroup container, int position) {        //0下标与最大下标分别加入图一与图5,正常图片顺序从1下标开始.所以需要改变position        //如果下标是0,        if (position == 0) {            //将下标指向图五            position = newsList.size() - 1;            //如果是最后一个下标        } else if (position == getCount() - 1) {            //将下标指向图一            position = 0;        } else {            //上面两步将左右两边的下标指向了图一和图五            //我们正常的图片从下标一开始,所以需要-1            position -= 1;        }        ImageView imageView = new ImageView(context);        Glide.with(context).load(newsList.get(position % newsList.size())).centerCrop().crossFade().into(imageView);        container.addView(imageView);        return imageView;    }

主要是:

if (position == 0) {    position = newsList.size() - 1;} else if (position == getCount() - 1) {    position = 0;} else {    position -= 1;}

当下标=0时,也就是第一个7,这时候我们要瞬移到最后一个7
当下标=getCount() - 1时,也就是最后一个1,这时候我们要瞬移到最后一个1
然后正常显示,但是以为我们前后都插入了一张图片,所以下标都要-1;
我们在监听器中做瞬移:

            @Override            public void onPageScrollStateChanged(int state) {                //如果当前是静止的状态(等待动画走完,静默切换界面                if (state == ViewPager.SCROLL_STATE_IDLE) {                    //如果当前页面的直线0下标的图,静默切换界面                    if (viewPager.getCurrentItem() == 0) {                        //跳转到正常的图5                        viewPager.setCurrentItem(imageUrls.size(), false);                        //如果当前页面指向最大下标的图一                    } else if (viewPager.getCurrentItem() == imageUrls.size() + 1) {                        //跳转到正常的图一                        viewPager.setCurrentItem(1, false);                    }                }            }

这时候就OK了

对了,我的指示器和title呢???

在监听器中呢:

                if (position == 0) {                    position = imageUrls.size() - 1;                } else if (position == count+1) {                    position = 0;                } else {                    position -= 1;                }                title.setText(titles.get(position));                for (int i = 0; i < ll.getChildCount(); i++) {                    ImageView imageView = (ImageView) ll.getChildAt(i);                    if (position == i) {                        imageView.setImageResource(R.mipmap.select);                    } else {                        imageView.setImageResource(R.mipmap.unselect);                    }                }

这就是效果图了:

但是 看起来还欠缺点什么,对就是切换的时候划得太快了,猝不及防的,刷的一下就过去了,怎么办,既然是在setCurrentItem的时候切换的,那我就去这里面找吧,看能不能更改一下切换的时间(和之前那个位置瞬移不一样,那是是瞬移的位置,这个是切换的时间,在那个瞬移的时候还是时间静止了,没变);

咱们深入源码,一步一步点进去看看;点了几下,算了还是出来吧,有什么事情是不能选择放弃的呢?去网上看看别人家的孩子是怎么做的,果不其然:
先继承Scroller,修改过渡时间;然后通过反射ViewPager中的Scroller,将我们的Scroller替换成里面的Scroller

public class ViewPagerScroller extends Scroller {    private int mScrollDuration = 2000;             // 滑动速度    /**     * 设置速度速度     * @param duration     */    public void setScrollDuration(int duration){        this.mScrollDuration = duration;    }    public ViewPagerScroller(Context context) {        super(context);    }    @Override    public void startScroll(int startX, int startY, int dx, int dy, int duration) {        super.startScroll(startX, startY, dx, dy, mScrollDuration);    }    @Override    public void startScroll(int startX, int startY, int dx, int dy) {        super.startScroll(startX, startY, dx, dy, mScrollDuration);    }    public void initViewPagerScroll(ViewPager viewPager) {        try {            Field mScroller = ViewPager.class.getDeclaredField("mScroller");            mScroller.setAccessible(true);            mScroller.set(viewPager, this);        } catch(Exception e) {            e.printStackTrace();        }    }}

使用

ViewPagerScroller scroller = new ViewPagerScroller(context);  scroller.setScrollDuration(2000);  scroller.initViewPagerScroll(viewPager);//这个是设置切换过渡时间为2秒

使用之后,果然不错,但是还是有一个毛病,那就是当最后一个切换到第一个的时候,在第一个那也停顿了3秒,效果就很不好了,这就需要优化了,怎么办,放弃吧!

这次我是真放弃了,主要是天太晚了,还要干正事,只能先搁浅(主要是不想去优化,一旦有了这个念头,我就连一加一等于几都不想去想)

我的保守猜测是在瞬移的时候更换ViewPager的Scroller(间接更换时间),但是尝试后没效果,可能是我用的方法不对,也可能猜想不对。

给出所有代码:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="260dip"><android.support.v4.view.ViewPager    android:id="@+id/viewPager"    android:layout_width="match_parent"    android:layout_height="260dip" /><LinearLayout    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_gravity="bottom"    android:orientation="vertical">    <LinearLayout        android:id="@+id/ll"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:orientation="horizontal" />    <TextView        android:id="@+id/title"        android:layout_width="match_parent"        android:layout_height="30dip"        android:layout_gravity="bottom"        android:background="#30000000"        android:gravity="center_vertical"        android:paddingLeft="10dip"        android:text="今日安卓"        android:textColor="#ffffff" /></LinearLayout></FrameLayout>
package com.xiey94.viewpager;import android.content.Context;import android.support.v4.view.PagerAdapter;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import com.bumptech.glide.Glide;import java.util.List;/** * @author xiey * @date created at 2017/12/21 13:35 * @package com.xiey94.viewpager * @project Retrofit2 * @email xiey94@qq.com * @motto Why should our days leave us never to return? */public class BannerAdapter extends PagerAdapter {    private Context context;    private List<String> newsList;    public BannerAdapter(Context context, List<String> newsList) {        this.context = context;        this.newsList = newsList;    }    @Override    public int getCount() {        return newsList.size() + 2;    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view == object;    }    @Override    public Object instantiateItem(ViewGroup container, int position) {        //0下标与最大下标分别加入图一与图5,正常图片顺序从1下标开始.所以需要改变position        //如果下标是0,        if (position == 0) {            //将下标指向图五            position = newsList.size() - 1;            //如果是最后一个下标        } else if (position == getCount() - 1) {            //将下标指向图一            position = 0;        } else {            //上面两步将左右两边的下标指向了图一和图五            //我们正常的图片从下标一开始,所以需要-1            position -= 1;        }        ImageView imageView = new ImageView(context);        Glide.with(context).load(newsList.get(position % newsList.size())).centerCrop().crossFade().into(imageView);        container.addView(imageView);        return imageView;    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView((View) object);    }}
package com.xiey94.viewpager;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.v4.app.Fragment;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    private ViewPager viewPager;    private LinearLayout ll;    private TextView title;    private ViewPagerAdapter adapter;    private BannerAdapter adapter2;    private List<Fragment> fragments = new ArrayList<>();    private List<String> imageUrls = new ArrayList<>();    private List<String> titles = new ArrayList<>();    private int count=12;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        viewPager = (ViewPager) findViewById(R.id.viewPager);        ll = (LinearLayout) findViewById(R.id.ll);        title = (TextView) findViewById(R.id.title);        imageUrls.add("http://img06.tooopen.com/images/20160921/tooopen_sy_179583447187.jpg");        imageUrls.add("http://img05.tooopen.com/images/20160121/tooopen_sy_155168162826.jpg");        imageUrls.add("http://d.5857.com/tc_170411/001.jpg");        imageUrls.add("http://img02.tooopen.com/images/20160509/tooopen_sy_161967094653.jpg");        imageUrls.add("http://www.sdklty.com/d/file/2015/11/27/2123f7686d354b4d1b67b99a7f657747.jpg");        imageUrls.add("http://seopic.699pic.com/photo/00026/7248.jpg_wh1200.jpg");        imageUrls.add("http://pic.sc.chinaz.com/files/pic/pic9/201511/apic16248.jpg");        imageUrls.add("http://d.5857.com/tc_170411/001.jpg");        imageUrls.add("http://img02.tooopen.com/images/20160509/tooopen_sy_161967094653.jpg");        imageUrls.add("http://www.sdklty.com/d/file/2015/11/27/2123f7686d354b4d1b67b99a7f657747.jpg");        imageUrls.add("http://seopic.699pic.com/photo/00026/7248.jpg_wh1200.jpg");        imageUrls.add("http://pic.sc.chinaz.com/files/pic/pic9/201511/apic16248.jpg");        for (int i = 0; i < count; i++) {            ItemFragment fragment = new ItemFragment();            fragment.setUrl(imageUrls.get(i));            fragments.add(fragment);            titles.add("今日安卓----第" + (i + 1) + "张图");            ImageView imageView = new ImageView(this);            imageView.setImageResource(R.mipmap.unselect);            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(8, 8);            params.setMargins(4, 4, 4, 4);            imageView.setLayoutParams(params);            ll.addView(imageView);        }        ImageView imageView = (ImageView) ll.getChildAt(0);        imageView.setImageResource(R.mipmap.select);        title.setText(titles.get(0));        adapter = new ViewPagerAdapter(getSupportFragmentManager(), this, fragments, imageUrls);        adapter2 = new BannerAdapter(this, imageUrls);        viewPager.setAdapter(adapter2);        ViewPagerScroller scroller = new ViewPagerScroller(this);        scroller.setScrollDuration(3000);        scroller.initViewPagerScroll(viewPager);//这个是设置切换过渡时间为3秒        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {            @Override            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            }            @Override            public void onPageSelected(int position) {                if (position == 0) {                    position = imageUrls.size() - 1;                } else if (position == count+1) {                    position = 0;                } else {                    position -= 1;                }                title.setText(titles.get(position));                for (int i = 0; i < ll.getChildCount(); i++) {                    ImageView imageView = (ImageView) ll.getChildAt(i);                    if (position == i) {                        imageView.setImageResource(R.mipmap.select);                    } else {                        imageView.setImageResource(R.mipmap.unselect);                    }                }            }            @Override            public void onPageScrollStateChanged(int state) {                //如果当前是静止的状态(等待动画走完,静默切换界面                if (state == ViewPager.SCROLL_STATE_IDLE) {                    //如果当前页面的直线0下标的图,静默切换界面                    if (viewPager.getCurrentItem() == 0) {                        //跳转到正常的图5                        viewPager.setCurrentItem(imageUrls.size(), false);                        //如果当前页面指向最大下标的图一                    } else if (viewPager.getCurrentItem() == imageUrls.size() + 1) {                        //跳转到正常的图一                        viewPager.setCurrentItem(1, false);                    }                }            }        });        viewPager.setCurrentItem(1);        mHandler.sendEmptyMessageDelayed(MSG_WHAT, 3000);    }    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            viewPager.setCurrentItem((viewPager.getCurrentItem() + 1));            this.sendEmptyMessageDelayed(MSG_WHAT, 3000);        }    };    //发送    public static final int MSG_WHAT = 0001;}

我用的是网络图片,所以忘了网络权限,还有加载图片的Glide

<uses-permission android:name="android.permission.INTERNET" />

目前就是所有的代码以及效果了。
在此,感谢多次让我差点放弃的”别人家的孩子”






参考与摘抄:

ViewPager 超详解:玩出十八般花样
ViewPager真正的无限轮播
ViewPager真正实现无限轮播(偷梁换柱法,切换无回滚)
怎么设置viewpager在使用setCurrentItem的滑动速度


原创粉丝点击