Skip to content

Migrate to ViewPager2 #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.viewpager2.widget.MarginPageTransformer
import com.google.android.play.core.review.ReviewManagerFactory
import com.jdamcd.sudoku.R
import com.jdamcd.sudoku.app.IntentFactory
Expand Down Expand Up @@ -77,15 +78,14 @@ class PuzzleChoiceActivity : BaseActivity(), PuzzleChoicePresenter.View {
}

private fun configurePager() {
val pagerAdapter = PuzzlePagerAdapter(supportFragmentManager, resources)
val pagerAdapter = PuzzlePagerAdapter(this)
val pager = binding.pager
pager.adapter = pagerAdapter
binding.indicator.setViewPager(pager)
pager.offscreenPageLimit = pagerAdapter.itemCount - 1
pager.currentItem = 1
pager.offscreenPageLimit = pagerAdapter.count - 1
pager.setPageMarginDrawable(R.drawable.divider_vertical)
pager.pageMargin = ViewUtil.dpToPx(resources, 5)
pager.addOnPageChangeListener(fabView)
pager.setPageTransformer(MarginPageTransformer(ViewUtil.dpToPx(resources, 5)))
pager.registerOnPageChangeCallback(fabView)
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package com.jdamcd.sudoku.browse

import android.content.res.Resources
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.jdamcd.sudoku.repository.Level

internal class PuzzlePagerAdapter(fm: FragmentManager, private val resources: Resources) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
internal class PuzzlePagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {

override fun getItem(position: Int) = PuzzleListFragment.create(levels[position])
override fun getItemCount() = levels.size

override fun getPageTitle(position: Int): String = resources.getString(levels[position].nameId)

override fun getCount() = levels.size
override fun createFragment(position: Int) = PuzzleListFragment.create(levels[position])

companion object {
val levels = arrayOf(Level.EASY, Level.MEDIUM, Level.HARD, Level.EXTREME)
Expand Down
8 changes: 2 additions & 6 deletions app/src/main/kotlin/com.jdamcd.sudoku/browse/RandomFabView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package com.jdamcd.sudoku.browse
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.content.res.ColorStateList
import androidx.viewpager.widget.ViewPager
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.jdamcd.sudoku.R

internal class RandomFabView : ViewPager.OnPageChangeListener {
internal class RandomFabView : ViewPager2.OnPageChangeCallback() {

private lateinit var fab: FloatingActionButton
private lateinit var fabColours: IntArray
Expand All @@ -22,10 +22,6 @@ internal class RandomFabView : ViewPager.OnPageChangeListener {
return fabColours[position % fabColours.size]
}

override fun onPageScrollStateChanged(state: Int) {}

override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}

override fun onPageSelected(position: Int) {
animateBackgroundChange(position)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package com.jdamcd.sudoku.browse.indicator

import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import androidx.viewpager2.widget.ViewPager2

interface PageIndicator : OnPageChangeListener {
interface PageIndicator {

fun setViewPager(view: ViewPager)
fun setViewPager(view: ViewPager2)

fun setViewPager(view: ViewPager, initialPosition: Int)
fun setViewPager(view: ViewPager2, initialPosition: Int)

fun setCurrentItem(item: Int)

fun setOnPageChangeListener(listener: OnPageChangeListener)
fun setOnPageChangeCallback(listener: ViewPager2.OnPageChangeCallback)

fun notifyDataSetChanged()
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,32 @@ import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.widget.TextViewCompat
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.jdamcd.sudoku.R
import com.jdamcd.sudoku.util.ViewUtil

class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: AttributeSet, defStyle: Int = 0) : HorizontalScrollView(context, attrs, defStyle), PageIndicator {

private val tabLayoutParams: LinearLayout.LayoutParams

private var pager: ViewPager? = null
private var listener: OnPageChangeListener? = null
private var pager: ViewPager2? = null
private var listener: OnPageChangeCallback? = null

private val tabsContainer: LinearLayout

private var tabCount: Int = 0
private lateinit var rectPaint: Paint
private var tabBackground: Int = 0
private var tabTextColour = -0x99999a
private val indicatorColours: IntArray
private var tabTextSize = 12
private var scrollOffset = 52
private var indicatorHeight = 8
private var tabPadding = 24

private val indicatorColours: IntArray
private val indicatorTitles: Array<String>

private var currentPosition = 0
private var currentPositionOffset = 0f
private var lastScrollX = 0
Expand All @@ -59,6 +61,7 @@ class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: Att
initSystemAttributes(context, attrs)

indicatorColours = resources.getIntArray(R.array.tab_colours)
indicatorTitles = resources.getStringArray(R.array.tab_titles)
tabLayoutParams = LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f)
}

Expand All @@ -85,17 +88,17 @@ class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: Att
a.recycle()
}

override fun setViewPager(view: ViewPager) {
override fun setViewPager(view: ViewPager2) {
if (pager === view) {
return
}
view.adapter ?: throw IllegalStateException("ViewPager does not have adapter instance.")
this.pager = view
view.addOnPageChangeListener(this)
view.registerOnPageChangeCallback(CallbackWrapper())
notifyDataSetChanged()
}

override fun setViewPager(view: ViewPager, initialPosition: Int) {
override fun setViewPager(view: ViewPager2, initialPosition: Int) {
setViewPager(view)
setCurrentItem(initialPosition)
}
Expand All @@ -105,17 +108,17 @@ class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: Att
requestLayout()
}

override fun setOnPageChangeListener(listener: OnPageChangeListener) {
override fun setOnPageChangeCallback(listener: OnPageChangeCallback) {
this.listener = listener
}

@SuppressLint("NewApi")
override fun notifyDataSetChanged() {
tabsContainer.removeAllViews()

tabCount = pager?.adapter!!.count
tabCount = pager?.adapter!!.itemCount
for (i in 0 until tabCount) {
addTextTab(i, pager?.adapter!!.getPageTitle(i).toString())
addTextTab(i)
}

updateTabStyles()
Expand All @@ -132,9 +135,9 @@ class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: Att
)
}

private fun addTextTab(position: Int, title: String) {
private fun addTextTab(position: Int) {
val tab = TextView(context)
tab.text = title
tab.text = indicatorTitles[position]
tab.gravity = Gravity.CENTER
TextViewCompat.setTextAppearance(tab, R.style.TabText)
tab.setOnClickListener { pager!!.currentItem = position }
Expand Down Expand Up @@ -218,32 +221,6 @@ class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: Att
return indicatorColours[position % indicatorColours.size]
}

override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
currentPosition = position
currentPositionOffset = positionOffset

if (currentPositionOffset == 1.0f) {
currentPosition++
currentPositionOffset = 0f
}

scrollToChild(position, (positionOffset * tabsContainer.getChildAt(position).width).toInt())
invalidate()

listener?.onPageScrolled(position, positionOffset, positionOffsetPixels)
}

override fun onPageScrollStateChanged(state: Int) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
scrollToChild(pager!!.currentItem, 0)
}
listener?.onPageScrollStateChanged(state)
}

override fun onPageSelected(position: Int) {
listener?.onPageSelected(position)
}

public override fun onRestoreInstanceState(state: Parcelable) {
val savedState = state as SavedState
super.onRestoreInstanceState(savedState.superState)
Expand All @@ -258,6 +235,34 @@ class PagerStripIndicator @JvmOverloads constructor(context: Context, attrs: Att
return savedState
}

private inner class CallbackWrapper : OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
currentPosition = position
currentPositionOffset = positionOffset

if (currentPositionOffset == 1.0f) {
currentPosition++
currentPositionOffset = 0f
}

scrollToChild(position, (positionOffset * tabsContainer.getChildAt(position).width).toInt())
invalidate()

listener?.onPageScrolled(position, positionOffset, positionOffsetPixels)
}

override fun onPageScrollStateChanged(state: Int) {
if (state == ViewPager2.SCROLL_STATE_IDLE) {
scrollToChild(pager!!.currentItem, 0)
}
listener?.onPageScrollStateChanged(state)
}

override fun onPageSelected(position: Int) {
listener?.onPageSelected(position)
}
}

private class SavedState : BaseSavedState {
var currentPosition: Int = 0

Expand Down
Binary file removed app/src/main/res/drawable-hdpi/divider_vertical.9.png
Binary file not shown.
Binary file removed app/src/main/res/drawable-mdpi/divider_vertical.9.png
Binary file not shown.
Binary file removed app/src/main/res/drawable-xhdpi/divider_vertical.9.png
Binary file not shown.
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_puzzle_choice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
style="@style/PagerIndicator" />
</com.google.android.material.appbar.AppBarLayout>

<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
style="@style/Match"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/values/array.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
<item>@color/extreme</item>
</integer-array>

<integer-array name="tab_titles">
<item>@string/level_easy</item>
<item>@string/level_medium</item>
<item>@string/level_hard</item>
<item>@string/level_extreme</item>
</integer-array>

<string-array name="complete_greetings">
<item>@string/puzzle_complete_1</item>
<item>@string/puzzle_complete_2</item>
Expand Down