react-native-kenburns-view 5.0.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +19 -5
  3. package/example/kenburns-example/App.js +5 -5
  4. package/example/kenburns-example/README.md +5 -17
  5. package/example/kenburns-example/app.json +4 -4
  6. package/example/kenburns-example/ios/KenBurnsExample/AppDelegate.swift +69 -0
  7. package/example/kenburns-example/ios/KenBurnsExample/Info.plist +73 -71
  8. package/example/kenburns-example/ios/KenBurnsExample/KenBurnsExample-Bridging-Header.h +1 -1
  9. package/example/kenburns-example/ios/KenBurnsExample/PrivacyInfo.xcprivacy +11 -0
  10. package/example/kenburns-example/ios/KenBurnsExample/SplashScreen.storyboard +7 -2
  11. package/example/kenburns-example/ios/KenBurnsExample.xcodeproj/project.pbxproj +114 -106
  12. package/example/kenburns-example/ios/Podfile +14 -17
  13. package/example/kenburns-example/ios/Podfile.lock +1058 -691
  14. package/example/kenburns-example/ios/Podfile.properties.json +1 -2
  15. package/example/kenburns-example/metro.config.js +4 -1
  16. package/example/kenburns-example/package-lock.json +1256 -5067
  17. package/example/kenburns-example/package.json +12 -8
  18. package/lib/KenBurnsView.js +57 -35
  19. package/package.json +1 -1
  20. package/example/kenburns-example/assets/images/image1.jpg +0 -0
  21. package/example/kenburns-example/assets/images/image2.jpg +0 -0
  22. package/example/kenburns-example/assets/images/image3.jpg +0 -0
  23. package/example/kenburns-example/assets/images/placeholder.jpg +0 -0
  24. package/example/kenburns-example/ios/KenBurnsExample/AppDelegate.h +0 -7
  25. package/example/kenburns-example/ios/KenBurnsExample/AppDelegate.mm +0 -62
  26. package/example/kenburns-example/ios/KenBurnsExample/main.m +0 -10
  27. package/example/kenburns-example/ios/KenBurnsExample/noop-file.swift +0 -4
@@ -2,18 +2,22 @@
2
2
  "name": "kenburns-example",
3
3
  "version": "1.0.0",
4
4
  "private": true,
5
+ "main": "expo/AppEntry.js",
5
6
  "scripts": {
6
7
  "start": "expo start",
7
- "android": "expo run:android",
8
- "ios": "expo run:ios"
8
+ "android": "expo start --android",
9
+ "ios": "expo start --ios",
10
+ "web": "expo start --web"
9
11
  },
10
12
  "dependencies": {
11
- "expo": "~52.0.0",
12
- "expo-asset": "~11.0.1",
13
- "expo-status-bar": "~2.0.0",
14
- "react": "18.3.1",
15
- "react-native": "0.76.5",
16
- "react-native-kenburns-view": "file:../.."
13
+ "expo": "~55.0.4",
14
+ "expo-asset": "~55.0.8",
15
+ "expo-status-bar": "~55.0.4",
16
+ "react": "19.2.0",
17
+ "react-native": "0.83.2",
18
+ "react-native-kenburns-view": "file:../..",
19
+ "prop-types": "^15.8.1",
20
+ "babel-preset-expo": "~55.0.10"
17
21
  },
