无限循环的ViewPager

网络上有很多无线循环的Viewpager,但是学习嘛,就自己写了一个无线循环的ViewPager。

思路一
网上有一种是真正意义的无限循环,比如View0,View1,View2,View3, 4个View,
在View0左侧加一个View3,View3右侧加一个View0,
就成了View3-2, View0,View1,View2,View3, View0-2,
View3向右滑动,显示的是View0-2,viewPager.setCurrentItem(position,fasle)这个方法跳到View0,
同理View0左滑,显示的是View3-2,同样跳到View3,
这个方法的缺点就是,View0到View3滑动时流畅的,但是View3到View0,是瞬间变化的,不好看。

思路二
Adapter,getCount()设置为 Integer.MAX_VALUE ,这是一个非常非常大的数,
然后我们一进去就取中间值,无论左滑还是右滑,都能不停的循环加载View,
这些view也是重复使用的,因为这个数非常大,
所以你不会那么无聊,一直挂机,挂到他到底吧,所以就能模拟成无线循环,
而且界面的切换也是如丝般顺滑,我比较倾斜这个算法。


LoopView.gif

废话不说,直接代码上
小圆圈样式,少用图片吧,自己写个圆,很简单的。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">  
<item 
    android:drawable="@drawable/advertisement_circle_1"     
    android:state_checked="true"/>   
<item 
    android:drawable="@drawable/advertisement_circle_2" 
    android:state_checked="false"/>
</selector>

这是一个圆

<?xml version="1.0" encoding="utf-8"?>
<shape   
     android:shape="oval"    
     xmlns:android="http://schemas.android.com/apk/res/android">  
  <solid        
    android:color="#FFFFFF"/>  
  <size        
    android:width="15dp"        
    android:height="15dp"/>
</shape>
圆.jpg

这是一个圈

<?xml version="1.0" encoding="utf-8"?>
<shape    
    android:shape="oval"    
    xmlns:android="http://schemas.android.com/apk/res/android">    
<solid        
    android:color="#22FFFFFF"/>    
<stroke       
     android:width="1dp"        
    android:color="#FFFFFF"/>    
<size        
    android:width="15dp"        
    android:height="15dp"/>
</shape>
圈.jpg

自定义一个Adapter,要想使用LoopView。一定要使用该Adapter

import android.support.v4.view.PagerAdapter;
 
/**
 * 要用LoopView一定要使用这个Adapter
 */
public abstract class MyLoopViewAdapter extends PagerAdapter
{
    /**
     * 返回真实的view数
     */
    public abstract int getRealCount();
}
public class LoopViewAdapter extends MyLoopViewAdapter
{
    private ArrayList<View> views = new ArrayList<>();
 
    public LoopViewAdapter()
    {
    }
 
    public LoopViewAdapter(ArrayList<View> views)
    {
        this.views = views;
    }
 
    /**
     * 在下标position处添加View
     */
    public void insertView(View view, int position)
    {
        if (view != null)
        {
            this.views.add(position, view);
            notifyDataSetChanged();
        }
    }
 
    /**
     * 在尾部添加view
     */
    public void insertView(View view)
    {
        if (view != null)
        {
            this.views.add(view);
            notifyDataSetChanged();
        }
    }
 
    /**
     * 获取view
     */
    public View getView(int position)
    {
        return this.views.get(position);
    }
 
    @Override
    public int getCount()
    {
        //设置为一个很大很大的数
        return Integer.MAX_VALUE;
    }
 
    @Override
    public int getRealCount()
    {
        return views.size();
    }
 
    @Override
    public Object instantiateItem(final ViewGroup container, int position)
    {
        final View view = views.get(position % (views.size()));
 
        //在主线程添加
        container.post(new Runnable()
        {
            @Override
            public void run()
            {
                container.removeView(view);
                container.addView(view);
            }
        });
 
        return view;
    }
 
    @Override
    public void destroyItem(ViewGroup container, int position, Object object)
    {
    }
 
    @Override
    public boolean isViewFromObject(View view, Object object)
    {
        return view == object;
    }
}

自动轮播的Viewpager,默认情况下自动循环,时间间隔为2000毫秒


/**
 * 自动轮播Viewpager
 */
public class LoopViewPager extends RelativeLayout implements ViewPager.OnPageChangeListener
{
    //底部小圆圈的样式
    private int dotRes = -1;
    //图片轮转周期
    private int period = 2000;
    private static final int ADVERTISEMENT = 1;
    private NoScrollViewPager noScrollViewpager;
    private RadioGroup radioGroup;
    private LoopViewAdapter loopViewAdapter;
 
    public LoopViewPager(Context context)
    {
        this(context, null);
    }
 
