SHARE
TWEET

Untitled

a guest Jul 18th, 2019 73 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top