SoFunction
Updated on 2025-04-09

Android implements a silky automatic carousel control example code

Preface

Many apps now have automatic carousel banner interfaces, which are used to display advertising pictures or display some popular activities. In addition to having cool effects, it is also a great design point to reduce the use of the interface through carousel. This article mainly summarizes the implementation process of automatic carousel controls and some optimization techniques for such controls.

1. How to achieve it

Before starting our code programming, we need to think about whether there are similar controls in the official API provided by Google that implement similar functions. After all, most of the official controls have been tested by time, and they are very good in terms of stability and performance. If we can transform them accordingly based on the official controls, the stability of the control will be relatively guaranteed.

Among the more common mainstream controls, ViewPager and RecyclerView have actually implemented similar functions, especially ViewPager, which can be said to have implemented most of the functions of our control. Therefore, if we transform based on ViewPager, our carousel control can also be more stable.

So how much difference is there between ViewPager and the automatic carousel controls we need? There are two main ones:

  • Automatic playback is not supported
  • Can't slide from last to first

So we mainly transform these two parts accordingly to realize our own automatic carousel control.

1.1 Implement automatic carousel function

To implement the automatic carousel function, the first thing we think of is to implement the timer function through Timer or ScheduledExecutorService, and then let the ViewPager set the current Item to the data of the next position through the serCurrentItem(int position) method. However, if it is implemented through a timer, there will be a problem, that is, it is more troublesome when we need to stop the playback of the banner, so it is more reasonable to send events through the Handler to realize the automatic carousel of the ViewPager and the stop of some scenes.

Let's look at the code:

 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_CHANGE_SELECTION) {
  if (mBannerRef == null || () == null) {
   return;
  }
  AutoScrollViewPager banner = ();

  if ( == Integer.MAX_VALUE) {
   int rightPos =  % ();
   (() + rightPos + 1, true);
  } else {
   if (!hasMessages(MSG_CHANGE_SELECTION)) {
   ( + 1, true);
   sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
   }
  }

  }
 }
 }

As you can see, we first pass in the external ViewPager, and then prevent memory leakage through weak references. By calling the setCurrentItem() method in the handlerMessage() method, setting the current ViewPager's Item to the corresponding position + 1 data. Therefore, as long as we call the Handler's sendMessage() method externally, we can make the ViewPager perform automatic unlimited carousel.

1.2 Let ViewPager slide from the last picture to the first picture

We know that ViewPager cannot slide from the last page to the first page, but we can change our thinking. If we set the size of ViewPager to infinite size in the Adapter of ViewPager to infinite size through the getCount() method, and then use the remaining method to ensure that the sliding page always corresponds to the data source data, so that the ViewPager can achieve the effect of sliding from the last page to the first page.

 public int getCount() {
  if (mBannerList == null) {
   return 0;
  }
  if (() == 1) {
   return 1;
  } else {
   return Integer.MAX_VALUE;
  }
 }
 public Object instantiateItem(ViewGroup container, final int position) {
  if (mBannerList != null &amp;&amp; () &gt; 0) {
   View imageView = null;
   Uri uri = ((position % ()).cover_url); // By taking the rest   imageView = new SimpleDraweeView(mContext);
   ((SimpleDraweeView) imageView).setImageURI(uri);
   (imageView);
   return imageView;
  }
  return null;
 }

2. How to optimize

In the above, we simply implemented the automatic carousel function of ViewPager, but in fact there are still many details that we need to optimize. For example: we slide from the last to the first by setting the size of ViewPager to infinitely large. However, if we do not cache at this time, we need to return many new Views in the instantiateItem(ViewGroup container, final int position) method of Adapter, which will cause unnecessary memory waste. Only by optimizing these details can our control be more useful and have better stability and performance.

2.1 Reduce memory waste through cache

In order to enable ViewPager to implement wireless carousel function, we used the method of setting the size of getCount() to infinitely large, but this will create a problem, which will cause us to return many new Views in the instantiateItem() method of Adapter, causing unnecessary memory waste.

So we can use a List as the cache pool to store the abandoned object in the destroyItem() method in Adapter and reuse it, so that memory waste can be avoided.

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

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

Then in the instantiateItem() method of Adapter, the cached View is taken out from the List and reuse it

 public Object instantiateItem(ViewGroup container, final int position) {
  if (mBannerList != null &amp;&amp; () &gt; 0) {
   View imageView = null;
   Uri uri = ((position % ()).cover_url);
   if (()) {
    imageView = new SimpleDraweeView(());
   } else {
    // When there is data in the cache collection, reuse it    imageView = (ImageView) (0);
   }
 }

2.2 Stop automatic carousel appropriately

When we touch the Banner or leave the page where the Banner is currently displaying the Banner, if the banner is still performing wireless carousels, it will cause unnecessary performance losses. Therefore, we need to stop the Banner's carousel when the Banner and the current Activity are invisible to improve performance.

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

2.3 Change the ViewPager switching speed

When the native ViewPager is automatically carousel, the switching speed is particularly fast, which gives people a very abrupt feeling. Moreover, the ViewPager does not provide an interface to set the switching speed of the ViewPager, so we need to use Scroller to set the switching speed through reflection, so that our Banner is more silky.

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

 private void initViewPagerScroll() {
  try {
   Field mField = ("mScroller");
   (true);
   BannerScroller scroller = new BannerScroller(getContext());
   (this, scroller);
  } catch (Exception e) {
   (TAG, ());
  }
 }
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) {
  (startX, startY, dx, dy, mDuration);
 }
}

At this point, our automatic carousel controls are already very good in terms of performance and stability.

Summarize

The above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.