Skip to content

Commit 74f3939

Browse files
author
Shinya Kumagai
authored
Merge pull request #14 from aeirola/custom-animations
Support custom animations
2 parents ef1a91c + e0e61e4 commit 74f3939

File tree

3 files changed

+62
-26
lines changed

3 files changed

+62
-26
lines changed

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ CustomTabs.openURL(url, {
9090
enableUrlBarHiding: true,
9191
showPageTitle: true,
9292
enableDefaultShare: true,
93+
// For value, specify only full qualifier or only resource name.
94+
// In the case of the resource name, the module complements the application package in java side.
95+
animations: {
96+
startEnter: 'com.github.droibit.android.reactnative.customtabs.example:anim/slide_in_bottom',
97+
startExit: 'com.github.droibit.android.reactnative.customtabs.example:anim/slide_out_bottom',
98+
endEnter: 'com.github.droibit.android.reactnative.customtabs.example:anim/slide_in_bottom',
99+
endExit: 'com.github.droibit.android.reactnative.customtabs.example:anim/slide_out_bottom',
100+
},
101+
// or
93102
animations: ANIMATIONS_SLIDE, // or ANIMATIONS_FADE
94103
headers: {
95104
'my-custom-header': 'my custom header value'
@@ -105,7 +114,7 @@ The option to support:
105114
|enableUrlBarHiding|boolean|undefined|Enables the url bar to hide as the user scrolls down on the page.|
106115
|showPageTitle|boolean|undefined|Sets whether the title should be shown in the custom tab.|
107116
|enableDefaultShare|boolean|undefined|Whether to add a default shared items of the menu.|
108-
|animations|number|undefined|Sets the exit and start animations. ANIMATIONS_FADE or ANIMATIONS_SLIDE.|
117+
|animations|Object|undefined|Sets the exit and start animations. ANIMATIONS_FADE, ANIMATIONS_SLIDE or custom object with string properties `startEnter`, `startExit`, `endEnter` and `endExit` each defining an Android animation resource ID to use for the animations, such as `com.github.droibit.android.reactnative.customtabs:anim/slide_in_right`.|
109118
|headers|Object|undefined|Sets any custom headers that should be used.|
110119

111120
`undefined` property is the default behavior of the Custom Tabs.

android/src/main/java/com/github/droibit/android/reactnative/customtabs/CustomTabsModule.java

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.facebook.react.common.annotations.VisibleForTesting;
2323

2424
import java.util.Map;
25+
import java.util.regex.Pattern;
2526

2627
import javax.annotation.Nullable;
2728

@@ -43,12 +44,6 @@ public class CustomTabsModule extends ReactContextBaseJavaModule {
4344
@VisibleForTesting
4445
/* package */ static final String KEY_HEADERS = "headers";
4546

46-
@VisibleForTesting
47-
/* package */ static final int ANIMATIONS_SLIDE = 0;
48-
49-
@VisibleForTesting
50-
/* package */ static final int ANIMATIONS_FADE = 1;
51-
5247
private static final Map<String, Object> CONSTANTS;
5348

5449
static {
@@ -63,6 +58,10 @@ public class CustomTabsModule extends ReactContextBaseJavaModule {
6358

6459
private static final String MODULE_NAME = "CustomTabsManager";
6560

61+
// Note: The full resource qualifier is "package:type/entry".
62+
// https://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)
63+
private static final Pattern animationIdentifierPattern = Pattern.compile("^.+:.+/");
64+
6665
public CustomTabsModule(ReactApplicationContext reactContext) {
6766
super(reactContext);
6867
}
@@ -148,15 +147,8 @@ public void openURL(String url, ReadableMap option, Promise promise) {
148147
// TODO: If it does not launch Chrome, animation is unnecessary?
149148

150149
if (option.hasKey(KEY_ANIMATIONS)) {
151-
final int animation = option.getInt(KEY_ANIMATIONS);
152-
switch (animation) {
153-
case ANIMATIONS_SLIDE:
154-
applySlideAnimation(context, builder);
155-
break;
156-
case ANIMATIONS_FADE:
157-
applyFadeAnimation(context, builder);
158-
break;
159-
}
150+
final ReadableMap animations = option.getMap(KEY_ANIMATIONS);
151+
applyAnimation(context, builder, animations);
160152
}
161153
CustomTabsIntent customTabsIntent = builder.build();
162154

@@ -194,14 +186,29 @@ public void openURL(String url, ReadableMap option, Promise promise) {
194186
}
195187

196188
@VisibleForTesting
197-
/* package */ void applySlideAnimation(Context context, CustomTabsIntent.Builder builder) {
198-
builder.setStartAnimations(context, R.anim.slide_in_right, R.anim.slide_out_left)
199-
.setExitAnimations(context, android.R.anim.slide_in_left, android.R.anim.slide_out_right);
189+
/* package */ void applyAnimation(Context context, CustomTabsIntent.Builder builder, ReadableMap animations) {
190+
final int startEnterAnimationId = animations.hasKey("startEnter")
191+
? resolveAnimationIdentifierIfNeed(context, animations.getString("startEnter"))
192+
: 0;
193+
final int startExitAnimationId = animations.hasKey("startExit")
194+
? resolveAnimationIdentifierIfNeed(context, animations.getString("startExit"))
195+
: 0;
196+
final int endEnterAnimationId = animations.hasKey("endEnter")
197+
? resolveAnimationIdentifierIfNeed(context, animations.getString("endEnter"))
198+
: 0;
199+
final int endExitAnimationId = animations.hasKey("endExit")
200+
? resolveAnimationIdentifierIfNeed(context, animations.getString("endExit"))
201+
: 0;
202+
builder.setStartAnimations(context, startEnterAnimationId, startExitAnimationId)
203+
.setExitAnimations(context, endEnterAnimationId, endExitAnimationId);
200204
}
201205

202-
@VisibleForTesting
203-
/* package */ void applyFadeAnimation(Context context, CustomTabsIntent.Builder builder) {
204-
builder.setStartAnimations(context, android.R.anim.fade_in, android.R.anim.fade_out)
205-
.setExitAnimations(context, android.R.anim.fade_out, android.R.anim.fade_in);
206+
// Complement the application name of the resource qualifier as necessary.
207+
private int resolveAnimationIdentifierIfNeed(Context context, String identifier) {
208+
if (animationIdentifierPattern.matcher(identifier).find()) {
209+
return context.getResources().getIdentifier(identifier, null, null);
210+
} else {
211+
return context.getResources().getIdentifier(identifier, "anim", context.getPackageName());
212+
}
206213
}
207214
}

src/TabOption.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,30 @@
77
* Start and exit animations of Custom Tabs.
88
* Slide in from left at start, Slide out to right.at exit.
99
*/
10-
export const ANIMATIONS_SLIDE:number = 0;
10+
export const ANIMATIONS_SLIDE: Animations = {
11+
startEnter: 'slide_in_right',
12+
startExit: 'slide_out_left',
13+
endEnter: 'android:anim/slide_in_left',
14+
endExit: 'android:anim/slide_out_right',
15+
};
1116

1217
/**
1318
* Start and exit animations of Custom Tabs.
1419
* Fade in at start, Fade out at exit.
1520
*/
16-
export const ANIMATIONS_FADE:number = 1;
21+
export const ANIMATIONS_FADE: Animations = {
22+
startEnter: 'android:anim/fade_in',
23+
startExit: 'android:anim/fade_out',
24+
endEnter: 'android:anim/fade_out',
25+
endExit: 'android:anim/fade_in',
26+
};
27+
28+
export type Animations = {
29+
startEnter: string,
30+
startExit: string,
31+
endEnter: string,
32+
endExit: string,
33+
}
1734

1835
/**
1936
* Options to customize Custom Tabs of look & feel.
@@ -46,10 +63,13 @@ export type TabOption = {
4663
/**
4764
* Sets the exit and start animations.
4865
*
66+
* Each property needs to be an Andrion animation resource ID,
67+
* e.g. 'com.github.droibit.android.reactnative.customtabs.example:anim/slide_out_bottom'
68+
*
4969
* @see ANIMATIONS_FADE
5070
* @see ANIMATIONS_SLIDE
5171
*/
52-
animations?: number;
72+
animations?: Animations;
5373

5474
/**
5575
* Sets any custom headers that should be used.

0 commit comments

Comments
 (0)