Android实现一个丝滑的自动轮播控件实例代码

前言

现在很多的 App 都有自动轮播的 banner 界面,用于展示广告图片或者显示当前比较热门的一些活动,除了具备比较酷炫的效果之外,通过轮播的方式来减少对界面的占用,也是很赞的一个设计点。本文主要是总结自动轮播控件的实现过程,以及对这类控件的一些优化的技巧。

一、如何实现

在开始进行我们的代码编程之前,我们先要思考一下,在 Google 提供的官方 Api 里面,有没有类似的控件实现了相似的功能,毕竟官方的控件大都经过了时间的考验,无论是稳定性还是性能方面都是非常不错的,如果我们能够基于官方的控件进行相应的改造,控件的稳定性也会有相对的保障。

在比较常见的主流控件里面,其实 ViewPager 和 RecyclerView 已经实现了类似的功能,尤其是 ViewPager,可以说是已经实现了我们这个控件的大部分功能,所以如果我们基于 ViewPager 来进行改造的话,也能让我们的轮播控件更加稳定。

那 ViewPager 跟我们需要的自动轮播控件有多少差距呢,主要有两个:

  • 不支持自动播放
  • 无法从最后一张滑动到第一张

所以我们主要是针对这两部分进行相应的改造,从而实现我们自己的自动轮播控件。

1.1 实现自动轮播功能

要想实现自动轮播功能,我们最先想到的应该是通过 Timer 或者 ScheduledExecutorService 来实现计时器的功能,然后让 ViewPager 通过 serCurrentItem(int position) 方法,将当前的 Item 设置为下一个 position 的数据,但是如果通过定时器来实现的话,会有一个问题,那就是我们在需要让 banner 进行停止播放的时候就比较麻烦,所以通过 Handler 用 sendMessage 的形式,进行事件的发送实现 ViewPager 的自动轮播,以及某些场景的停止是比较合理的。

我们来看下代码:

 private static class AutoScrollHandler extends Handler {

 private WeakReference<AutoScrollViewPager> mBannerRef;

 private static final int MSG_CHANGE_SELECTION = 1;

 AutoScrollHandler(AutoScrollViewPager autoScrollViewPager) {
  mBannerRef = new WeakReference<>(autoScrollViewPager);
 }

 private void start() {
  removeMessages(MSG_CHANGE_SELECTION);
  sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
 }

 private void stop() {
  removeMessages(MSG_CHANGE_SELECTION);
 }

 @Override
 public void handleMessage(Message msg) {
  if (msg.what == MSG_CHANGE_SELECTION) {
  if (mBannerRef == null || mBannerRef.get() == null) {
   return;
  }
  AutoScrollViewPager banner = mBannerRef.get();

  if (banner.mSelectedIndex == Integer.MAX_VALUE) {
   int rightPos = banner.mSelectedIndex % banner.mBannerList.size();
   banner.setCurrentItem(banner.getInitPosition() + rightPos + 1, true);
  } else {
   if (!hasMessages(MSG_CHANGE_SELECTION)) {
   banner.setCurrentItem(banner.mSelectedIndex + 1, true);
   sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
   }
  }

  }
 }
 }

可以看到,我们先传入外部的 ViewPager,然后通过弱引用的形式防止内存泄露,通过在 handlerMessage() 方法里面,调用 setCurrentItem() 方法,将当前 ViewPager 的 Item 设置为对应的 position + 1 的数据,所以我们只要在外部调用 Handler 的 sendMessage() 方法,就能使 ViewPager 进行自动的无限轮播。

1.2 让 ViewPager 从最后一张滑动到第一张

我们知道,ViewPager 是无法从最后一页滑动到第一页的,但我们可以换一个思路,如果我们在 ViewPager 的 Adapter 里面,通过 getCount() 方法将 ViewPager 的大小设置为无限大,然后通过取余的方式来保证滑动的页面一直对应数据源的那几个数据,这样便能让 ViewPager 实现从最后一张滑动到第一张的效果。

 public int getCount() {
  if (mBannerList == null) {
   return 0;
  }
  if (mBannerList.size() == 1) {
   return 1;
  } else {
   return Integer.MAX_VALUE;
  }
 }
 public Object instantiateItem(ViewGroup container, final int position) {
  if (mBannerList != null && mBannerList.size() > 0) {
   View imageView = null;
   Uri uri = Uri.parse(mBannerList.get(position % mBannerList.size()).cover_url); // 通过取余的方式
   imageView = new SimpleDraweeView(mContext);
   ((SimpleDraweeView) imageView).setImageURI(uri);
   container.addView(imageView);
   return imageView;
  }
  return null;
 }

