First, the realization of effect diagram

Second, the way of implementation

There are two main ways to do this:

The first is to use the getCount() method in the Adapter to return integer.max_value. Second, insert the last piece of data at the front of the list and the first at the end of the list to create the illusion of a loop.

Both methods have their pros and cons. The first one slides more smoothly, but requires at least 4 elements to use. Otherwise, you either get an error or you get a blank screen. The disadvantage of the second approach is that the first and last element switching may not work as well.

2.1 First implementation method: integer.max_value

    1. Simple layout
<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.viewpager.widget.ViewPager android:id="@+id/vp_vp_test_vp" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:id="@+id/ll_vp_test_indicator" android:layout_width="match_parent" android:layout_height="20dp" android:background="@color/blue_74D3FF" android:orientation="horizontal" android:gravity="center"/> </LinearLayout>Copy the code
    1. activity

In order to be able to slide to the left or to slide to the left, you can set the initial position in the middle, or you can set it to a larger number, and you don’t usually have to deal with the position when you slide to zero, but if you do, you can do that by listening to scroll, and at position = 0, you can set a new position. Similarly, when you swipe right to the last one, do the same thing.

class VpTestActivity : BaseActivity(R.layout.activity_vp_test) { override fun initData() { } override fun initEvent() { } override fun initInterface() { val dataList = arrayListOf<Fragment>() for (i in 0.. 3){ dataList.add(VpTestFg.newInstance(i)) } val adapter = VpTestAdapter(supportFragmentManager,dataList) Vp_vp_test_vp. adapter = Adapter // Set the initial position to a larger position vp_vp_test_vp.currentItem = dataList. Size * 1000 // Set the dot indicator ll_vp_test_indicator.removeAllViews() val dimen = resources.getDimensionPixelOffset(R.dimen.m10) for (i in 0.. 3){ val image = ImageView(this) image.setBackgroundResource(R.drawable.circle_white) ll_vp_test_indicator.addView(image) // Set interval val layoutParams: LinearLayout.LayoutParams = image.layoutParams as LinearLayout.LayoutParams layoutParams.setMargins(dimen,0,dimen,0) Image.layoutparams = layoutParams} // Set the first indicator to be red ll_vp_test_indicates.getChildat (0)? .setBackgroundResource(R.drawable.circle_red) vp_vp_test_vp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{ override fun onPageScrollStateChanged(state: Int) { } override fun onPageScrolled( position: Int, positionOffset: Float, positionOffsetPixels: Int ) { } override fun onPageSelected(position: Int) {// changeIndicator(position)}})} private fun changeIndicator(position: Int) { val size = ll_vp_test_indicator.childCount for (i in 0.. size){ ll_vp_test_indicator.getChildAt(i)? .setBackgroundResource(R.drawable.circle_white) } ll_vp_test_indicator.getChildAt(position%size)? .setBackgroundResource(R.drawable.circle_red) } override fun onReload() { } }Copy the code
    1. adapter

In this case getCount returns a large value so that you can slide for a long time without slipping to the head. In the getItem, do not do processing, the processing of position should be put in the instantiateItem, in the getItem will report an error.

class VpTestAdapter(fragmentManager: FragmentManager, val data: ArrayList<Fragment>) : FragmentPagerAdapter(fragmentManager) { override fun getItem(position: Int): Fragment = data[position] override fun getCount(): Int = Int.MAX_VALUE override fun instantiateItem(container: ViewGroup, position: Int): Any {// Handle position. Set array index to [0,fragmentList.size), Var position = position %= data.size return super.instantiateItem(container, position)}}Copy the code
    1. Dot indicator

Just two simple backgrounds, either an image or a drawable file. In this case, a simple file is used: the white circle:

<? The XML version = "1.0" encoding = "utf-8"? > <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@color/white"/> <size android:height="10dp" android:width="10dp"/> </shape>Copy the code

The red circle:

<? The XML version = "1.0" encoding = "utf-8"? > <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@color/red_FF8EB7"/> <size android:height="10dp" android:width="10dp"/> </shape>Copy the code
    1. Simple fragments

The layout is very simple, just a TextView in the middle.

class VpTestFg: Fragment() { companion object{ fun newInstance(type: Int): VpTestFg{ val bundle = Bundle() bundle.putInt("type",type) val fragment = VpTestFg() fragment.arguments = bundle return fragment } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup? , savedInstanceState: Bundle? ) : View? { return inflater.inflate(R.layout.fg_vp_test,container,false) } @SuppressLint("SetTextI18n") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val type = arguments? .getint ("type") tv_fg_vp_test_text.text = "this is fragment $type" tv_fg_VP_test_text. setOnClickListener {// enter another method startActivity(Intent(context,VpTestTwoActivity::class.java)) } } }Copy the code
    1. Realize automatic round casting
private val mDelayTime: Long = 3000 private val mHandler = @SuppressLint("HandlerLeak") object : Handler(){ override fun handleMessage(msg: Message) { super.handleMessage(msg) } } override fun run() { var currentItem = vp_vp_test_vp.currentItem currentItem ++ If (currentItem == vp_vp_test_vp.childCount - 1){// slide to the last currentItem = 0 vp_vp_test_vp.setCurrentItem(currentItem,false) mHandler.postDelayed(this,mDelayTime) }else{ vp_vp_test_vp.setCurrentItem(currentItem,true) mHandler.postDelayed(this,mDelayTime) } } override fun onResume() { super.onResume() mHandler.postDelayed(this,mDelayTime) } override fun onPause() { super.onPause() mHandler.removeCallbacks(this) }Copy the code
    1. When you scroll manually, the rotation is stopped
vp_vp_test_vp.setOnTouchListener { v, event ->
            when(event.action){
                MotionEvent.ACTION_DOWN -> {
                    LogUtils.e("action-down")
                    mHandler.removeCallbacks(this)
                }
                MotionEvent.ACTION_UP -> {
                    LogUtils.e("action-up")
                    mHandler.postDelayed(this,mDelayTime)
                }
                MotionEvent.ACTION_MOVE -> {
                    //LogUtils.e("action-move")
                    //mHandler.removeCallbacks(this)
                }
            }
             false
        }
Copy the code
    1. The complete activity is as follows:
class VpTestActivity : BaseActivity(R.layout.activity_vp_test), Runnable { private val mDelayTime: Long = 3000 private val mHandler = @SuppressLint("HandlerLeak") object : Handler(){ override fun handleMessage(msg: Message) { super.handleMessage(msg) } } override fun run() { var currentItem = vp_vp_test_vp.currentItem currentItem ++ If (currentItem == vp_vp_test_vp.childCount - 1){// slide to the last currentItem = 0 vp_vp_test_vp.setCurrentItem(currentItem,false) mHandler.postDelayed(this,mDelayTime) }else{ vp_vp_test_vp.setCurrentItem(currentItem,true) mHandler.postDelayed(this,mDelayTime) } } override fun onResume() { super.onResume() mHandler.postDelayed(this,mDelayTime) } override fun onPause() { super.onPause() mHandler.removeCallbacks(this) } override fun initData() { } override fun initEvent() { } @SuppressLint("ClickableViewAccessibility") override fun initInterface() { val dataList = arrayListOf<Fragment>() for (i  in 0.. 3){ dataList.add(VpTestFg.newInstance(i)) } val adapter = VpTestAdapter(supportFragmentManager,dataList) Vp_vp_test_vp. adapter = Adapter // Set the initial position to a larger position vp_vp_test_vp.currentItem = dataList. Size * 1000 // Set the dot indicator ll_vp_test_indicator.removeAllViews() val dimen = resources.getDimensionPixelOffset(R.dimen.m10) for (i in 0.. 3){ val image = ImageView(this) image.setBackgroundResource(R.drawable.circle_white) ll_vp_test_indicator.addView(image) // Set interval val layoutParams: LinearLayout.LayoutParams = image.layoutParams as LinearLayout.LayoutParams layoutParams.setMargins(dimen,0,dimen,0) Image.layoutparams = layoutParams} // Set the first indicator to be red ll_vp_test_indicates.getChildat (0)? .setBackgroundResource(R.drawable.circle_red) vp_vp_test_vp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{ override fun onPageScrollStateChanged(state: Int) { } override fun onPageScrolled( position: Int, positionOffset: Float, positionOffsetPixels: Int ) { } override fun onPageSelected(position: Var var var var var var var var var var var var var var var var var var var var var var var DepthPageTransformer()) vp_vp_test_vp.setOnTouchListener { v, event -> when(event.action){ MotionEvent.ACTION_DOWN -> { LogUtils.e("action-down") mHandler.removeCallbacks(this) } MotionEvent.ACTION_UP -> { LogUtils.e("action-up") mHandler.postDelayed(this,mDelayTime) } MotionEvent.ACTION_MOVE -> { //LogUtils.e("action-move") //mHandler.removeCallbacks(this) } } false } } private fun changeIndicator(position: Int) { val size = ll_vp_test_indicator.childCount for (i in 0.. size){ ll_vp_test_indicator.getChildAt(i)? .setBackgroundResource(R.drawable.circle_white) } ll_vp_test_indicator.getChildAt(position%size)? .setBackgroundResource(R.drawable.circle_red) } override fun onReload() { } }Copy the code

2.2 The second method

    1. The layout file is as above
    1. activity
class VpTestTwoActivity: BaseActivity(R.layout.activity_vp_test) { override fun initData() { } override fun initEvent() { } lateinit var dataList: ArrayList<Fragment> var mCurrent2 = 1 Override fun initInterface() {dataList = arrayListOf<Fragment>() Add (vptestfg.newinstance (3)) for (I in 0.. 3){ dataList.add(VpTestFg.newInstance(i)) } dataList.add(VpTestFg.newInstance(0)) val adapter = VpTestAdapter2(supportFragmentManager,dataList) vp_vp_test_vp.adapter = adapter vp_vp_test_vp.currentItem = mCurrent2 / / set the dot indicator ll_vp_test_indicator. RemoveAllViews () val dimen = resources. GetDimensionPixelOffset (R.d imen. M10) for (I in 0.. 3){ val image = ImageView(this) image.setBackgroundResource(R.drawable.circle_white) ll_vp_test_indicator.addView(image) // Set interval val layoutParams: LinearLayout.LayoutParams = image.layoutParams as LinearLayout.LayoutParams layoutParams.setMargins(dimen,0,dimen,0) Image.layoutparams = layoutParams} // Set the first indicator to be red ll_vp_test_indicates.getChildat (0)? .setBackgroundResource(R.drawable.circle_red) vp_vp_test_vp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{ override fun onPageScrollStateChanged(state: If (state == viewpager.scroll_state_idle){if (mCurrent2 == 0){ vp_vp_test_vp.setCurrentItem(dataList.size - 2, false); }else if (mCurrent2 == dataList.size -1){vp_vp_test_vp.setCurrentItem(1, false); }}} @suppressLint ("MissingSuperCall") Override fun onPageScrolled(Position: Int, positionOffset: Float, positionOffsetPixels: Int) {Float fun onPageSelected(position: Int) Float, positionOffsetPixels: Int) { Int) {mCurrent2 = position // changeIndicator(position)}} private fun changeIndicator(position: Int) { val size = ll_vp_test_indicator.childCount for (i in 0.. size){ ll_vp_test_indicator.getChildAt(i)? .setBackgroundResource(R.drawable.circle_white) } when (position) { 0 -> { ll_vp_test_indicator.getChildAt(size - 1)? .setBackgroundResource(R.drawable.circle_red) } dataList.size - 1 -> { ll_vp_test_indicator.getChildAt(0)? .setBackgroundResource(R.drawable.circle_red) } else -> { ll_vp_test_indicator.getChildAt(position - 1)? .setBackgroundResource(R.drawable.circle_red) } } } override fun onReload() { } }Copy the code
    1. adapter
class VpTestAdapter2(fragmentManager: FragmentManager, val data: ArrayList<Fragment>) :
    FragmentPagerAdapter(fragmentManager) {

    override fun getItem(position: Int): Fragment = data[position]

    override fun getCount(): Int = data.size
    
}
Copy the code
    1. Ditto for indicators and fragments
    1. Set up by

It’s similar to the way you set up a runnable, but it’s a little different.

 override fun run() {
        var currentItem = vp_vp_test_vp.currentItem
        currentItem ++
       vp_vp_test_vp.currentItem = currentItem
        mHandler.postDelayed(this,mDelayTime)
    }
Copy the code
    1. The complete activity is shown below
class VpTestTwoActivity: BaseActivity(R.layout.activity_vp_test) ,Runnable{ private val mDelayTime: Long = 3000 private val mHandler = @SuppressLint("HandlerLeak") object : Handler(){ override fun handleMessage(msg: Message) { super.handleMessage(msg) } } override fun run() { var currentItem = vp_vp_test_vp.currentItem currentItem ++ vp_vp_test_vp.currentItem = currentItem mHandler.postDelayed(this,mDelayTime) } override fun onResume() { super.onResume() mHandler.postDelayed(this,mDelayTime) } override fun onPause() { super.onPause() mHandler.removeCallbacks(this) } override fun initData() { } override fun initEvent() { } lateinit var dataList: ArrayList<Fragment> var mCurrent2 = 1 @SuppressLint("ClickableViewAccessibility") override fun initInterface() { DataList = arrayListOf<Fragment>() // Add the last Fragment to the first position, and add the first Fragment to the last position dataList. Add (vptestfg.newinstance (3)) for  (i in 0.. 3){ dataList.add(VpTestFg.newInstance(i)) } dataList.add(VpTestFg.newInstance(0)) val adapter = VpTestAdapter2(supportFragmentManager,dataList) vp_vp_test_vp.adapter = adapter vp_vp_test_vp.currentItem = mCurrent2 / / set the dot indicator ll_vp_test_indicator. RemoveAllViews () val dimen = resources. GetDimensionPixelOffset (R.d imen. M10) for (I in 0.. 3){ val image = ImageView(this) image.setBackgroundResource(R.drawable.circle_white) ll_vp_test_indicator.addView(image) // Set interval val layoutParams: LinearLayout.LayoutParams = image.layoutParams as LinearLayout.LayoutParams layoutParams.setMargins(dimen,0,dimen,0) Image.layoutparams = layoutParams} // Set the first indicator to be red ll_vp_test_indicates.getChildat (0)? .setBackgroundResource(R.drawable.circle_red) vp_vp_test_vp.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{ override fun onPageScrollStateChanged(state: If (state == viewpager.scroll_state_idle){if (mCurrent2 == 0){ vp_vp_test_vp.setCurrentItem(dataList.size - 2, false); }else if (mCurrent2 == dataList.size -1){vp_vp_test_vp.setCurrentItem(1, false); }}} @suppressLint ("MissingSuperCall") Override fun onPageScrolled(Position: Int, positionOffset: Float, positionOffsetPixels: Int) {Float fun onPageSelected(position: Int) Float, positionOffsetPixels: Int) { Int) {mCurrent2 = position // changeIndicator(position)}}) {v, event -> when(event.action){ MotionEvent.ACTION_DOWN -> { LogUtils.e("action-down") mHandler.removeCallbacks(this) } MotionEvent.ACTION_UP -> { LogUtils.e("action-up") mHandler.postDelayed(this,mDelayTime) } MotionEvent.ACTION_MOVE -> { //LogUtils.e("action-move") //mHandler.removeCallbacks(this) } } false } } private fun changeIndicator(position: Int) { val size = ll_vp_test_indicator.childCount for (i in 0.. size){ ll_vp_test_indicator.getChildAt(i)? .setBackgroundResource(R.drawable.circle_white) } when (position) { 0 -> { ll_vp_test_indicator.getChildAt(size - 1)? .setBackgroundResource(R.drawable.circle_red) } dataList.size - 1 -> { ll_vp_test_indicator.getChildAt(0)? .setBackgroundResource(R.drawable.circle_red) } else -> { ll_vp_test_indicator.getChildAt(position - 1)? .setBackgroundResource(R.drawable.circle_red) } } } override fun onReload() { } }Copy the code

Three, reference

ViewPager two ways to achieve infinite carousel ViewPager automatic carousel, hold down the finger to stop the carousel ViewPager combined with Fragment for infinite sliding ViewPager package carousel effect + indicator to achieve a line of code to show the carousel diagram