Browse Source

Support declaring interpolation per shared element transition (#6139)

* Implement startDelay + fix image scale transition

This commit adds support to the startDelay option in shared element transitions on Android. It also fixes image scale transition which only animated the image's scale type, but not its bounds.

* Support declaring interpolator per element transition
Guy Carmeli 4 years ago
parent
commit
e80eb9275a
No account linked to committer's email address
14 changed files with 200 additions and 31 deletions
  1. 12
    0
      lib/android/app/src/main/java/com/reactnativenavigation/parse/SharedElementTransitionOptions.java
  2. 20
    0
      lib/android/app/src/main/java/com/reactnativenavigation/utils/Animator.kt
  3. 2
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/SharedElementTransition.kt
  4. 15
    13
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/TransitionAnimatorCreator.kt
  5. 19
    5
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorAnimator.kt
  6. 32
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ClipBoundsAnimator.kt
  7. 42
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ClipBoundsEvaluator.kt
  8. 18
    7
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/MatrixAnimator.kt
  9. 8
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ScaleXAnimator.kt
  10. 8
    0
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ScaleYAnimator.kt
  11. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/TextChangeAnimator.kt
  12. 11
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/XAnimator.kt
  13. 11
    1
      lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/YAnimator.kt
  14. 0
    1
      playground/src/screens/sharedElementTransition/CocktailDetailsScreen.js

+ 12
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/SharedElementTransitionOptions.java View File

1
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
+import com.reactnativenavigation.parse.params.Interpolation;
3
 import com.reactnativenavigation.parse.params.NullNumber;
4
 import com.reactnativenavigation.parse.params.NullNumber;
4
 import com.reactnativenavigation.parse.params.NullText;
5
 import com.reactnativenavigation.parse.params.NullText;
5
 import com.reactnativenavigation.parse.params.Number;
6
 import com.reactnativenavigation.parse.params.Number;
6
 import com.reactnativenavigation.parse.params.Text;
7
 import com.reactnativenavigation.parse.params.Text;
8
+import com.reactnativenavigation.parse.parsers.InterpolationParser;
7
 import com.reactnativenavigation.parse.parsers.NumberParser;
9
 import com.reactnativenavigation.parse.parsers.NumberParser;
8
 import com.reactnativenavigation.parse.parsers.TextParser;
10
 import com.reactnativenavigation.parse.parsers.TextParser;
9
 
11
 
15
     public Text fromId = new NullText();
17
     public Text fromId = new NullText();
16
     public Text toId = new NullText();
18
     public Text toId = new NullText();
17
     public Number duration = new NullNumber();
19
     public Number duration = new NullNumber();
20
+    public Number startDelay = new NullNumber();
21
+    public Interpolation interpolation = Interpolation.NO_VALUE;
18
 
22
 
19
     public static SharedElementTransitionOptions parse(@Nullable JSONObject json) {
23
     public static SharedElementTransitionOptions parse(@Nullable JSONObject json) {
20
         SharedElementTransitionOptions transition = new SharedElementTransitionOptions();
24
         SharedElementTransitionOptions transition = new SharedElementTransitionOptions();
23
         transition.fromId = TextParser.parse(json, "fromId");
27
         transition.fromId = TextParser.parse(json, "fromId");
24
         transition.toId = TextParser.parse(json, "toId");
28
         transition.toId = TextParser.parse(json, "toId");
25
         transition.duration = NumberParser.parse(json, "duration");
29
         transition.duration = NumberParser.parse(json, "duration");
30
+        transition.startDelay = NumberParser.parse(json, "startDelay");
31
+        transition.interpolation = InterpolationParser.parse(json, "interpolation");
26
 
32
 
27
         return transition;
33
         return transition;
28
     }
34
     }
31
         if (other.fromId.hasValue()) fromId = other.fromId;
37
         if (other.fromId.hasValue()) fromId = other.fromId;
32
         if (other.toId.hasValue()) toId = other.toId;
38
         if (other.toId.hasValue()) toId = other.toId;
33
         if (other.duration.hasValue()) duration = other.duration;
39
         if (other.duration.hasValue()) duration = other.duration;
40
+        if (other.startDelay.hasValue()) startDelay = other.startDelay;
34
     }
41
     }
35
 
42
 
