15
15
*/
16
16
package com .google .android .material .motion ;
17
17
18
- import static androidx .annotation .RestrictTo .Scope .LIBRARY_GROUP ;
19
-
20
18
import android .animation .TimeInterpolator ;
21
19
import android .content .Context ;
22
20
import android .util .TypedValue ;
21
+ import android .view .animation .AnimationUtils ;
23
22
import androidx .annotation .AttrRes ;
24
23
import androidx .annotation .NonNull ;
25
- import androidx .annotation .RestrictTo ;
26
24
import androidx .core .graphics .PathParser ;
27
25
import androidx .core .view .animation .PathInterpolatorCompat ;
28
26
import com .google .android .material .resources .MaterialAttributes ;
29
27
30
- /**
31
- * A utility class for motion system functions.
32
- *
33
- * @hide
34
- */
35
- @ RestrictTo (LIBRARY_GROUP )
28
+ /** A utility class for motion system functions. */
36
29
public class MotionUtils {
37
30
38
31
// Constants corresponding to motionEasing* theme attr values.
@@ -43,61 +36,96 @@ public class MotionUtils {
43
36
44
37
private MotionUtils () {}
45
38
39
+ /**
40
+ * Resolve a duration from a material duration theme attribute.
41
+ *
42
+ * @param context the context from where the theme attribute will be resolved.
43
+ * @param attrResId the {@code motionDuration*} theme attribute to resolve
44
+ * @param defaultDuration the duration to be returned if unable to resolve {@code attrResId}
45
+ * @return the resolved {@code int} duration which {@code attrResId} points to or the {@code
46
+ * defaultDuration} if resolution was unsuccessful.
47
+ */
46
48
public static int resolveThemeDuration (
47
49
@ NonNull Context context , @ AttrRes int attrResId , int defaultDuration ) {
48
50
return MaterialAttributes .resolveInteger (context , attrResId , defaultDuration );
49
51
}
50
52
53
+ /**
54
+ * Load an interpolator from a material easing theme attribute.
55
+ *
56
+ * @param context context from where the theme attribute will be resolved
57
+ * @param attrResId the {@code motionEasing*} theme attribute to resolve
58
+ * @param defaultInterpolator the interpolator to be returned if unable to resolve {@code
59
+ * attrResId}.
60
+ * @return the resolved {@link TimeInterpolator} which {@code attrResId} points to or the {@code
61
+ * defaultInterpolator} if resolution was unsuccessful.
62
+ */
51
63
@ NonNull
52
64
public static TimeInterpolator resolveThemeInterpolator (
53
65
@ NonNull Context context ,
54
66
@ AttrRes int attrResId ,
55
67
@ NonNull TimeInterpolator defaultInterpolator ) {
56
68
TypedValue easingValue = new TypedValue ();
57
- if (context .getTheme ().resolveAttribute (attrResId , easingValue , true )) {
58
- if (easingValue .type != TypedValue .TYPE_STRING ) {
59
- throw new IllegalArgumentException ("Motion easing theme attribute must be a string" );
60
- }
69
+ if (!context .getTheme ().resolveAttribute (attrResId , easingValue , true )) {
70
+ return defaultInterpolator ;
71
+ }
61
72
62
- String easingString = String .valueOf (easingValue .string );
73
+ if (easingValue .type != TypedValue .TYPE_STRING ) {
74
+ throw new IllegalArgumentException (
75
+ "Motion easing theme attribute must be an @interpolator resource for"
76
+ + " ?attr/motionEasing*Interpolator attributes or a string for"
77
+ + " ?attr/motionEasing* attributes." );
78
+ }
63
79
64
- if (isEasingType (easingString , EASING_TYPE_CUBIC_BEZIER )) {
65
- String controlPointsString = getEasingContent (easingString , EASING_TYPE_CUBIC_BEZIER );
66
- String [] controlPoints = controlPointsString .split ("," );
67
- if (controlPoints .length != 4 ) {
68
- throw new IllegalArgumentException (
69
- "Motion easing theme attribute must have 4 control points if using bezier curve"
70
- + " format; instead got: "
71
- + controlPoints .length );
72
- }
80
+ String easingString = String .valueOf (easingValue .string );
81
+ if (isLegacyEasingAttribute (easingString )) {
82
+ return getLegacyThemeInterpolator (easingString );
83
+ }
84
+
85
+ return AnimationUtils .loadInterpolator (context , easingValue .resourceId );
86
+ }
73
87
74
- float controlX1 = getControlPoint (controlPoints , 0 );
75
- float controlY1 = getControlPoint (controlPoints , 1 );
76
- float controlX2 = getControlPoint (controlPoints , 2 );
77
- float controlY2 = getControlPoint (controlPoints , 3 );
78
- return PathInterpolatorCompat .create (controlX1 , controlY1 , controlX2 , controlY2 );
79
- } else if (isEasingType (easingString , EASING_TYPE_PATH )) {
80
- String path = getEasingContent (easingString , EASING_TYPE_PATH );
81
- return PathInterpolatorCompat .create (PathParser .createPathFromPathData (path ));
82
- } else {
83
- throw new IllegalArgumentException ("Invalid motion easing type: " + easingString );
88
+ private static TimeInterpolator getLegacyThemeInterpolator (String easingString ) {
89
+ if (isLegacyEasingType (easingString , EASING_TYPE_CUBIC_BEZIER )) {
90
+ String controlPointsString = getLegacyEasingContent (easingString , EASING_TYPE_CUBIC_BEZIER );
91
+ String [] controlPoints = controlPointsString .split ("," );
92
+ if (controlPoints .length != 4 ) {
93
+ throw new IllegalArgumentException (
94
+ "Motion easing theme attribute must have 4 control points if using bezier curve"
95
+ + " format; instead got: "
96
+ + controlPoints .length );
84
97
}
98
+
99
+ float controlX1 = getLegacyControlPoint (controlPoints , 0 );
100
+ float controlY1 = getLegacyControlPoint (controlPoints , 1 );
101
+ float controlX2 = getLegacyControlPoint (controlPoints , 2 );
102
+ float controlY2 = getLegacyControlPoint (controlPoints , 3 );
103
+ return PathInterpolatorCompat .create (controlX1 , controlY1 , controlX2 , controlY2 );
104
+ } else if (isLegacyEasingType (easingString , EASING_TYPE_PATH )) {
105
+ String path = getLegacyEasingContent (easingString , EASING_TYPE_PATH );
106
+ return PathInterpolatorCompat .create (PathParser .createPathFromPathData (path ));
107
+ } else {
108
+ throw new IllegalArgumentException ("Invalid motion easing type: " + easingString );
85
109
}
86
- return defaultInterpolator ;
87
110
}
88
111
89
- private static boolean isEasingType (String easingString , String easingType ) {
112
+ private static boolean isLegacyEasingAttribute (String easingString ) {
113
+ return isLegacyEasingType (easingString , EASING_TYPE_CUBIC_BEZIER )
114
+ || isLegacyEasingType (easingString , EASING_TYPE_PATH );
115
+ }
116
+
117
+ private static boolean isLegacyEasingType (String easingString , String easingType ) {
90
118
return easingString .startsWith (easingType + EASING_TYPE_FORMAT_START )
91
119
&& easingString .endsWith (EASING_TYPE_FORMAT_END );
92
120
}
93
121
94
- private static String getEasingContent (String easingString , String easingType ) {
122
+ private static String getLegacyEasingContent (String easingString , String easingType ) {
95
123
return easingString .substring (
96
124
easingType .length () + EASING_TYPE_FORMAT_START .length (),
97
125
easingString .length () - EASING_TYPE_FORMAT_END .length ());
98
126
}
99
127
100
- private static float getControlPoint (String [] controlPoints , int index ) {
128
+ private static float getLegacyControlPoint (String [] controlPoints , int index ) {
101
129
float controlPoint = Float .parseFloat (controlPoints [index ]);
102
130
if (controlPoint < 0 || controlPoint > 1 ) {
103
131
throw new IllegalArgumentException (
0 commit comments