今天通過 ViewPager 做一個類似 iOS 中的 UIScrollView 的功能。
Android 不像 iOS 有原生的 UIPageController,也就是提供有圓點的 Indicator ,所以乾脆改成顯示文字了。
這是一個容器類,需要 PagerAdapter 來提供數據,ViewPager 經常和 Fragment 一起使用。
這裡的 PagerAdapter 有點像是 iOS 開發中 UICollectionView 的 Delegate + Datasource。
我們將 Activity 上拿到的 data 交給 Adapter 處理,Adapter 在將 data 和 Fragment 綁定(比如呈現在 Fragment 的畫面上)
在 activity_main.xml 中,上面放一個 ViewPager (id=pager),用來放多個 Fragment(呈現不同的圖片)
下面放一個用來顯示「當下第幾張圖/總共幾張圖」的 textView(id=pageCountTextView)
在 fragment_slider.xml 中,定義一個放一張圖片的 Fragment 之後放到 ViewPager 中使用。
其中 imageView 的 ID 就取名叫 ImageView
我們先建立一個 IntArray 用來管理 images
(前面的動手做有提到, Android 的 Resource 都會有個對應的 Int,對 ImageView setImageResource 的時候是通過 Int)
我們實例化 adapter,並且加入一個 pageChangeListener 的監聽,當頁面切換的時候修改 畫面底部的數字。
class MainActivity : AppCompatActivity() {
lateinit var pager: ViewPager
val images: IntArray = intArrayOf(R.drawable.img_1, R.drawable.img_2, R.drawable.img_3, R.drawable.img_4, R.drawable.img_5, R.drawable.img_6)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupView()
}
private fun setupView() {
val adapter: PagerAdapter = SliderPagerAdapter(this, images)
pager = findViewById(R.id.pager)
pager.adapter = adapter
pager.addOnPageChangeListener(object: OnPageChangeListener{
override fun onPageScrollStateChanged(state: Int) {
println("on page scroll state changed $state")
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
val currentPosition = position + 1
pageCountTextView.text = "$currentPosition / ${images.size}"
}
override fun onPageSelected(position: Int) {
println("on page selected $position")
}
})
}
}
四個需要複寫的方法:
class SliderPagerAdapter : PagerAdapter {
val context: Context
val images: IntArray
lateinit var inflator: LayoutInflater
constructor(context: Context, images: IntArray) : super(){
this.context = context
this.images = images
}
override fun isViewFromObject(view: View?, `object`: Any?): Boolean {
return view == `object` as ConstraintLayout
}
override fun getCount(): Int {
return images.size
}
override fun instantiateItem(container: ViewGroup?, position: Int): Any {
inflator = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val rv: View = inflator.inflate(R.layout.fragment_slider, container,false)
rv.imageView.setImageResource(images[position])
container!!.addView(rv)
return rv
}
override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any?) {
container!!.removeView(`object` as ConstraintLayout)
}
}
問題:findViewByID 可以理解成類似 iOS 通過 XIB 來實例化介面的工具嗎?
問題:我在 Activity 建立了一份 images,而之後又將 images 丟給 PagerAdapter 這樣其實在記憶體上算兩份吧。
這不像 UIViewControllerDatasource 經常寫在 ViewController 上,共用一份 images。
可以在這方面多思考一下。