├── .gitignore ├── README.md ├── apple-app-of-the-day ├── App.js ├── README.md ├── app.json ├── assets │ ├── icons │ │ ├── app-icon.png │ │ └── loading-icon.png │ ├── images │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ └── 4.jpg │ └── snack-icon.png ├── components │ └── AssetExample.js └── package.json └── case-gif ├── app-store-today-demo.gif └── lottery-demo.gif /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-showcase 2 | 3 | 记录React Native的各种动画、交互Case,供大家参考使用,欢迎大家Star。 4 | 5 | ## Table of Contents 6 | 7 | * [九宫格抽奖转盘](#react-native-lottery) 8 | 9 | * [仿App Store Today页](#apple-app-store-today) 10 | 11 | * [自定义下拉刷新header组件](#react-native-pull-to-refresh-custom) 12 | 13 | * [motion-manager实现卡片动感光效动画](#react-native-motion-event-manager) 14 | 15 | ## react-native-lottery 16 | 17 | **React Native使用的9宫格抽奖转盘。** 18 | 19 | ![](./case-gif/lottery-demo.gif) 20 | 21 | [expo在线Demo](https://snack.expo.io/@wangcheng714/react-native-lottery) 22 | 23 | 开源组件 [react-native-super-lottery](https://github.com/rrd-fe/react-native-super-lottery) 24 | 25 | ## apple-app-store-today 26 | 27 | **仿照苹果应用商店`Today`页面的动画效果** 28 | 29 | ![](./case-gif/app-store-today-demo.gif) 30 | 31 | [expo在线Demo](https://snack.expo.io/@wangcheng714/apple-app-of-the-day) 32 | 33 | 实现文档 [React Native 实现 App Store Today页效果](https://github.com/rrd-fe/blog/blob/master/react-native/app-today-page.md) 34 | 35 | ## react-native-pull-to-refresh-custom 36 | 37 | **自定义下拉刷新header组件** 38 | 39 | ![pull to refresh screenshot](https://user-images.githubusercontent.com/219501/61520080-f9ac7000-aa3f-11e9-910c-7fa64f84f3ef.gif) 40 | 41 | [expo demo](https://snack.expo.io/@sophister/custom-pull-to-refresh-header) 42 | 43 | [github source](https://github.com/sophister/react-native-pull-to-refresh-custom) 44 | 45 | ## react-native-motion-event-manager 46 | 47 | **利用motion-manager实现卡片动感光效动画** 48 | 49 | ![react-native-motion-event-manager](https://user-images.githubusercontent.com/660208/61530682-5bc49f80-aa57-11e9-9fb0-4a8b74786984.gif) 50 | 51 | [React Native中如原生般流畅地使用设备传感器](https://github.com/rrd-fe/blog/blob/master/react-native/motion-event.md) 52 | 53 | [github source](https://github.com/rrd-fe/react-native-motion-event-manager) 54 | -------------------------------------------------------------------------------- /apple-app-of-the-day/App.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Text, 4 | View, 5 | Image, 6 | Alert, 7 | Animated, 8 | StyleSheet, 9 | ScrollView, 10 | Dimensions, 11 | SafeAreaView, 12 | TouchableWithoutFeedback, 13 | } from 'react-native'; 14 | 15 | const Images = [ 16 | require('./assets/images/1.jpg'), 17 | require('./assets/images/2.jpg'), 18 | require('./assets/images/3.jpg'), 19 | require('./assets/images/4.jpg'), 20 | ]; 21 | 22 | const SCREEN_HEIGHT = Dimensions.get('window').height; 23 | const SCREEN_WIDTH = Dimensions.get('window').width; 24 | 25 | export default class App extends React.Component { 26 | 27 | constructor(props) { 28 | super(props); 29 | this.imageRef = []; 30 | this.oldPosition = {}; 31 | // 描述图片的位置变化 32 | this.position = new Animated.ValueXY(); 33 | // 描述图片的大小变化 34 | this.measure = new Animated.ValueXY(); 35 | // 其他动画公用变量 36 | this.animation = new Animated.Value(0); 37 | this.state = { 38 | activeImage: null, 39 | } 40 | } 41 | 42 | openImage = (index) => { 43 | this.imageRef[index].measure((x, y, width, height, pageX, pageY) => { 44 | // 记录图片点击的时候位置,关闭详情视图的时候需要还原回去 45 | this.oldPosition = { 46 | width, 47 | height, 48 | x: pageX, 49 | y: pageY, 50 | }; 51 | 52 | // 初始化动画变量,准备开始动画 53 | this.position.setValue({ 54 | x: pageX, 55 | y: pageY, 56 | }); 57 | this.measure.setValue({ 58 | x: width, 59 | y: height, 60 | }); 61 | 62 | this.setState(() => { 63 | return { 64 | activeImage: Images[index], 65 | } 66 | }, () => { 67 | this.imageContainer.measure((x, y, width, height, pageX, pageY) => { 68 | Animated.parallel([ 69 | Animated.timing(this.position.x, { 70 | toValue: pageX, 71 | duration: 300, 72 | }), 73 | Animated.timing(this.position.y, { 74 | toValue: pageY, 75 | duration: 300, 76 | }), 77 | Animated.timing(this.measure.x, { 78 | toValue: width, 79 | duration: 300, 80 | }), 81 | Animated.timing(this.measure.y, { 82 | toValue: height, 83 | duration: 300, 84 | }), 85 | Animated.timing(this.animation, { 86 | toValue: 1, 87 | duration: 300, 88 | }), 89 | ]).start(); 90 | }); 91 | }); 92 | 93 | }); 94 | } 95 | 96 | closeImage = () => { 97 | Animated.parallel([ 98 | Animated.timing(this.position.x, { 99 | toValue: this.oldPosition.x, 100 | duration: 300, 101 | }), 102 | Animated.timing(this.position.y, { 103 | toValue: this.oldPosition.y, 104 | duration: 250, 105 | }), 106 | Animated.timing(this.measure.x, { 107 | toValue: this.oldPosition.width, 108 | duration: 250, 109 | }), 110 | Animated.timing(this.measure.y, { 111 | toValue: this.oldPosition.height, 112 | duration: 250, 113 | }), 114 | Animated.timing(this.animation, { 115 | toValue: 0, 116 | duration: 250, 117 | }), 118 | ]).start(() => { 119 | this.setState(() => { 120 | return { 121 | activeImage: null 122 | } 123 | }); 124 | }); 125 | } 126 | 127 | render() { 128 | 129 | const imageBorderAnimate = this.animation.interpolate({ 130 | inputRange: [0, 0, 1], 131 | outputRange: [20, 10, 0] 132 | }); 133 | // 设置图片的动画 134 | const imageAnimatedStyle = { 135 | top: this.position.y, 136 | left: this.position.x, 137 | width: this.measure.x, 138 | height: this.measure.y, 139 | borderRadius: imageBorderAnimate, 140 | }; 141 | 142 | const contentOpacityAnimate = this.animation.interpolate({ 143 | inputRange: [0, 0.5, 1], 144 | outputRange: [0, 1, 1] 145 | }); 146 | 147 | const contentYAnimate = this.animation.interpolate({ 148 | inputRange: [0, 1], 149 | outputRange: [-150, 0] 150 | }); 151 | // 设置内容的动画 152 | const contentAnimatedStyle = { 153 | opacity: contentOpacityAnimate, 154 | transform: [{ 155 | translateY: contentYAnimate, 156 | }] 157 | } 158 | // 设置关闭按钮的动画 159 | const croseAnimatedStyle = { 160 | opacity: this.animation 161 | }; 162 | 163 | return ( 164 | 165 | 166 | { 167 | Images.map((image, index) => { 168 | return ( 169 | { this.openImage(index); }}> 170 | 173 | { this.imageRef[index] = image; }} 175 | source={image} 176 | style={{ flex: 1, height: null, width: null, resizeMode: 'cover', borderRadius: 20, }} 177 | /> 178 | 179 | 180 | ); 181 | }) 182 | } 183 | 184 | 188 | { this.imageContainer = view; }}> 189 | 195 | 199 | 203 | X 204 | 205 | 206 | 207 | 211 | 这是图片的Title 212 | 这是图片的内容区域 213 | 214 | 215 | 216 | ); 217 | } 218 | } 219 | 220 | -------------------------------------------------------------------------------- /apple-app-of-the-day/README.md: -------------------------------------------------------------------------------- 1 | # Apple App of the day 2 | 3 | 模仿苹果App Store Today 页面的动画效果,实现React Native版本 4 | 5 | ## 实现步骤 6 | 7 | 1. 实现基本的列表布局 8 | 2. 实现打开详情页效果 9 | 3. 实现关闭详情页效果 -------------------------------------------------------------------------------- /apple-app-of-the-day/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "apple-app-of-the-day", 4 | "description": "No description", 5 | "slug": "snack-SJtwp_2gH", 6 | "privacy": "unlisted", 7 | "sdkVersion": "33.0.0", 8 | "version": "1.0.0", 9 | "orientation": "portrait", 10 | "primaryColor": "#cccccc", 11 | "icon": "https://d1wp6m56sqw74a.cloudfront.net/~assets/c9aa1be8a6a6fe81e20c3ac4106a2ebc", 12 | "loading": { 13 | "icon": "https://d1wp6m56sqw74a.cloudfront.net/~assets/c9aa1be8a6a6fe81e20c3ac4106a2ebc", 14 | "hideExponentText": false 15 | }, 16 | "packagerOpts": { 17 | "assetExts": [ 18 | "ttf", 19 | "mp4", 20 | "otf", 21 | "xml" 22 | ] 23 | }, 24 | "ios": { 25 | "supportsTablet": true 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/icons/app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/icons/app-icon.png -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/icons/loading-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/icons/loading-icon.png -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/images/1.jpg -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/images/2.jpg -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/images/3.jpg -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/images/4.jpg -------------------------------------------------------------------------------- /apple-app-of-the-day/assets/snack-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/apple-app-of-the-day/assets/snack-icon.png -------------------------------------------------------------------------------- /apple-app-of-the-day/components/AssetExample.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Text, View, StyleSheet, Image } from 'react-native'; 3 | 4 | export default class AssetExample extends React.Component { 5 | render() { 6 | return ( 7 | 8 | 9 | Local files and assets can be imported by dragging and dropping them into the editor 10 | 11 | 12 | 13 | ); 14 | } 15 | } 16 | 17 | const styles = StyleSheet.create({ 18 | container: { 19 | alignItems: 'center', 20 | justifyContent: 'center', 21 | padding: 24, 22 | }, 23 | paragraph: { 24 | margin: 24, 25 | marginTop: 0, 26 | fontSize: 14, 27 | fontWeight: 'bold', 28 | textAlign: 'center', 29 | }, 30 | logo: { 31 | height: 128, 32 | width: 128, 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /apple-app-of-the-day/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apple-app-of-the-day", 3 | "version": "0.0.0", 4 | "description": "No description", 5 | "author": null, 6 | "private": true, 7 | "main": "node_modules/expo/AppEntry.js", 8 | "dependencies": { 9 | "expo": "^33.0.0", 10 | "react": "16.8.3", 11 | "react-native": "https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz", 12 | "react-native-paper": "2.15.2" 13 | } 14 | } -------------------------------------------------------------------------------- /case-gif/app-store-today-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/case-gif/app-store-today-demo.gif -------------------------------------------------------------------------------- /case-gif/lottery-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrd-fe/react-native-showcase/470f745eb5d2cea7d878e58148b20a8db4711fcd/case-gif/lottery-demo.gif --------------------------------------------------------------------------------