    public LoopViewPager(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }
 
    public LoopViewPager(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }
 
    private Handler handler = new Handler(new Handler.Callback()
    {
        @Override
        public boolean handleMessage(Message msg)
        {
            switch (msg.what)
            {
                case ADVERTISEMENT:
                    viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
                    handler.sendEmptyMessageDelayed(ADVERTISEMENT, period);
                    break;
                default:
                    break;
            }
            return false;
        }
    });
 
    /**
     * 初始化控件
     */
    private void init()
    {
        noScrollViewpager = new NoScrollViewPager(getContext());
        noScrollViewpager.addOnPageChangeListener(this);
       //允许滑动
       noScrollViewpager.setScrollable(true);
 
        radioGroup = new RadioGroup(getContext());
        //设置RadioGroup为水平排列
        radioGroup.setOrientation(RadioGroup.HORIZONTAL);
 
        //让viewpager填充满怎个布局
        RelativeLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT
                , LayoutParams.MATCH_PARENT);
        viewPager.setLayoutParams(params);
        addView(viewPager);
 
        //设置radioGroup包裹内容
        params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        //设置为水平居中
        params.addRule(CENTER_HORIZONTAL);
        //设置为父布局的底部
        params.addRule(ALIGN_PARENT_BOTTOM);
        radioGroup.setLayoutParams(params);
        addView(radioGroup);
    }
 
    /**
     * 设置小圆点的样式
     */
    public void setDotRes(int dotRes)
    {
        this.dotRes = dotRes;
        if (dotRes == 0)
        {
            return;
        }
        for (int i = 0; i < radioGroup.getChildCount(); i++)
        {
            radioGroup.getChildAt(i).setBackgroundResource(dotRes);
        }
    }
 
    /**
     * 设置底部小圆点RadioGroup是否可见
     */
    public void setDotVisible(boolean visible)
    {
        if (visible)
        {
            radioGroup.setVisibility(VISIBLE);
        } else
        {
            radioGroup.setVisibility(GONE);
        }
    }
 
    /**
     * 设置轮播间隔
     */
    public void setPeriod(int period)
    {
        this.period = period;
    }
 
    /**
     * 设置是否开始滚动
     */
    public void startLoop()
    {
        //先移除,防止重复加载
        stopLoop();
        //发送延时消息
        handler.sendEmptyMessageDelayed(ADVERTISEMENT, period);
    }
 
    /**
     * 停止滚动
     */
    public void stopLoop()
    {
        handler.removeMessages(ADVERTISEMENT);
    }

   /**
      * 设置ViewPager是否允许手动滑动
      */
    public void setViewPagerScrollable(boolean scroll)
    {    
        noScrollViewpager.setScrollable(scroll);
    }
 
    /**
     * 返回当前页码
     */
    public int getCurrentItem()
    {
        return viewPager.getCurrentItem() % loopViewAdapter.getRealCount();
    }
 
    /**
     * 设置适配器
     */
    public void setAdapter(LoopViewAdapter adapter)
    {
        if (adapter == null)
        {
            return;
        }
        this.loopViewAdapter = adapter;
        int count = adapter.getRealCount();
 
        //根据适配器的图片数量,设置小圆点的数量
        for (int i = 0; i < count; i++)
        {
            RadioButton radioButton = new RadioButton(getContext());
            //给RadioButton一个空的BitmapDrawable对象,骗过setButtonDrawable的过滤,实际上绘制的时候是没有图片资源
            //将RadioButton的小圆点去掉
            radioButton.setButtonDrawable(new ColorDrawable());
            //设置不能点击
            radioButton.setEnabled(false);
            //设置小圆点的尺寸
            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(15, 15);
            //设置小圆点的间距
            params.setMargins(0, 0, 10, 20);
            radioButton.setLayoutParams(params);
 
            //设置背景样式
            if (dotRes != -1)
            {
                radioButton.setBackgroundResource(dotRes);
            } else
            {
                radioButton.setBackgroundResource(R.drawable.advertisement_circle);
            }
            radioGroup.addView(radioButton);
        }
 
        //第一个显示为已选定
        RadioButton radioButton = (RadioButton) radioGroup.getChildAt(0);
        radioButton.setChecked(true);
 
        viewPager.setAdapter(loopViewAdapter);
        //设置viewPager切换动画
        viewPager.setPageTransformer(true, new DepthPageTransformer());
        //每次打开都会显示Viewpager第一页
        viewPager.setCurrentItem((loopViewAdapter.getCount() / 2) -
                (loopViewAdapter.getCount() / 2) % loopViewAdapter.getRealCount());
        //开始循环
        startLoop();

       //不显示小圆点,不能滑动,不循环
       if (count == 1)
       {    
           setDotVisible(false);    
           stopLoop();    
           noScrollViewpager.setScrollable(false);     
           noScrollViewpager.setCurrentItem(0);
       }
    }
 
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
    {
    }
 
    @Override
    public void onPageSelected(int position)
    {
        RadioButton radioButton = (RadioButton) radioGroup
                .getChildAt(position % loopViewAdapter.getRealCount());
        radioButton.setChecked(true);
    }
 
    @Override
    public void onPageScrollStateChanged(int state)
    {
        switch (state)
        {
            //手拖住就停止计时
            case ViewPager.SCROLL_STATE_DRAGGING:
                stopLoop();
                break;
            //松开继续继续计时
            case ViewPager.SCROLL_STATE_IDLE:
                startLoop();
                break;
            default:
                break;
        }
    }
}

