iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 13
1
Software Development

英國研究顯示,連續30天用Kotlin開發Android將有益於身心健康系列 第 13

Android Kotlin 實作 Day 9:ImageSlider(使用 ViewPager)

使用語言

  • Kotlin

使用元件

  • ImageView
  • TextView
  • ViewPager

Layout 配置

  • 一個主 layout 包含一個 ViewPager 及 TextView
  • 一個 ViewPager 子項目的 layout,裡面放一個 ImageView

Method


ViewPager

可以用來達到左右翻頁的效果

  • 類似於 RecyclerView 需要設置 Adapter
    ViewPager 也需要設置 PagerAdapter 來產出畫面

  • 若搭配 Fragment 使用,可設置 FragmentPagerAdapterFragmentStatePagerAdapter

  • 可透過 OnPageChangeListener 監聽換頁過程

這次實作使用的為最基本的 PagerAdapter
關於三種 Adapter 的差異可以參考 參考資料


PagerAdapter

負責處理 ViewPager 的頁面

class Adapter(val context: Context, val list: List<Int>) : PagerAdapter() {}

有四個必須 override 的 function

  • instantiateItem

    實例化 ViewPager 中相對應位置的頁面
    預設會實例化當前頁面及前後各一個頁面

    instantiateItem (container: ViewGroup, position: Int) : Object

    • container:ViewPager 用來放子項目 View 的容器,這個方法主要就是負責將子項目 View 加進這個 container 中。

    • position:要實例化的頁面位置

    • 回傳代表這個子項目 View 的 Object,可以為 View 或這個頁面的其他 container。

      這個回傳的 Object 會被 isViewFromObject 這個方法拿來做判斷使用,也會被用來做為 destroyItem 方法要移除的 View 的依據。

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val view = LayoutInflater.from(context).inflate(R.layout.imageview, container, false)
        Glide.with(context).load(list[position]).into(view.imageView)
        container.addView(view)   //將 View 加進 container 中
        return view
    }
    

    這裡用了 Glide 工具來載入圖避免 OOM

  • isViewFromObject

    PagerAdapter 需要此方法才能正常運作
    用來判斷頁面的 View 和上面 instantiateItem 方法回傳的物件是否一樣

    isViewFromObject (view: View, object: Object) : Boolean

    • view:ViewPager 源碼中呼叫此方法的 function 傳入的他們想判斷的 View

    • object:instantiateItem 回傳的 Object

    • 回傳一個 Boolean 值,告訴呼叫此方法的那些 function 他們想判斷的 view 和我們創建的 Object 是不是同一個

      ViewPager 源碼中有很多 function 會呼叫此方法,這些 function 需要利用判斷的結果做為依據來執行動作

    override fun isViewFromObject(v: View, any: Any): Boolean {
          return v == any
    }
    
  • getCount

    回傳 ViewPager 的子項目個數

    getCount() : Int

    override fun getCount(): Int {
        return list.size
    }
    
  • destroyItem

    當子項目 View 被滑出預備範圍內(當前及前後各一個頁面)時會被移除

    destroyItem (container: ViewGroup, position: Int, object: Object)

    • container:要被移除的子項目 View 的 container,這個方法主要就是負責將 View 從 container 中移除。

    • position:要移除子項目 View 的頁面位置

    • object:代表要移除的子項目 View 的 Object,為 instantiateItem 方法回傳的 Object。

    override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
        container.removeView(`object` as View)
    }
    

完成後將 PagerAdapter 指定給 ViewPager

// viewPager 為 Layout 中為 ViewPager 元件設置的 id
viewPager.adapter = Adapter(this, list)

OnPageChangeListener

用來監聽 ViewPager 頁面切換的監聽器,為一個 Interface。

val listener = object: ViewPager.OnPageChangeListener{}

此 Interface 中有三個 abstract function 需要實作

  • onPageScrollStateChanged

    頁面滑動狀態改變時觸發

    onPageScrollStateChanged (state: Int)

    • state:頁面滑動的狀態,有三種狀態:

      • SCROLL_STATE_IDLE:值為 0,為沒有任何動作,靜止的狀態

      • SCROLL_STATE_DRAGGING:值為 1,為拖曳中的狀態

      • SCROLL_STATE_SETTLING:值為 2,拖曳停止手指離開畫面時,頁面歸位至最後位置的過程狀態

      • 從觸碰並拖曳至手離開螢幕,狀態變化依序會為 1 > 2 > 0。

    override fun onPageScrollStateChanged(p0: Int) {}
    
  • onPageScrolled

    頁面滾動時觸發

    onPageScrolled (position: Int, positionOffset: Float, positionOffsetPixels: Int)

    • position:當前頁面(手指觸摸的頁面)的位置 Index

    • positionOffset:頁面滾動時,當前頁面偏移的百分比

    • positionOffsetPixels:頁面滾動時,當前頁面偏移的像素值

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
        val pageNow = position + 1
        textView.setText("$pageNow / ${list.size}")
    }
    
  • onPageSelected

    當新的頁面被選擇時觸發

    onPageSelected (position: Int)

    • position:新選擇的頁面的位置 Index
    override fun onPageSelected(p0: Int) {}
    

完成後將監聽器設置給 ViewPager

viewPager.addOnPageChangeListener(listener)

實作成果

查看詳細 Code > GitHub

tags: Android Kotlin ViewPager PagerAdapter OnPageChangeListener

上一篇
Android - Activity 啟動模式
下一篇
Android Kotlin 實作 Day 10:ProgressControl(上)(ProgressBar)
系列文
英國研究顯示,連續30天用Kotlin開發Android將有益於身心健康30

尚未有邦友留言

立即登入留言