36
     void mergeWithDefault(SharedElementTransitionOptions defaultOptions) {
43
     void mergeWithDefault(SharedElementTransitionOptions defaultOptions) {
37
         if (!fromId.hasValue()) fromId = defaultOptions.fromId;
44
         if (!fromId.hasValue()) fromId = defaultOptions.fromId;
38
         if (!toId.hasValue()) toId = defaultOptions.toId;
45
         if (!toId.hasValue()) toId = defaultOptions.toId;
39
         if (!duration.hasValue()) duration = defaultOptions.duration;
46
         if (!duration.hasValue()) duration = defaultOptions.duration;
47
+        if (!startDelay.hasValue()) startDelay = defaultOptions.startDelay;
40
     }
48
     }
41
 
49
 
42
     public long getDuration() {
50
     public long getDuration() {
43
         return duration.get(0).longValue();
51
         return duration.get(0).longValue();
44
     }
52
     }
53
+
54
+    public long getStartDelay() {
55
+        return startDelay.get(0).longValue();
56
+    }
45
 }
57
 }

+ 20
- 0
lib/android/app/src/main/java/com/reactnativenavigation/utils/Animator.kt View File

1
+package com.reactnativenavigation.utils
2
+
3
+import android.animation.Animator
4
+import android.animation.TimeInterpolator
5
+import android.view.animation.Interpolator
6
+
7
+fun Animator.withStartDelay(delay: Long): Animator {
8
+    startDelay = delay
9
+    return this
10
+}
11
+
12
+fun Animator.withDuration(duration: Long): Animator {
13
+    this.duration = duration
14
+    return this
15
+}
16
+
17
+fun Animator.withInterpolator(interpolator: TimeInterpolator): Animator {
18
+    this.interpolator = interpolator
19
+    return this
20
+}

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/element/SharedElementTransition.kt View File

30
 
30
 