使用,里面的view都是自定义的

public class LoopViewPagerActivity extends AppCompatActivity
{
    private LoopViewPager loopViewPager;
    private LoopViewAdapter loopViewAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view);
        initView();
    }
    private void initView()
    {
        loopViewPager = (LoopViewPager) findViewById(R.id.advertisementViewPager);
        //设置间隔
        loopViewPager.setPeriod(3000);
        initAdapter(getImages());
        loopViewPager.setAdapter(loopViewAdapter);
    }
    private void initAdapter(ArrayList<String> images)
    {
        final ArrayList<View> views = new ArrayList<>();
        for (int i = 0; i < 5; i++)
        {
            View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item, null);
            final TextView textView = (TextView) view.findViewById(R.id.item_tv);
            textView.setText("Mo.nica " + i);
            ImageView imageView = (ImageView) view.findViewById(R.id.item_image);
            //Glide加载图片
            Glide.with(getApplicationContext())
                    .load(images.get(i))
                    .into(imageView);
            textView.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    Toast.makeText(LoopViewPagerActivity.this, textView.getText().toString(), Toast.LENGTH_SHORT).show();
                }
            });
            view.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    Toast.makeText(LoopViewPagerActivity.this, "" + loopViewPager.getCurrentItem(), Toast.LENGTH_SHORT).show();
                    if (loopViewPager.getCurrentItem() == views.size() - 1)
                    {
                        finish();
                    }
                }
            });
            views.add(view);
        }
        loopViewAdapter = new LoopViewAdapter(views);
    }
    private ArrayList<String> getImages()
    {
        ArrayList<String> images = new ArrayList<>();
        images.add("http://download.pchome.net/wallpaper/pic-9468-1.jpg");
        images.add("http://img5.duitang.com/uploads/item/201506/14/20150614215810_ckiPE.jpeg");
        images.add("http://bizhi.cnanzhi.com/upload/bizhi/2014/1202/1417503024216.png");
        images.add("http://img4.duitang.com/uploads/item/201511/09/20151109150254_EFTmw.jpeg");
        images.add("http://img1.3lian.com/2015/w22/99/d/86.jpg");
        images.add("http://cdn.duitang.com/uploads/item/201504/09/20150409H0455_dSNH4.jpeg");
        return images;
    }}


ViewPager切换也是有动画的,这个是看鸿洋大神的
http://blog.csdn.net/lmj623565791/article/details/40411921

public class DepthPageTransformer implements ViewPager.PageTransformer
{
    private static final float MIN_SCALE = 0.75f;
 
    public void transformPage(View view, float position)
    {
        int pageWidth = view.getWidth();
 
        if (position < -1)
        { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);
 
        } else if (position <= 0)
        { // [-1,0]
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);
 
        } else if (position <= 1)
        { // (0,1]
            // Fade the page out.
            view.setAlpha(1 - position);
 
            // Counteract the default slide transition
            view.setTranslationX(pageWidth * -position);
 
            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
 
        } else
        { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

最后附件,上传不了啊,算了,全部代码都在,没有大牛写的厉害,但是一起学习吧
源码下载地址:http://download.csdn.net/detail/u013365445/9608109

Github:https://github.com/Goodbao/LoopViewPager

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,116评论 25 707
  • 这是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api。而view...
    Ten_Minutes阅读 5,738评论 1 19
  • 不是读幼儿心理学的我一直在纳闷,为何儿子明明是爱我的,为什么表现出这么的讨厌我? 宝宝最黏就是我了,...
    咸蛋黄ss阅读 149评论 0 0
  • 觉得该写点东西,再睡。 好吧,我承认我是三心二意的人。我来给你详细分析下我说的“三心二意”。我总是会这样,和人说着...
    马祥阅读 280评论 0 0