二、如何进行优化

在上面我们只是简单的实现了 ViewPager 的自动轮播功能,但其实还有很多的细节需要我们进行优化,例如:我们是通过将 ViewPager 的大小设置为无限大的方式,来实现从最后一张滑动到第一张的,但这时候如果不进行缓存的话,我们在 Adapter 的 instantiateItem(ViewGroup container, final int position) 方法里面,便需要返回很多新 new 出来的 View,这样会造成不必要的内存浪费,只有对这些细节进行优化,才能让我们的控件更加的好用,稳定性和性能方面也会更加优异。

2.1 通过缓存减少内存浪费

为了让 ViewPager 能实现无线轮播的功能,我们是使用了通过将 getCount() 的大小设置为无限大的方式来实现的,但这会产生一个问题,这样会使我们在 Adapter 的 instantiateItem() 方法中返回很多新 new 出来的 View,而造成不必要的内存浪费。

所以我们可以通过一个 List 作为缓存池,在 Adapter 中的 destroyItem() 方法中将废弃的 object 存到缓存池中,重复利用,这样便能避免内存浪费。

 private final ArrayList<View> mViewCaches = new ArrayList<>();

 @Override
 public void destroyItem(ViewGroup container, int position, Object object) {
  ImageView imageView = (ImageView) object;
  container.removeView(imageView);
  mViewCaches.add(imageView);
 }

然后在 Adapter 的 instantiateItem() 方法中,从 List 中取出已经被缓存的 View,进行重复利用

 public Object instantiateItem(ViewGroup container, final int position) {
  if (mBannerList != null && mBannerList.size() > 0) {
   View imageView = null;
   Uri uri = Uri.parse(mBannerList.get(position % mBannerList.size()).cover_url);
   if (mViewCaches.isEmpty()) {
    imageView = new SimpleDraweeView(GlobalContext.getContext());
   } else {
    // 当缓存集合有数据时,进行复用
    imageView = (ImageView) mViewCaches.remove(0);
   }
 }

2.2 适当的停止自动轮播

当我们触摸 Banner 或者离开当前展示 Banner 的页面时,如果 banner 还在不停的进行无线轮播的话,会造成没必要的性能损失,所以我们需要在触摸 Banner 以及当前的 Activity 为不可见状态的时候,停止 Banner 的轮播,从而提升性能。

 public boolean dispatchTouchEvent(MotionEvent ev) {
  int action = ev.getAction();
  if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
    || action == MotionEvent.ACTION_OUTSIDE) {
   startAutoPlay();
  } else if (action == MotionEvent.ACTION_DOWN) {
   stopAutoPlay();
  }
  return super.dispatchTouchEvent(ev);
 }

2.3 改变 ViewPager 切换速度

原生的 ViewPager 在进行自动轮播的时候,切换速度是特别快的,会给人一种很突兀的感觉,而且 ViewPager 也没有提供接口给我们对 ViewPager 进行切换速度的设置,所以我们需要通过反射的方式,使用 Scroller 来进行切换速度的设置,从而让我们的 Banner 更加的丝滑。

 public AutoScrollViewPager(Context context) {
  this(context, null);
  initViewPagerScroll();
 }

 private void initViewPagerScroll() {
  try {
   Field mField = ViewPager.class.getDeclaredField("mScroller");
   mField.setAccessible(true);
   BannerScroller scroller = new BannerScroller(getContext());
   mField.set(this, scroller);
  } catch (Exception e) {
   Log.d(TAG, e.getMessage());
  }
 }
public class BannerScroller extends Scroller {

 private static final int BANNER_DURATION = 1000;
 private int mDuration = BANNER_DURATION;

 public BannerScroller(Context context) {
  super(context);
 }

 @Override
 public void startScroll(int startX, int startY, int dx, int dy, int duration) {
  super.startScroll(startX, startY, dx, dy, mDuration);
 }
}

