iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 9
1
Software Development

Kotlin 30 天,通過每天一個小 demo 學習 Android 開發系列 第 9

Kotlin 開發第 9 天 ImageSlider (ViewPager)

ImagesSlider

今天通過 ViewPager 做一個類似 iOS 中的 UIScrollView 的功能。

Android 不像 iOS 有原生的 UIPageController,也就是提供有圓點的 Indicatorhttps://ithelp.ithome.com.tw/upload/images/20171212/20107329ydSXbqdaVM.png ,所以乾脆改成顯示文字了。

  • 通過滑動畫面可以切換圖片。
  • 換圖片的過程畫面底部的數字會切換,左邊的數字代表當前第幾張,右邊代表總共的圖片數。

ViewPager

這是一個容器類,需要 PagerAdapter 來提供數據,ViewPager 經常和 Fragment 一起使用。

這裡的 PagerAdapter 有點像是 iOS 開發中 UICollectionView 的 Delegate + Datasource。

我們將 Activity 上拿到的 data 交給 Adapter 處理,Adapter 在將 data 和 Fragment 綁定(比如呈現在 Fragment 的畫面上)

MainLayout 

在 activity_main.xml 中,上面放一個 ViewPager (id=pager),用來放多個 Fragment(呈現不同的圖片)
下面放一個用來顯示「當下第幾張圖/總共幾張圖」的 textView(id=pageCountTextView)

https://ithelp.ithome.com.tw/upload/images/20171212/20107329OD31velDzo.png

Fragment Slider

在 fragment_slider.xml 中,定義一個放一張圖片的 Fragment 之後放到 ViewPager 中使用。

其中 imageView 的 ID 就取名叫 ImageView
https://ithelp.ithome.com.tw/upload/images/20171212/201073291WcKy1mm97.png

MainActivity

我們先建立一個 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")
            }

        })

    }

}

PagerAdapter

四個需要複寫的方法:

  • isViewFromObject()
  • getCount()
  • instantiateItem()
  • destoryItem()
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。
可以在這方面多思考一下。


參考


上一篇
Kotlin 開發第 8 天 BottomNavigation ( Fragment + Intent)
下一篇
Kotlin 開發第 10 天 ProgressControl ( ProgressBar + Handler )
系列文
Kotlin 30 天,通過每天一個小 demo 學習 Android 開發30

尚未有邦友留言

立即登入留言