18
22
  "devDependencies": {
19
23
  "@babel/core": "^7.25.2"
@@ -13,6 +13,7 @@ import React, {
13
13
  useEffect,
14
14
  useImperativeHandle,
15
15
  useRef,
16
+ useState,
16
17
  } from 'react';
17
18
  import PropTypes from 'prop-types';
18
19
  import {
@@ -26,6 +27,17 @@ import {
26
27
  const DEFAULT_DURATION = 20000;
27
28
  const FILL_SCALE = 1.15;
28
29
 
30
+ function getRandomCycle(zoomStart, zoomEnd, panXAmount, panYAmount) {
31
+ return {
32
+ scaleFrom: zoomStart + Math.random() * (zoomEnd - zoomStart),
33
+ scaleTo: zoomStart + Math.random() * (zoomEnd - zoomStart),
34
+ txFrom: -panXAmount + Math.random() * 2 * panXAmount,
35
+ txTo: -panXAmount + Math.random() * 2 * panXAmount,
36
+ tyFrom: -panYAmount + Math.random() * 2 * panYAmount,
37
+ tyTo: -panYAmount + Math.random() * 2 * panYAmount,
38
+ };
39
+ }
40
+
29
41
  const KenBurnsView = forwardRef((props, ref) => {
30
42
  const {
31
43
  imageWidth,
@@ -43,14 +55,24 @@ const KenBurnsView = forwardRef((props, ref) => {
43
55
  ...rest
44
56
  } = props;
45
57
 
58
+ const w = imageWidth || 0;
59
+ const h = imageHeight || 0;
60
+ const panXAmount = w * panX;
61
+ const panYAmount = h * panY;
62
+
46
63
  const progress = useRef(new Animated.Value(0)).current;
47
64
  const animationRef = useRef(null);
65
+ const configRef = useRef({ zoomStart, zoomEnd, panXAmount, panYAmount });
66
+ configRef.current = { zoomStart, zoomEnd, panXAmount, panYAmount };
67
+
68
+ const [cycle, setCycle] = useState(() =>
69
+ getRandomCycle(zoomStart, zoomEnd, panXAmount, panYAmount),
70
+ );
71
+ const cycleRef = useRef(cycle);
72
+ cycleRef.current = cycle;
48
73
 
49
74
  const randomRef = useRef({
50
- phase: Math.random(),
51
75
  durationFactor: 0.7 + Math.random() * 0.6,
52
- panXSign: Math.random() > 0.5 ? 1 : -1,
53
- panYSign: Math.random() > 0.5 ? 1 : -1,
54
76
  }).current;
55
77
 
56
78
  const stop = useCallback(() => {
@@ -60,32 +82,37 @@ const KenBurnsView = forwardRef((props, ref) => {
60
82
  }
61
83
  }, []);
62
84
 
63
- const start = useCallback(() => {
64
- stop();
65
- progress.setValue(randomRef.phase);
66
-
85
+ const runNextCycle = useCallback(() => {
86
+ const { zoomStart: zs, zoomEnd: ze, panXAmount: pxa, panYAmount: pya } =
87
+ configRef.current;
88
+ const prev = cycleRef.current;
89
+ const nextTo = getRandomCycle(zs, ze, pxa, pya);
90
+ setCycle({
91
+ scaleFrom: prev.scaleTo,
92
+ scaleTo: nextTo.scaleTo,
93
+ txFrom: prev.txTo,
94
+ txTo: nextTo.txTo,
95
+ tyFrom: prev.tyTo,
96
+ tyTo: nextTo.tyTo,
97
+ });
98
+ progress.setValue(0);
67
99
  const d = Math.round(duration * randomRef.durationFactor);
100
+ animationRef.current = Animated.timing(progress, {
101
+ toValue: 1,
102
+ duration: d,
103
+ easing: Easing.inOut(Easing.quad),
104
+ useNativeDriver: true,
105
+ });
106
+ animationRef.current.start(({ finished }) => {
107
+ if (finished) runNextCycle();
108
+ });
109
+ }, [duration, progress, randomRef.durationFactor]);
68
110
 
69
- animationRef.current = Animated.loop(
70
- Animated.sequence([
71
- Animated.timing(progress, {
72
- toValue: 1,
73
- duration: d,
74
- easing: Easing.inOut(Easing.quad),
75
- useNativeDriver: true,
76
- }),
77
- Animated.timing(progress, {
78
- toValue: 0,
79
- duration: d,
80
- easing: Easing.inOut(Easing.quad),
81
- useNativeDriver: true,
82
- }),
83
- ]),
84
- {resetBeforeIteration: false},
85
- );
86
-
87
- animationRef.current.start();
88
- }, [duration, progress, stop, randomRef]);
111
+ const start = useCallback(() => {
112
+ stop();
113
+ progress.setValue(0);
114
+ runNextCycle();
115
+ }, [progress, runNextCycle, stop]);
89
116
 
90
117
  useImperativeHandle(
91
118
  ref,
@@ -110,24 +137,19 @@ const KenBurnsView = forwardRef((props, ref) => {
110
137
  };
111
138
  }, [autoStart, start, stop]);
112
139
 
113
- const w = imageWidth || 0;
114
- const h = imageHeight || 0;
115
- const panXAmount = w * panX * randomRef.panXSign;
116
- const panYAmount = h * panY * randomRef.panYSign;
117
-
118
140
  const translateX = progress.interpolate({
119
141
  inputRange: [0, 1],
120
- outputRange: [-panXAmount, panXAmount],
142
+ outputRange: [cycle.txFrom, cycle.txTo],
121
143
  });
122
144
 
123
145
  const translateY = progress.interpolate({
124
146
  inputRange: [0, 1],
125
- outputRange: [-panYAmount, panYAmount],
147
+ outputRange: [cycle.tyFrom, cycle.tyTo],
126
148
  });
127
149
 
128
150
  const scale = progress.interpolate({
129
151
  inputRange: [0, 1],
130
- outputRange: [zoomStart, zoomEnd],
152
+ outputRange: [cycle.scaleFrom, cycle.scaleTo],
131
153
  });
132
154
 
133
155
  const innerSize = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-kenburns-view",
3
- "version": "5.0.0",
3
+ "version": "5.2.0",
4
4
  "description": "KenBurns Image Effect for React Native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,7 +0,0 @@
1
- #import <RCTAppDelegate.h>
2
- #import <UIKit/UIKit.h>
3
- #import <Expo/Expo.h>
4
-
5
- @interface AppDelegate : EXAppDelegateWrapper
6
-
7
- @end
@@ -1,62 +0,0 @@
1
- #import "AppDelegate.h"
2
-
3
- #import <React/RCTBundleURLProvider.h>
4
- #import <React/RCTLinkingManager.h>
5
-
6
- @implementation AppDelegate
7
-
8
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
9
- {
10
- self.moduleName = @"main";
11
-
12
- // You can add your custom initial props in the dictionary below.
13
- // They will be passed down to the ViewController used by React Native.
14
- self.initialProps = @{};
15
-
16
- return [super application:application didFinishLaunchingWithOptions:launchOptions];
17
- }
18
-
19
- - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
20
- {
21
- return [self bundleURL];
22
- }
23
-
24
- - (NSURL *)bundleURL
25
- {
26
- #if DEBUG
27
- return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@".expo/.virtual-metro-entry"];
28
- #else
29
- return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
30
- #endif
31
- }
32
-
33
- // Linking API
34
- - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
35
- return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
36
- }
37
-
38
- // Universal Links
39
- - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
40
- BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
41
- return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
42
- }
43
-
44
- // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
45
- - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
46
- {
47
- return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
48
- }
49
-
50
- // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
51
- - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
52
- {
53
- return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
54
- }
55
-
56
- // Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
57
- - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
58
- {
59
- return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
60
- }
61
-
62
- @end
@@ -1,10 +0,0 @@
1
- #import <UIKit/UIKit.h>
2
-
3
- #import "AppDelegate.h"
4
-
5
- int main(int argc, char * argv[]) {
6
- @autoreleasepool {
7
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
8
- }
9
- }
10
-
@@ -1,4 +0,0 @@
1
- //
2
- // @generated
3
- // A blank Swift file must be created for native modules with Swift files to work correctly.
4
- //