至此,我们的自动轮播控件,无论是性能上还是稳定性上都已经很不错了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Android实现图片文字轮播特效

    本文实例讲解了Android实现图片文字轮播特效的详细代码,分享给大家供大家参考,具体内容如下 图片轮播是类似知乎日报上的一个轮播效果,如下图. 好了直接进入正题,首先是出示一下效果: MainActivity: import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService;

  • Android自定义控件实现简单的轮播图控件

    最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码.于是自己封装了一下.本篇轮播图实现原理原文出处:循环广告位组件的实现,这里只是做了下封装成一个控件,不必每次重复写代码了. 效果图: 实现分析 轮播图的功能就是实现左右滑动的广告.图片信息展示,那我们就用ViewPager来实现,由于考虑到用户体验,我们还需要在下面加一个指示器来标示滑动到了第几张轮播图.指示器我们可以用一个线性布局来根据要展示的轮播图

  • Android自动播放Banner图片轮播效果

    先看一下效果图 支持本地图片以及网络图片or本地网络混合. 使用方式: <com.jalen.autobanner.BannerView android:id="@+id/banner" android:layout_width="match_parent" android:layout_height="230dip"> </com.jalen.autobanner.BannerView> 核心代码: int length

  • Android实现图片轮播效果的两种方法

    大家在使用APP的过程中,经常会看到上部banner图片轮播的效果,那么今天我们就一起来学习一下,android中图片轮询的几种实现方法: 第一种:使用动画的方法实现:(代码繁琐) 这种发放需要:两个动画效果,一个布局,一个主类来实现,不多说了,来看代码吧: public class IamgeTrActivity extends Activity { /** Called when the activity is first created. */ public ImageView image

  • Android实现图片轮播效果

    本文实例讲述了JaAndroid实现图片轮播效果代码,分享给大家供大家参考.具体如下: 运行效果截图如下: 具体代码如下: 首先看下一下布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_par

  • Android实现广告图片轮播效果

    本文实例介绍了Android广告轮播图效果实现方法,分享给大家供大家参考,具体内容如下 首先看下一下布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:

  • Android 使用ViewPager自动滚动循环轮播效果

    对Android 利用ViewPager实现图片可以左右循环滑动效果,感兴趣的朋友可以直接点击查看内容详情. 主要介绍如何实现ViewPager自动播放,循环滚动的效果及使用.顺便解决ViewPager嵌套(ViewPager inside ViewPager)影响触摸滑动及ViewPager滑动速度设置问题. 先给大家展示下效果图,喜欢的朋友可以下载源码: 1.实现 没有通过ScheduledExecutorService或Timer定期执行某个任务实现,而是简单的通过handler发送消息去

  • Android实现图片自动轮播并且支持手势左右无限滑动

    废话不多说了,先给大家上左右无限滑动的代码了. 1.左右无限滑动 public class MainActivity extends AppCompatActivity { private static ViewPager viewPager; private RadioGroup group; //图片资源,实际项目需要从网络获取 private int[] imageIds = {R.drawable.ym1, R.drawable.ym2, R.drawable.ym3, R.drawab

  • Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)

    前言:经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环.本以为单纯的ViewPager就可以实现这些功能.但是蛋疼的事情来了,ViewPager并不支持循环翻页.所以要实现循环还得需要自己去动手.自己在网上也找了些例子,本博文的Demo是结合自己找到的一些相关例子的基础上去改造,也希望对读者有用. Demo实现的效果图如下: Demo代码: 工程目录如下图: 废话不多说,上代码. 1.主Activity代码如下: package com.stevenhu.and

  • Android使用ViewPager加载图片和轮播视频

    作为Android基础组件之一,大家对viewpager已经很熟悉了,网上也有很多使用viewpager来加载图片的案例.但是像微信那样点击图片,可以轮播显示图片和视频的例子却没找到.正巧项目中有需求,可以就花时间写了下,现在给一下核心代码,希望对有此需求的同学们起一个抛砖引玉的作用.话不多说了,上代码: 以下是initData的代码 public void initData() { //把聊天界面的图片和视频找出来,并加到数组中,并在 //并根据传进来的position来找到视频或图片在数组中

随机推荐