Advertisement
Guest User

Untitled

a guest
Jul 18th, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.73 KB | None | 0 0
  1. package one.xcorp.widget
  2.  
  3. import android.animation.ValueAnimator
  4. import android.content.Context
  5. import android.util.AttributeSet
  6. import android.view.View
  7. import android.view.ViewGroup.LayoutParams.MATCH_PARENT
  8. import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
  9. import one.xcorp.widget.R
  10. import kotlin.properties.Delegates.observable
  11.  
  12. class ViewPager : android.support.v4.view.ViewPager {
  13.  
  14. var enableAnimation by observable(false) { _, _, enable ->
  15. if (enable) {
  16. addOnPageChangeListener(onPageChangeListener)
  17. } else {
  18. removeOnPageChangeListener(onPageChangeListener)
  19. }
  20. }
  21.  
  22. private var animationDuration = 0L
  23. private var animator: ValueAnimator? = null
  24.  
  25. constructor (context: Context) : super(context) {
  26. init(context, null)
  27. }
  28.  
  29. constructor (context: Context, attrs: AttributeSet?) : super(context, attrs) {
  30. init(context, attrs)
  31. }
  32.  
  33. private fun init(context: Context, attrs: AttributeSet?) {
  34. context.theme.obtainStyledAttributes(
  35. attrs,
  36. R.styleable.ViewPager,
  37. 0,
  38. 0
  39. ).apply {
  40. try {
  41. enableAnimation = getBoolean(
  42. R.styleable.ViewPager_enableAnimation,
  43. enableAnimation
  44. )
  45. animationDuration = getInteger(
  46. R.styleable.ViewPager_animationDuration,
  47. resources.getInteger(android.R.integer.config_shortAnimTime)
  48. ).toLong()
  49. } finally {
  50. recycle()
  51. }
  52. }
  53. }
  54.  
  55. override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
  56. val heightMode = MeasureSpec.getMode(heightMeasureSpec)
  57.  
  58. val measuredHeight = if (heightMode == MeasureSpec.EXACTLY) {
  59. MeasureSpec.getSize(heightMeasureSpec)
  60. } else {
  61. val currentViewHeight = findViewByPosition(currentItem)?.also {
  62. measureView(it)
  63. }?.measuredHeight ?: 0
  64.  
  65. if (heightMode != MeasureSpec.AT_MOST) {
  66. currentViewHeight
  67. } else {
  68. Math.min(
  69. currentViewHeight,
  70. MeasureSpec.getSize(heightMeasureSpec)
  71. )
  72. }
  73. }
  74.  
  75. super.onMeasure(
  76. widthMeasureSpec,
  77. MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY)
  78. )
  79. }
  80.  
  81. private fun measureView(view: View) = with(view) {
  82. val horizontalMode: Int
  83. val horizontalSize: Int
  84. when (layoutParams.width) {
  85. MATCH_PARENT -> {
  86. horizontalMode = MeasureSpec.EXACTLY
  87. horizontalSize = this@ViewPager.measuredWidth
  88. }
  89. WRAP_CONTENT -> {
  90. horizontalMode = MeasureSpec.UNSPECIFIED
  91. horizontalSize = 0
  92. }
  93. else -> {
  94. horizontalMode = MeasureSpec.EXACTLY
  95. horizontalSize = layoutParams.width
  96. }
  97. }
  98.  
  99. val verticalMode: Int
  100. val verticalSize: Int
  101. when (layoutParams.height) {
  102. MATCH_PARENT -> {
  103. verticalMode = MeasureSpec.EXACTLY
  104. verticalSize = this@ViewPager.measuredHeight
  105. }
  106. WRAP_CONTENT -> {
  107. verticalMode = MeasureSpec.UNSPECIFIED
  108. verticalSize = 0
  109. }
  110. else -> {
  111. verticalMode = MeasureSpec.EXACTLY
  112. verticalSize = layoutParams.height
  113. }
  114. }
  115.  
  116. val horizontalMeasureSpec = MeasureSpec.makeMeasureSpec(horizontalSize, horizontalMode)
  117. val verticalMeasureSpec = MeasureSpec.makeMeasureSpec(verticalSize, verticalMode)
  118.  
  119. measure(horizontalMeasureSpec, verticalMeasureSpec)
  120. }
  121.  
  122. private fun findViewByPosition(position: Int): View? {
  123. for (i in 0 until childCount) {
  124. val childView = getChildAt(i)
  125. val childLayoutParams = childView.layoutParams as LayoutParams
  126.  
  127. val childPosition by lazy {
  128. val field = childLayoutParams.javaClass.getDeclaredField("position")
  129. field.isAccessible = true
  130. field.get(childLayoutParams) as Int
  131. }
  132.  
  133. if (!childLayoutParams.isDecor && position == childPosition) {
  134. return childView
  135. }
  136. }
  137.  
  138. return null
  139. }
  140.  
  141. private fun animateContentHeight(childView: View, fromHeight: Int, toHeight: Int) {
  142. animator?.cancel()
  143.  
  144. if (fromHeight == toHeight) {
  145. return
  146. }
  147.  
  148. animator = ValueAnimator.ofInt(fromHeight, toHeight).apply {
  149. addUpdateListener {
  150. measureView(childView)
  151. if (childView.measuredHeight != toHeight) {
  152. animateContentHeight(childView, height, childView.measuredHeight)
  153. } else {
  154. layoutParams.height = animatedValue as Int
  155. requestLayout()
  156. }
  157. }
  158. duration = animationDuration
  159. start()
  160. }
  161. }
  162.  
  163. private val onPageChangeListener = object : OnPageChangeListener {
  164.  
  165. override fun onPageScrollStateChanged(state: Int) {
  166. /* do nothing */
  167. }
  168.  
  169. override fun onPageScrolled(
  170. position: Int,
  171. positionOffset: Float,
  172. positionOffsetPixels: Int
  173. ) {
  174. /* do nothing */
  175. }
  176.  
  177. override fun onPageSelected(position: Int) {
  178. if (!isAttachedToWindow) {
  179. return
  180. }
  181.  
  182. findViewByPosition(position)?.let { childView ->
  183. measureView(childView)
  184. animateContentHeight(childView, height, childView.measuredHeight)
  185. }
  186. }
  187. }
  188. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement