To achieve the silky effect of tiktok sliding up and down a small video, there needs to be a pre-loaded feature. The so-called preloading,

In the case that the current page is displayed, the content behind the current page should be loaded in advance to ensure that when the user slides to the next video,

Can reduce the wait time, under the normal network speed, you can do silky browsing.

A new feature was added in the fourth version of ViewPager2: setOffscreenPageLimit

setOffscreenPageLimit(int limit)

Parameters: Limit How many pages will be kept off-screen on either side. Valid values are >= 1 and default values are -1

Note: Set the number of pages that should remain on either side of the currently visible page. Pages that exceed this limit will be recreated from the adapter as needed. The value must be greater than 0 or the default value -1. Before and after the current page (limit number) page is added to the view hierarchy, even if it is not visible, exceeding the limit number will be removed from the view, but recycled like RecyclerView.

Through the method description, you can know that this feature is simply a magic tool to do this function, but can achieve the desired effect.

Let’s write a simple Demo to test the View life cycle when sliding, so that we can create it in the appropriate callback method. Destroy the player and pause/play the video.

Use:

Dependencies {implementation (" androidx viewpager2: viewpager2:1.0.0 ")}Copy the code

Adapter

inner class VPAdapter() : RecyclerView.Adapter<VPAdapter.BaseViewHolder? >() { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int): BaseViewHolder { val itemView: View = LayoutInflater.from(parent.context).inflate(R.layout.vp_item_layout, parent, false) return BaseViewHolder(itemView) } override fun onBindViewHolder( holder: BaseViewHolder, position: Int) { } override fun getItemCount(): Int { return dataArray.size } override fun onViewDetachedFromWindow(holder: BaseViewHolder) {super. OnViewDetachedFromWindow (holder) enter the d (" ViewPager2 ", "the View from the screen in the first page ${holder. AdapterPosition + 1}")} override fun onViewAttachedToWindow(holder: BaseViewHolder) {super. OnViewAttachedToWindow (holder) enter the d (" ViewPager2 ", "the View screen The first ${holder. AdapterPosition + 1} ")} inner class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var root: RelativeLayout? var image :TextView? init { root = itemView.findViewById(R.id.root) image = itemView.findViewById(R.id.iv_test) } } }Copy the code

Prepare 10 pieces of data, set offscreenPageLimit to 1, and the number of pages on the screen will always be 3. When the first page is expected, a second page will be created. When you slide to page 2, create page 3. When you slide to the third page, create the fourth page and delete the first page from the view by going onViewDetachedFromWindow. So let’s scroll down and look at the log.

Enter the page ViewPager2: View adds to the screen page 1 ViewPager2: View adds to the screen page 2 slide to the second page ViewPager2: View adds to the screen page 3 slide to the third page ViewPager2: View join screen page 4 ViewPager2: View off screen page 1 Slide to page 4 ViewPager2: View join screen page 5 ViewPager2: View off screen page 2 return to page 3 ViewPager2: ViewPager2: View off screen page 5Copy the code

As you can see, the log input is exactly what we expect, except after the first page, there will always be three pages on the view.

All we need to do is create the player in the corresponding callback, pause it, and destroy it. The following

In the View join window callback, create the player, start playing and then pause ⏸️ override Fun onViewAttachedToWindow(holder: BaseViewHolder) {super. OnViewAttachedToWindow (holder) enter the d (" ViewPager2 ", "the View screen The first page ${holder. AdapterPosition + 1} ") val  player =createArLivePlayer() dataArray[holder.adapterPosition].player=player player.startPlay("url") player.pause() }Copy the code
Override Fun onViewDetachedFromWindow(holder: BaseViewHolder) {super. OnViewDetachedFromWindow (holder) enter the d (" ViewPager2 ", "the View from the screen the first page ${holder. AdapterPosition + 1}") dataArray[holder.adapterPosition].player.release() }Copy the code

Pause the creation of the player so that the player can buffer the next page of video data, so we need to find a place to start playing the player of the currently displayed page.

Simply register the pager2 listener, play the player of the current page, and pause the other pages.

binding.vp.registerOnPageChangeCallback(object :ViewPager2.OnPageChangeCallback(){ override fun onPageSelected(position:  Int) { super.onPageSelected(position) dataArray.forEachIndexed { index, videoData -> if (index==position){ dataArray[index].player? .resumePlay() log.d ("ViewPager2"," current ${index} play ")}}else{dataArray[index].player? . Pause (Log). D (" ViewPager2 ", "current" ${index} suspended)}}}}})Copy the code

Run, found the effect is very smooth, as shown in the figure. So ViewPager2 is very suitable for similar scenarios