用ViewPager写一个Banner

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的滑动速度


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个使用Android Studio编轮播图的示例代码: 1. 首先,在你的布局文件中添加一个ViewPager和一个指示器(例如使用ViewPagerIndicator库),用于显示轮播图和当前轮播图的位置。 ```xml <androidx.viewpager.widget.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="200dp"/> <com.viewpagerindicator.CirclePageIndicator android:id="@+id/indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:padding="10dp"/> ``` 2. 创建一个Adapter类,用于向ViewPager中添加轮播图视图。在这个类中,你需要重getItem()方法,该方法返回一个包含轮播图视图的Fragment。 ```java public class BannerAdapter extends FragmentPagerAdapter { private List<Fragment> fragmentList; public BannerAdapter(FragmentManager fm, List<Fragment> fragments) { super(fm); this.fragmentList = fragments; } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public int getCount() { return fragmentList.size(); } } ``` 3. 在MainActivity中,创建一个包含轮播图图片的Fragment列表,然后将它们添加到ViewPager中,并设置ViewPager的适配器和指示器。 ```java public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private CirclePageIndicator indicator; private List<Fragment> fragmentList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = findViewById(R.id.view_pager); indicator = findViewById(R.id.indicator); // 创建包含轮播图图片的Fragment列表 fragmentList = new ArrayList<>(); fragmentList.add(BannerFragment.newInstance(R.drawable.banner1)); fragmentList.add(BannerFragment.newInstance(R.drawable.banner2)); fragmentList.add(BannerFragment.newInstance(R.drawable.banner3)); // 设置ViewPager的适配器和指示器 BannerAdapter adapter = new BannerAdapter(getSupportFragmentManager(), fragmentList); viewPager.setAdapter(adapter); indicator.setViewPager(viewPager); } } ``` 4. 最后,创建一个BannerFragment类,用于显示轮播图图片。在该类中,你需要在onCreateView()方法中创建一个包含ImageView的视图,并设置其图片资源。 ```java public class BannerFragment extends Fragment { private static final String ARG_RES_ID = "res_id"; private int resId; public BannerFragment() { } public static BannerFragment newInstance(int resId) { BannerFragment fragment = new BannerFragment(); Bundle args = new Bundle(); args.putInt(ARG_RES_ID, resId); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { resId = getArguments().getInt(ARG_RES_ID); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_banner, container, false); ImageView imageView = view.findViewById(R.id.image_view); imageView.setImageResource(resId); return view; } } ``` 这就是一个简单的Android Studio

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值