當我們在使用ViewPager時,有時候會覺得滑到最後一個項目時,要重新返回第一項是很麻煩的事情。
除了使用ViewPager的setCurrentItem(0)方法,就只能手動滑到第一項。
如果項目數量一多就是件很可怕的事。
如果可以直接回第一項就好了...
沒問題!! 今天就來作一個無限Loop ViewPager!!
先上個架構 :
首先,我們先自訂一個ViewPager。
我們直覺就是直接宣告一個類別去繼承ViewPager
class RoomViewPager (context: Context) :ViewPager(context) { }
開心地編譯,先炸個半熟。
Caused by: java.lang.NoSuchMethodException: [class android.content.Context, interface android.util.AttributeSet]
Caused by: android.view.InflateException: Binary XML file line #9: Error inflating class com.example.room.RoomViewPager.RoomViewPager
這是因為當我們在繼承ViewPager時,裡面的constructor並沒有正確的定義,像這個例子就是缺少了AttributeSet這個參數。
那麼改成下列的方式編譯
class RoomViewPager (context: Context, attrs : AttributeSet) :ViewPager(context,attrs) { }
果然找到失散多年的親人,痛哭流涕,成功編譯。
上程式碼先
class RoomViewPager (context: Context, attrs : AttributeSet) :ViewPager(context,attrs) {
override fun setCurrentItem(item :Int, smoothScroll :Boolean) {
var mItem:Int=0
if (adapter!!.getCount() == 0) {
super.setCurrentItem(item, smoothScroll)
return
}
mItem = getOffsetAmount() + (item % adapter!!.count);
super.setCurrentItem(mItem, smoothScroll);
}
fun getOffsetAmount(): Int {
if (adapter!!.count == 0) {
return 0
}
if (adapter is RoomViewPagerAdapter) {
val adapter = adapter as RoomViewPagerAdapter?
return adapter!!.getRealCount() * 100
} else {
return 0
}
}
}
我們需要override setCurrentItem 函式,並指向一個假的數值。
這段程式碼的用意,是增加我們畫面上滑動的項目數量,實際上還是我們給定的項目數量在循環。
接著自訂一個ViewPagerAdapter 。
class RoomViewPagerAdapter( private val mListViews:List<View>) : PagerAdapter() {
override fun isViewFromObject(p0: View, p1: Any): Boolean {
return p0==p1
}
override fun getCount(): Int {
if (getRealCount() == 0) {
return 0
}
return Integer.MAX_VALUE;
}
fun getRealCount(): Int {
return mListViews.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val virtualPosition = position % getRealCount()
if (mListViews != null) {
var targetView=mListViews[virtualPosition]
container.addView(targetView)
return targetView
}
return super.instantiateItem(container, position)
}
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
val virtualPosition = position % getRealCount()
if (mListViews != null) {
val view = mListViews.get(virtualPosition)
container.removeView(view)
}
}
}
這邊我們需要覆寫4個方法
object
: Any)我們回傳了return p0==p1作為判斷物件是否為View
我們判斷當真實的列表項目的數量為0時,回傳0
不然回傳Integer.MAX_VALUE這個大值來實現無限的概念(其實還是有限值,但我想沒人這麼有耐心刷到這個數值..
public static final int MAX_VALUE = 0x7fffffff;
我們先把虛擬位置給還原成真實位置
val virtualPosition = position % getRealCount()
將View項目加到ViewGroup裡並回傳列表位置的VIEW項目。
object
: Any)裡一樣先把虛擬位置給還原成真實位置,然後從ViewGroup裡移除該項目.
我們完成了
那麼就完成剩下的部分吧
來設定activity_main.xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.room.RoomViewPager.RoomViewPager
android:layout_width="0dp"
android:layout_height="325dp" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" android:layout_marginRight="8dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginLeft="8dp"
android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintTop_toTopOf="parent"
android:id="@+id/roomViewpager"/>
</android.support.constraint.ConstraintLayout>
我們使用我們上次自訂的RoomViewPager,訂好ID後準備給MainActivity使用。
來實作MainActivity
class MainActivity : AppCompatActivity() {
var roomList = ArrayList<View>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initRoomView()
var roomAdapter=RoomViewPagerAdapter(roomList)
roomViewpager.adapter=roomAdapter
roomViewpager.setCurrentItem(Integer.MAX_VALUE/2)
}
private fun initRoomView() {
val mInflater : LayoutInflater= layoutInflater
val v1 = mInflater.inflate(R.layout.room_n, null)
val v2 = mInflater.inflate(R.layout.room_e, null)
val v3 = mInflater.inflate(R.layout.room_s, null)
val v4 = mInflater.inflate(R.layout.room_w, null)
roomList=arrayListOf(v1,v2,v3,v4)
}
}
怎麼建立room_n等4個layout就不提了。
我們在MainActivity先宣告一個var roomList = ArrayList<View>()
來存放layout項目。
然後,宣告一個var roomAdapter=RoomViewPagerAdapter(roomList)
傳入roomList並交給我們自訂好的roomViewpager元件接收。
那麼就可以來編譯執行了。
這時候我們的第一項往左可以繼續接到最後一項的畫面,反之最後一項往右也可以接到第一項的畫面,如此完成了我們的無限loop的功能。