31
     private fun animators(): List<PropertyAnimatorCreator<*>> {
31
     private fun animators(): List<PropertyAnimatorCreator<*>> {
32
         return listOf(
32
         return listOf(
33
+                MatrixAnimator(from, to),
34
+                ClipBoundsAnimator(from, to),
33
                 XAnimator(from, to),
35
                 XAnimator(from, to),
34
                 YAnimator(from, to),
36
                 YAnimator(from, to),
35
-                MatrixAnimator(from, to),
36
                 ScaleXAnimator(from, to),
37
                 ScaleXAnimator(from, to),
37
                 ScaleYAnimator(from, to),
38
                 ScaleYAnimator(from, to),
38
                 BackgroundColorAnimator(from, to),
39
                 BackgroundColorAnimator(from, to),

+ 15
- 13
lib/android/app/src/main/java/com/reactnativenavigation/views/element/TransitionAnimatorCreator.kt View File

9
 import androidx.core.animation.doOnCancel
9
 import androidx.core.animation.doOnCancel
10
 import androidx.core.animation.doOnEnd
10
 import androidx.core.animation.doOnEnd
11
 import com.facebook.react.uimanager.ViewGroupManager
11
 import com.facebook.react.uimanager.ViewGroupManager
12
+import com.facebook.react.views.image.ReactImageView
12
 import com.reactnativenavigation.R
13
 import com.reactnativenavigation.R
13
 import com.reactnativenavigation.parse.AnimationOptions
14
 import com.reactnativenavigation.parse.AnimationOptions
14
 import com.reactnativenavigation.utils.ViewTags
15
 import com.reactnativenavigation.utils.ViewTags
51
     private fun reparentViews(transitions: TransitionSet) {
52
     private fun reparentViews(transitions: TransitionSet) {
52
         transitions.transitions
53
         transitions.transitions
53
                 .sortedBy { ViewGroupManager.getViewZIndex(it.view) }
54
                 .sortedBy { ViewGroupManager.getViewZIndex(it.view) }
54
-                .forEach {
55
-                    reparent(it)
56
-                }
55
+                .forEach { reparent(it) }
57
     }
56
     }
58
 
57
 
59
     private fun createSharedElementTransitionAnimators(transitions: List<SharedElementTransition>): List<AnimatorSet> {
58
     private fun createSharedElementTransitionAnimators(transitions: List<SharedElementTransition>): List<AnimatorSet> {
65
     }
64
     }
66
 
65
 
67
     private fun createSharedElementAnimator(transition: SharedElementTransition): AnimatorSet {
66
     private fun createSharedElementAnimator(transition: SharedElementTransition): AnimatorSet {
68
-        val set = AnimatorSet()
69
-        set.playTogether(transition.createAnimators())
70
-        set.addListener(object : AnimatorListenerAdapter() {
71
-            override fun onAnimationStart(animation: Animator) {
72
-                transition.from.alpha = 0f
73
-            }
74
-        })
75
-        return set
67
+        return transition
68
+                .createAnimators()
69
+                .apply {
70
+                    addListener(object : AnimatorListenerAdapter() {
71
+                        override fun onAnimationStart(animation: Animator) {
72
+                            transition.from.alpha = 0f
73
+                        }
74
+                    })
75
+                }
76
     }
76
     }
77
 
77
 
78
     private fun createElementTransitionAnimators(transitions: List<ElementTransition>): List<AnimatorSet> {
78
     private fun createElementTransitionAnimators(transitions: List<ElementTransition>): List<AnimatorSet> {
116
             lp.topMargin = loc.y + viewController.topInset
116
             lp.topMargin = loc.y + viewController.topInset
117
             lp.topMargin = loc.y
117
             lp.topMargin = loc.y
118
             lp.leftMargin = loc.x
118
             lp.leftMargin = loc.x
119
-            lp.width = view.width
120
-            lp.height = view.height
119
+            if (view !is ReactImageView) {
120
+                lp.width = view.width
121
+                lp.height = view.height
122
+            }
121
             view.layoutParams = lp
123
             view.layoutParams = lp
122
             transition.viewController.requireParentController().addOverlay(view)
124
             transition.viewController.requireParentController().addOverlay(view)
123
         }
125
         }

+ 19
- 5
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/BackgroundColorAnimator.kt View File

1
 package com.reactnativenavigation.views.element.animators
1
 package com.reactnativenavigation.views.element.animators
2
 
2
 
3
 import android.animation.Animator
3
 import android.animation.Animator
4
+import android.animation.AnimatorListenerAdapter
4
 import android.animation.ObjectAnimator
5
 import android.animation.ObjectAnimator
5
 import android.view.View
6
 import android.view.View
6
 import android.view.ViewGroup
7
 import android.view.ViewGroup
8
+import androidx.core.animation.addListener
9
+import androidx.core.animation.doOnStart
7
 import com.facebook.react.views.text.ReactTextView
10
 import com.facebook.react.views.text.ReactTextView
8
 import com.facebook.react.views.view.ReactViewBackgroundDrawable
11
 import com.facebook.react.views.view.ReactViewBackgroundDrawable
9
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
12
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
10
 import com.reactnativenavigation.utils.ColorUtils
13
 import com.reactnativenavigation.utils.ColorUtils
11
 import com.reactnativenavigation.utils.ViewUtils
14
 import com.reactnativenavigation.utils.ViewUtils
15
+import com.reactnativenavigation.utils.withInterpolator
16
+import com.reactnativenavigation.utils.withStartDelay
12
 
17
 
13
 class BackgroundColorAnimator(from: View, to: View) : PropertyAnimatorCreator<ViewGroup>(from, to) {
18
 class BackgroundColorAnimator(from: View, to: View) : PropertyAnimatorCreator<ViewGroup>(from, to) {
14
     override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean {
19
     override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean {
19
     override fun excludedViews() = listOf(ReactTextView::class.java)
24
     override fun excludedViews() = listOf(ReactTextView::class.java)
20
 
25
 
21
     override fun create(options: SharedElementTransitionOptions): Animator {
26
     override fun create(options: SharedElementTransitionOptions): Animator {
22
-        return ObjectAnimator.ofObject(
23
-                BackgroundColorEvaluator(to.background as ReactViewBackgroundDrawable),
24
-                ColorUtils.colorToLAB(ViewUtils.getBackgroundColor(from)),
25
-                ColorUtils.colorToLAB(ViewUtils.getBackgroundColor(to))
26
-        ).setDuration(options.getDuration())
27
+        val backgroundColorEvaluator = BackgroundColorEvaluator(to.background as ReactViewBackgroundDrawable)
28
+        val fromColor = ColorUtils.colorToLAB(ViewUtils.getBackgroundColor(from))
29
+        val toColor = ColorUtils.colorToLAB(ViewUtils.getBackgroundColor(to))
30
+
31
+        backgroundColorEvaluator.evaluate(0f, fromColor, toColor)
32
+        return ObjectAnimator
33
+                .ofObject(
34
+                        backgroundColorEvaluator,
35
+                        fromColor,
36
+                        toColor
37
+                )
38
+                .setDuration(options.getDuration())
39
+                .withStartDelay(options.getStartDelay())
40
+                .withInterpolator(options.interpolation.interpolator)
27
     }
41
     }
28
 }
42
 }

+ 32
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ClipBoundsAnimator.kt View File

1
+package com.reactnativenavigation.views.element.animators
2
+
3
+import android.animation.Animator
4
+import android.animation.ObjectAnimator
5
+import android.graphics.Rect
6
+import android.view.View
7
+import com.facebook.react.views.image.ReactImageView
8
+import com.reactnativenavigation.parse.SharedElementTransitionOptions
9
+import com.reactnativenavigation.utils.ViewUtils
10
+import com.reactnativenavigation.utils.withDuration
11
+import com.reactnativenavigation.utils.withInterpolator
12
+import com.reactnativenavigation.utils.withStartDelay
13
+
14
+class ClipBoundsAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactImageView>(from, to) {
15
+    override fun shouldAnimateProperty(fromChild: ReactImageView, toChild: ReactImageView): Boolean {
16
+        return !ViewUtils.areDimensionsEqual(from, to)
17
+    }
18
+
19
+    override fun create(options: SharedElementTransitionOptions): Animator {
20
+        val startDrawingRect = Rect(); from.getDrawingRect(startDrawingRect)
21
+        val endDrawingRect = Rect(); to.getDrawingRect(endDrawingRect)
22
+        return ObjectAnimator.ofObject(
23
+                ClipBoundsEvaluator(),
24
+                startDrawingRect,
25
+                endDrawingRect
26
+        )
27
+                .setDuration(options.getDuration())
28
+                .withStartDelay(options.getStartDelay())
29
+                .withInterpolator(options.interpolation.interpolator)
30
+    }
31
+
32
+}

+ 42
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ClipBoundsEvaluator.kt View File

1
+package com.reactnativenavigation.views.element.animators
2
+
3
+import android.animation.TypeEvaluator
4
+import android.graphics.Rect
5
+
6
+class ClipBoundsEvaluator : TypeEvaluator<Rect> {
7
+    private var fromWidth = 0
8
+    private var fromHeight = 0
9
+    private var toWidth = 0
10
+    private var toHeight = 0
11
+    private val result = Rect()
12
+
13
+    override fun evaluate(ratio: Float, from: Rect, to: Rect): Rect {
14
+        sync(from, to)
15
+        if (toHeight == fromHeight) {
16
+            result.bottom = toHeight
17
+        } else {
18
+            if (toHeight > fromHeight) {
19
+                result.bottom = (toHeight - (toHeight - fromHeight) * (1 - ratio)).toInt()
20
+            } else {
21
+                result.bottom = (toHeight + (fromHeight - toHeight) * (1 - ratio)).toInt()
22
+            }
23
+        }
24
+        if (toWidth == fromWidth) {
25
+            result.right = toWidth
26
+        } else {
27
+            if (toWidth > fromWidth) {
28
+                result.right = (toWidth - (toWidth - fromWidth) * (1 - ratio)).toInt()
29
+            } else {
30
+                result.right = (toWidth + (fromWidth - toWidth) * (1 - ratio)).toInt()
31
+            }
32
+        }
33
+        return result
34
+    }
35
+
36
+    private fun sync(from: Rect, to: Rect) {
37
+        fromWidth = from.right
38
+        fromHeight = from.bottom
39
+        toWidth = to.right
40
+        toHeight = to.bottom
41
+    }
42
+}

+ 18
- 7
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/MatrixAnimator.kt View File

1
 package com.reactnativenavigation.views.element.animators
1
 package com.reactnativenavigation.views.element.animators
2
 
2
 
3
 import android.animation.Animator
3
 import android.animation.Animator
4
+import android.animation.AnimatorListenerAdapter
4
 import android.animation.ObjectAnimator
5
 import android.animation.ObjectAnimator
5
 import android.animation.TypeEvaluator
6
 import android.animation.TypeEvaluator
6
 import android.graphics.Rect
7
 import android.graphics.Rect
7
 import android.view.View
8
 import android.view.View
9
+import androidx.core.animation.addListener
10
+import androidx.core.animation.doOnStart
8
 import com.facebook.drawee.drawable.ScalingUtils.InterpolatingScaleType
11
 import com.facebook.drawee.drawable.ScalingUtils.InterpolatingScaleType
9
 import com.facebook.react.views.image.ReactImageView
12
 import com.facebook.react.views.image.ReactImageView
10
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
13
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
11
 import com.reactnativenavigation.utils.ViewUtils
14
 import com.reactnativenavigation.utils.ViewUtils
15
+import com.reactnativenavigation.utils.withDuration
16
+import com.reactnativenavigation.utils.withInterpolator
17
+import com.reactnativenavigation.utils.withStartDelay
12
 
18
 
13
 class MatrixAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactImageView>(from, to) {
19
 class MatrixAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactImageView>(from, to) {
14
     override fun shouldAnimateProperty(fromChild: ReactImageView, toChild: ReactImageView): Boolean {
20
     override fun shouldAnimateProperty(fromChild: ReactImageView, toChild: ReactImageView): Boolean {
23
                     calculateBounds(from),
29
                     calculateBounds(from),
24
                     calculateBounds(to)
30
                     calculateBounds(to)
25
             )
31
             )
26
-            return ObjectAnimator.ofObject(TypeEvaluator<Float> { fraction: Float, _: Any, _: Any ->
27
-                hierarchy.actualImageScaleType?.let {
28
-                    (hierarchy.actualImageScaleType as InterpolatingScaleType?)!!.value = fraction
29
-                    to.invalidate()
30
-                }
31
-                null
32
-            }, 0, 1).setDuration(options.getDuration())
32
+
33
+            return ObjectAnimator
34
+                    .ofObject(TypeEvaluator<Float> { fraction: Float, _: Any, _: Any ->
35
+                        hierarchy.actualImageScaleType?.let {
36
+                            (hierarchy.actualImageScaleType as InterpolatingScaleType?)!!.value = fraction
37
+                            to.invalidate()
38
+                        }
39
+                        null
40
+                    }, 0, 1)
41
+                    .setDuration(options.getDuration())
42
+                    .withStartDelay(options.getStartDelay())
43
+                    .withInterpolator(options.interpolation.interpolator)
33
         }
44
         }
34
     }
45
     }
35
 
46
 

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ScaleXAnimator.kt View File

4
 import android.animation.ObjectAnimator
4
 import android.animation.ObjectAnimator
5
 import android.view.View
5
 import android.view.View
6
 import android.view.ViewGroup
6
 import android.view.ViewGroup
7
+import androidx.core.animation.addListener
8
+import androidx.core.animation.doOnStart
7
 import com.facebook.react.views.text.ReactTextView
9
 import com.facebook.react.views.text.ReactTextView
8
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
10
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
11
+import com.reactnativenavigation.utils.withDuration
12
+import com.reactnativenavigation.utils.withInterpolator
13
+import com.reactnativenavigation.utils.withStartDelay
9
 
14
 
10
 class ScaleXAnimator(from: View, to: View) : PropertyAnimatorCreator<ViewGroup>(from, to) {
15
 class ScaleXAnimator(from: View, to: View) : PropertyAnimatorCreator<ViewGroup>(from, to) {
11
     override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean {
16
     override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean {
15
     override fun excludedViews(): List<Class<*>> = listOf<Class<*>>(ReactTextView::class.java)
20
     override fun excludedViews(): List<Class<*>> = listOf<Class<*>>(ReactTextView::class.java)
16
 
21
 
17
     override fun create(options: SharedElementTransitionOptions): Animator {
22
     override fun create(options: SharedElementTransitionOptions): Animator {
23
+        to.scaleX = from.width.toFloat() / to.width
18
         return ObjectAnimator
24
         return ObjectAnimator
19
                 .ofFloat(to, View.SCALE_X, from.width.toFloat() / to.width, 1f)
25
                 .ofFloat(to, View.SCALE_X, from.width.toFloat() / to.width, 1f)
20
                 .setDuration(options.getDuration())
26
                 .setDuration(options.getDuration())
27
+                .withStartDelay(options.getStartDelay())
28
+                .withInterpolator(options.interpolation.interpolator)
21
     }
29
     }
22
 }
30
 }

+ 8
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ScaleYAnimator.kt View File

4
 import android.animation.ObjectAnimator
4
 import android.animation.ObjectAnimator
5
 import android.view.View
5
 import android.view.View
6
 import android.view.ViewGroup
6
 import android.view.ViewGroup
7
+import androidx.core.animation.addListener
8
+import androidx.core.animation.doOnStart
7
 import com.facebook.react.views.text.ReactTextView
9
 import com.facebook.react.views.text.ReactTextView
8
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
10
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
11
+import com.reactnativenavigation.utils.withDuration
12
+import com.reactnativenavigation.utils.withInterpolator
13
+import com.reactnativenavigation.utils.withStartDelay
9
 
14
 
10
 class ScaleYAnimator(from: View, to: View) : PropertyAnimatorCreator<ViewGroup>(from, to) {
15
 class ScaleYAnimator(from: View, to: View) : PropertyAnimatorCreator<ViewGroup>(from, to) {
11
     override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean {
16
     override fun shouldAnimateProperty(fromChild: ViewGroup, toChild: ViewGroup): Boolean {
15
     override fun excludedViews() = listOf(ReactTextView::class.java)
20
     override fun excludedViews() = listOf(ReactTextView::class.java)
16
 
21
 
17
     override fun create(options: SharedElementTransitionOptions): Animator {
22
     override fun create(options: SharedElementTransitionOptions): Animator {
23
+        to.scaleY = from.height.toFloat() / to.height
18
         return ObjectAnimator
24
         return ObjectAnimator
19
                 .ofFloat(to, View.SCALE_Y, from.height.toFloat() / to.height, 1f)
25
                 .ofFloat(to, View.SCALE_Y, from.height.toFloat() / to.height, 1f)
20
                 .setDuration(options.getDuration())
26
                 .setDuration(options.getDuration())
27
+                .withStartDelay(options.getStartDelay())
28
+                .withInterpolator(options.interpolation.interpolator)
21
     }
29
     }
22
 }
30
 }

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/TextChangeAnimator.kt View File

7
 import android.widget.TextView
7
 import android.widget.TextView
8
 import com.facebook.react.views.text.ReactTextView
8
 import com.facebook.react.views.text.ReactTextView
9
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
9
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
10
-import com.reactnativenavigation.utils.TextViewUtils
11
-import com.reactnativenavigation.utils.ViewUtils
10
+import com.reactnativenavigation.utils.*
12
 import com.shazam.android.widget.text.reflow.ReflowTextAnimatorHelper
11
 import com.shazam.android.widget.text.reflow.ReflowTextAnimatorHelper
13
 
12
 
14
 class TextChangeAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactTextView>(from, to) {
13
 class TextChangeAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactTextView>(from, to) {
39
                 }
38
                 }
40
                 .buildAnimator()
39
                 .buildAnimator()
41
                 .setDuration(options.getDuration())
40
                 .setDuration(options.getDuration())
41
+                .withInterpolator(options.interpolation.interpolator)
42
     }
42
     }
43
 }
43
 }

+ 11
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/XAnimator.kt View File

1
 package com.reactnativenavigation.views.element.animators
1
 package com.reactnativenavigation.views.element.animators
2
 
2
 
3
 import android.animation.Animator
3
 import android.animation.Animator
4
+import android.animation.AnimatorListenerAdapter
4
 import android.animation.ObjectAnimator
5
 import android.animation.ObjectAnimator
5
 import android.view.View
6
 import android.view.View
6
 import android.view.View.TRANSLATION_X
7
 import android.view.View.TRANSLATION_X
8
+import androidx.core.animation.addListener
9
+import androidx.core.animation.doOnStart
7
 import com.facebook.react.views.text.ReactTextView
10
 import com.facebook.react.views.text.ReactTextView
8
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
11
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
9
 import com.reactnativenavigation.utils.ViewUtils
12
 import com.reactnativenavigation.utils.ViewUtils
13
+import com.reactnativenavigation.utils.withInterpolator
14
+import com.reactnativenavigation.utils.withStartDelay
10
 
15
 
11
 class XAnimator(from: View, to: View) : PropertyAnimatorCreator<View>(from, to) {
16
 class XAnimator(from: View, to: View) : PropertyAnimatorCreator<View>(from, to) {
12
     private val dx: Int
17
     private val dx: Int
23
     override fun shouldAnimateProperty(fromChild: View, toChild: View) = dx != 0
28
     override fun shouldAnimateProperty(fromChild: View, toChild: View) = dx != 0
24
 
29
 
25
     override fun create(options: SharedElementTransitionOptions): Animator {
30
     override fun create(options: SharedElementTransitionOptions): Animator {
26
-        return ObjectAnimator.ofFloat(to, TRANSLATION_X, dx.toFloat(), 0f).setDuration(options.getDuration())
31
+        to.translationX = dx.toFloat()
32
+        return ObjectAnimator
33
+                .ofFloat(to, TRANSLATION_X, dx.toFloat(), 0f)
34
+                .setDuration(options.getDuration())
35
+                .withStartDelay(options.getStartDelay())
36
+                .withInterpolator(options.interpolation.interpolator)
27
     }
37
     }
28
 }
38
 }

+ 11
- 1
lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/YAnimator.kt View File

1
 package com.reactnativenavigation.views.element.animators
1
 package com.reactnativenavigation.views.element.animators
2
 
2
 
3
 import android.animation.Animator
3
 import android.animation.Animator
4
+import android.animation.AnimatorListenerAdapter
4
 import android.animation.ObjectAnimator
5
 import android.animation.ObjectAnimator
5
 import android.view.View
6
 import android.view.View
6
 import android.view.View.TRANSLATION_Y
7
 import android.view.View.TRANSLATION_Y
7
 import android.view.ViewGroup
8
 import android.view.ViewGroup
9
+import androidx.core.animation.addListener
10
+import androidx.core.animation.doOnStart
8
 import com.facebook.react.views.text.ReactTextView
11
 import com.facebook.react.views.text.ReactTextView
9
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
12
 import com.reactnativenavigation.parse.SharedElementTransitionOptions
10
 import com.reactnativenavigation.utils.ViewUtils
13
 import com.reactnativenavigation.utils.ViewUtils
14
+import com.reactnativenavigation.utils.withInterpolator
15
+import com.reactnativenavigation.utils.withStartDelay
11
 
16
 
12
 class YAnimator(from: View, to: View) : PropertyAnimatorCreator<View>(from, to) {
17
 class YAnimator(from: View, to: View) : PropertyAnimatorCreator<View>(from, to) {
13
     private val dy: Int
18
     private val dy: Int
24
     override fun excludedViews() = listOf(ReactTextView::class.java)
29
     override fun excludedViews() = listOf(ReactTextView::class.java)
25
 
30
 
26
     override fun create(options: SharedElementTransitionOptions): Animator {
31
     override fun create(options: SharedElementTransitionOptions): Animator {
27
-        return ObjectAnimator.ofFloat(to, TRANSLATION_Y, dy.toFloat(), 0f).setDuration(options.getDuration())
32
+        to.translationY = dy.toFloat()
33
+        return ObjectAnimator
34
+                .ofFloat(to, TRANSLATION_Y, dy.toFloat(), 0f)
35
+                .setDuration(options.getDuration())
36
+                .withStartDelay(options.getStartDelay())
37
+                .withInterpolator(options.interpolation.interpolator)
28
     }
38
     }
29
 }
39
 }

+ 0
- 1
playground/src/screens/sharedElementTransition/CocktailDetailsScreen.js View File

45
 module.exports = CocktailDetailsScreen;
45
 module.exports = CocktailDetailsScreen;
46
 const SIZE = 120;
46
 const SIZE = 120;
47
 const HEADER = 150;
47
 const HEADER = 150;
48
-const IMAGE_OFFSET = 52
49
 const styles = StyleSheet.create({
48
 const styles = StyleSheet.create({
50
   root: {
49
   root: {
51
     marginTop: 0
50
     marginTop: 0