3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

Android + ViewPager2で特定のページ(ポジション)を最初に表示する

概要

ViewPager2を使ってカレンダーの実装をしていたのですが、みなさんもご存知だと思うのですがカレンダーは先の月だけではなく前の月もスクロールしたら見れますよね?
それを実装するためにはViewPagerで真ん中辺りのページを開く必要があったのでその方法を記載します。

試してだめだったこと

ViewPager2について調べてみると、currentItemなるものがあり、そちらが現在のItem(ページ)を示すみたいだったので、そこの値をかえればいいのでは?と思い

MainActivity.kt
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_main)

        val pager = ScreenSlidePagerAdapter(this)
        binding.pager.adapter = pager
        //ここで指定
        binding.pager.currentItem = 4
    }

    private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
        override fun getItemCount(): Int = Int.MAX_VALUE

        override fun createFragment(position: Int): Fragment = CalendarFragment(position)
    }

一旦このように実装してみたのですが、起動してみると一番最初のページスタートになってしまいました...

成功した例

そこで色々調べてみると、ただcurrentItemの値を返るだけではだめなようで、オプションも設定する必要があるとのこと。
https://stackoverflow.com/questions/56311862/viewpager2-default-position
ここの記事では時間を開けて処理を実行してるのですが、おそらくそれはする必要がなく

        binding.pager.setCurrentItem(4, false)

こんな感じで特定のページを指定してあげるだけで良さそう。

実行結果

スクリーンショット 2020-06-26 23.43.41.png

昨日の記事を読んでいた方にはわかると思うのですが、月を表示するようにしたところ10月スタートになりました。(ただこれでは困るので6月の状態で途中スタートにしたい)

(+α)月の表示調節

カレンダーはほぼ無限スクロールなので開始位置はIntのMAX_VALUEの半分スタートにします。

MainActivity.kt
binding.pager.setCurrentItem(Int.MAX_VALUE / 2, false)

そしてフラグメントの方で今月(6月)を真ん中に表示しつつ月のラベルを渡すには

CalendarFragment.kt
        val default = Int.MAX_VALUE / 2
        binding = FragmentCalendarBinding.inflate(inflater, container, false)
        inflater.inflate(R.layout.fragment_calendar, container, false)
        val calendar = Calendar.getInstance()
        val year = 2019
        val month = 6
        val minDay = 1
        calendar.set(year, month, 1)
        calendar.add(Calendar.MONTH, position - default)
        val maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
        val blankDays = calendar.get(Calendar.DAY_OF_WEEK)

        val dayArray: MutableList<String> = mutableListOf()
        for (i in minDay until blankDays) {
            dayArray.add("")
        }
        for (i in minDay..maxDay) {
            dayArray.add(i.toString())
        }
        binding.date = dayArray.toTypedArray()
        binding.monthData = (((month - 1 + (position - default)) % 12) + 1).toString() + "月"

        return binding.root

こんな感じに書けばよいかと。

最終的な実行結果

無限スクロール_.gif

左右にスクロールでき、ちゃんと月も正しい値になりました!!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
3
Help us understand the problem. What are the problem?