🔘 Add border radius support to android and refactor and update examples.

This commit is contained in:
Dylan Vann 2018-01-29 01:42:29 -05:00
parent 737452bfa8
commit 3a33bdaa27
14 changed files with 474 additions and 180 deletions

View File

@ -1,10 +1,12 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {
View,
Image,
NativeModules,
requireNativeComponent,
ViewPropTypes,
StyleSheet,
} from 'react-native'
const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource')
@ -24,6 +26,9 @@ class FastImage extends Component {
onLoad,
onError,
onLoadEnd,
style,
children,
borderRadius,
...props
} = this.props
@ -44,21 +49,51 @@ class FastImage extends Component {
}
const resolvedSource = resolveAssetSource(source)
if (!children && !borderRadius) {
return (
<FastImageView
ref={e => (this._root = e)}
{...props}
style={style}
source={resolvedSource}
onFastImageLoadStart={onLoadStart}
onFastImageProgress={onProgress}
onFastImageLoad={onLoad}
onFastImageError={onError}
onFastImageLoadEnd={onLoadEnd}
/>
)
}
return (
<FastImageView
ref={e => (this._root = e)}
{...props}
source={resolvedSource}
onFastImageLoadStart={onLoadStart}
onFastImageProgress={onProgress}
onFastImageLoad={onLoad}
onFastImageError={onError}
onFastImageLoadEnd={onLoadEnd}
/>
<View style={style} borderRadius={borderRadius}>
<View style={styles.imageContainer} borderRadius={borderRadius}>
<FastImageView
ref={e => (this._root = e)}
{...props}
style={StyleSheet.absoluteFill}
source={resolvedSource}
onFastImageLoadStart={onLoadStart}
onFastImageProgress={onProgress}
onFastImageLoad={onLoad}
onFastImageError={onError}
onFastImageLoadEnd={onLoadEnd}
/>
</View>
{children}
</View>
)
}
}
const styles = StyleSheet.create({
imageContainer: {
...StyleSheet.absoluteFillObject,
overflow: 'hidden',
},
})
FastImage.resizeMode = {
contain: 'contain',
cover: 'cover',

View File

@ -1,13 +1,13 @@
import React from 'react'
import { TabNavigator, TabBarBottom } from 'react-navigation'
import FastImageExample from './fastImage/FastImageExample'
import FastImageExamples from './fastImage/FastImageExamples'
import FastImageGrid from './fastImage/FastImageGrid'
import DefaultImageGrid from './fastImage/DefaultImageGrid'
const App = TabNavigator(
{
fastImageExample: {
screen: FastImageExample,
screen: FastImageExamples,
},
image: {
screen: DefaultImageGrid,

View File

@ -0,0 +1,49 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
import withCacheBust from './withCacheBust'
import SectionFlex from './SectionFlex'
import FastImage from 'react-native-fast-image'
import Section from './Section'
import FeatureText from './FeatureText'
const IMAGE_URL = 'https://media.giphy.com/media/GEsoqZDGVoisw/giphy.gif'
const PLUS_IMAGE_URL =
'https://cdn3.iconfinder.com/data/icons/block/32/add-512.png'
const BorderRadiusAndChildrenExample = ({ onPressReload, bust }) => (
<View>
<Section>
<FeatureText text="• Border radius + children." />
</Section>
<SectionFlex onPress={onPressReload}>
<FastImage
style={styles.image}
borderRadius={100}
source={{
uri: IMAGE_URL + bust,
}}
>
<FastImage style={styles.plus} source={{ uri: PLUS_IMAGE_URL }} />
</FastImage>
</SectionFlex>
</View>
)
const styles = StyleSheet.create({
image: {
height: 100,
backgroundColor: '#ddd',
margin: 20,
width: 100,
flex: 0,
},
plus: {
width: 30,
height: 30,
position: 'absolute',
bottom: 0,
right: 0,
},
})
export default withCacheBust(BorderRadiusAndChildrenExample)

View File

@ -0,0 +1,22 @@
import React from 'react'
import { Text, TouchableOpacity, StyleSheet } from 'react-native'
const Button = ({ text, onPress }) => (
<TouchableOpacity onPress={onPress}>
<Text style={styles.button}>{text}</Text>
</TouchableOpacity>
)
const styles = StyleSheet.create({
button: {
backgroundColor: 'black',
color: 'white',
margin: 5,
padding: 5,
paddingLeft: 10,
paddingRight: 10,
borderRadius: 2,
},
})
export default Button

View File

@ -1,168 +0,0 @@
import React, { Component } from 'react'
import {
Button,
PixelRatio,
ScrollView,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native'
import Icon from 'react-native-vector-icons/Ionicons'
import FastImage from 'react-native-fast-image'
import uuid from 'uuid/v4'
const getImageUrl = (id, width, height) =>
`https://source.unsplash.com/${id}/${width}x${height}`
const IMAGE_SIZE = 150
const IMAGE_SIZE_PX = PixelRatio.getPixelSizeForLayoutSize(IMAGE_SIZE)
// The server is used to test that sending headers is working correctly.
const USE_SERVER = false
const TOKEN = 'someToken'
const getImages = () => {
if (USE_SERVER) {
const baseUrl = '192.168.2.11'
return [
`http://${baseUrl}:8080/pictures/ahmed-saffu-235616.jpg`,
`http://${baseUrl}:8080/pictures/alex-bertha-236361.jpg`,
`http://${baseUrl}:8080/pictures/jaromir-kavan-233699.jpg`,
]
}
return [
getImageUrl('x58soEovG_M', IMAGE_SIZE_PX, IMAGE_SIZE_PX),
getImageUrl('yPI7myL5eWY', IMAGE_SIZE_PX, IMAGE_SIZE_PX),
'https://cdn-images-1.medium.com/max/1600/1*-CY5bU4OqiJRox7G00sftw.gif',
]
}
const getTestProgressCallbacks = label => ({
onLoadStart: () => console.log(`${label} - onLoadStart`),
onProgress: e =>
console.log(
`${label} - onProgress - ${e.nativeEvent.loaded / e.nativeEvent.total}`,
),
onLoad: () => console.log(`${label} - onLoad`),
onError: () => console.log(`${label} - onError`),
onLoadEnd: () => console.log(`${label} - onLoadEnd`),
})
const images = getImages()
// Preload images. This can be called anywhere.
FastImage.preload([
{
uri: 'https://facebook.github.io/react/img/logo_og.png',
headers: { Authorization: 'someAuthToken' },
},
{
uri: 'https://facebook.github.io/react/img/logo_og.png',
headers: { Authorization: 'someAuthToken' },
},
])
class FastImageExample extends Component {
state = { bust: '?bust' }
onPressedReload = () => {
// Force complete re-render and bust image cache.
const key = uuid()
const bust = `?bust=${key}`
this.setState({ bust })
}
render() {
return (
<View style={styles.container} key={this.state.bust}>
<StatusBar
translucent
barStyle="dark-content"
backgroundColor="transparent"
/>
<ScrollView
style={styles.scrollContainer}
contentContainerStyle={styles.scrollContentContainer}
>
<View style={styles.textContainer}>
<Text style={styles.bold}>FastImage</Text>
<Text> priority (low, normal, high)</Text>
<Text> authentication (token)</Text>
<Button title="Reload" onPress={this.onPressedReload} />
</View>
<FastImage
style={styles.image}
source={{
uri: images[0] + this.state.bust,
headers: {
token: TOKEN,
},
priority: FastImage.priority.low,
}}
{...getTestProgressCallbacks('1')}
/>
<FastImage
style={styles.image}
source={{
uri: images[1] + this.state.bust,
headers: {
token: TOKEN,
},
priority: FastImage.priority.normal,
}}
{...getTestProgressCallbacks('2')}
/>
<FastImage
style={styles.image}
source={{
uri: images[2] + this.state.bust,
headers: {
token: TOKEN,
},
priority: FastImage.priority.high,
}}
{...getTestProgressCallbacks('3')}
/>
</ScrollView>
</View>
)
}
}
FastImageExample.navigationOptions = {
tabBarLabel: 'FastImage Example',
tabBarIcon: ({ focused, tintColor }) => {
if (focused)
return <Icon name="ios-information-circle" size={26} color={tintColor} />
return (
<Icon name="ios-information-circle-outline" size={26} color={tintColor} />
)
},
}
const styles = StyleSheet.create({
bold: {
fontWeight: '900',
},
textContainer: {
marginTop: 40,
marginBottom: 20,
},
image: {
height: IMAGE_SIZE,
width: IMAGE_SIZE,
backgroundColor: '#eee',
margin: 2,
},
container: {
flex: 1,
},
scrollContainer: {},
scrollContentContainer: {
alignItems: 'center',
flex: 0,
},
})
export default FastImageExample

View File

@ -0,0 +1,76 @@
import React from 'react'
import { ScrollView, StatusBar, StyleSheet, Text, View } from 'react-native'
import Icon from 'react-native-vector-icons/Ionicons'
import Section from './Section'
import PriorityExample from './PriorityExample'
import GifExample from './GifExample'
import BorderRadiusAndChildrenExample from './BorderRadiusAndChildrenExample'
import FeatureText from './FeatureText'
import ProgressExample from './ProgressExample'
import PreloadExample from './PreloadExample'
const FastImageExample = () => (
<View style={styles.container}>
<StatusBar
translucent
barStyle="dark-content"
backgroundColor="transparent"
/>
<ScrollView
style={styles.scrollContainer}
contentContainerStyle={styles.scrollContentContainer}
>
<View style={styles.contentContainer}>
<Section>
<Text style={styles.titleText}>🚩 FastImage</Text>
<FeatureText text="Tap images to reload examples." />
</Section>
<PriorityExample />
<GifExample />
<BorderRadiusAndChildrenExample />
<ProgressExample />
<PreloadExample />
</View>
</ScrollView>
</View>
)
FastImageExample.navigationOptions = {
tabBarLabel: 'FastImage Example',
tabBarIcon: ({ focused, tintColor }) => {
const name = focused
? 'ios-information-circle'
: 'ios-information-circle-outline'
return <Icon name={name} size={26} color={tintColor} />
},
}
const styles = StyleSheet.create({
titleText: {
fontWeight: '900',
marginBottom: 20,
color: '#222',
},
contentContainer: {
marginTop: 40,
marginBottom: 20,
},
image: {
flex: 1,
height: 100,
backgroundColor: '#ddd',
margin: 10,
},
container: {
flex: 1,
alignItems: 'stretch',
backgroundColor: '#fff',
},
scrollContainer: {},
scrollContentContainer: {
alignItems: 'stretch',
flex: 0,
},
})
export default FastImageExample

View File

@ -0,0 +1,10 @@
import React from 'react'
import { Text, StyleSheet } from 'react-native'
export default ({ text }) => <Text style={styles.style}>{text}</Text>
const styles = StyleSheet.create({
style: {
color: '#222',
},
})

View File

@ -0,0 +1,33 @@
import React from 'react'
import { View, StyleSheet } from 'react-native'
import withCacheBust from './withCacheBust'
import SectionFlex from './SectionFlex'
import FastImage from 'react-native-fast-image'
import Section from './Section'
import FeatureText from './FeatureText'
const GIF_URL =
'https://cdn-images-1.medium.com/max/1600/1*-CY5bU4OqiJRox7G00sftw.gif'
const GifExample = ({ onPressReload, bust }) => (
<View>
<Section>
<FeatureText text="• GIF support." />
</Section>
<SectionFlex onPress={onPressReload}>
<FastImage style={styles.image} source={{ uri: GIF_URL + bust }} />
</SectionFlex>
</View>
)
const styles = StyleSheet.create({
image: {
backgroundColor: '#ddd',
margin: 10,
height: 100,
width: 100,
flex: 0,
},
})
export default withCacheBust(GifExample)

View File

@ -0,0 +1,68 @@
import React, { Component } from 'react'
import { View, StyleSheet, TouchableOpacity, Text } from 'react-native'
import SectionFlex from './SectionFlex'
import FastImage from 'react-native-fast-image'
import Section from './Section'
import FeatureText from './FeatureText'
import uuid from 'uuid/v4'
import Button from './Button'
const IMAGE_URL =
'https://cdn-images-1.medium.com/max/1600/1*-CY5bU4OqiJRox7G00sftw.gif'
class PreloadExample extends Component {
state = {
show: false,
url: IMAGE_URL,
}
bustAndPreload = () => {
const key = uuid()
const bust = `?bust=${key}`
// Preload images. This can be called anywhere.
const url = IMAGE_URL + bust
FastImage.preload([{ uri: url }])
this.setState({ url, show: false })
}
showImage = () => {
this.setState({ show: true })
}
render() {
return (
<View>
<Section>
<FeatureText text="• Preloading." />
</Section>
<SectionFlex style={styles.section} onPress={this.props.onPressReload}>
{this.state.show ? (
<FastImage style={styles.image} source={{ uri: this.state.url }} />
) : (
<View style={styles.image} />
)}
<Button
text="Bust cache and preload."
onPress={this.bustAndPreload}
/>
<Button text="Render image." onPress={this.showImage} />
</SectionFlex>
</View>
)
}
}
const styles = StyleSheet.create({
section: {
flexDirection: 'column',
alignItems: 'center',
},
image: {
backgroundColor: '#ddd',
margin: 10,
height: 100,
width: 100,
},
})
export default PreloadExample

View File

@ -0,0 +1,59 @@
import React from 'react'
import { StyleSheet, View, PixelRatio } from 'react-native'
import withCacheBust from './withCacheBust'
import FastImage from 'react-native-fast-image'
import Section from './Section'
import SectionFlex from './SectionFlex'
import FeatureText from './FeatureText'
const getImageUrl = (id, width, height) =>
`https://source.unsplash.com/${id}/${width}x${height}`
const IMAGE_SIZE = 1024
const IMAGE_SIZE_PX = PixelRatio.getPixelSizeForLayoutSize(IMAGE_SIZE)
const IMAGE_URLS = [
getImageUrl('x58soEovG_M', IMAGE_SIZE_PX, IMAGE_SIZE_PX),
getImageUrl('yPI7myL5eWY', IMAGE_SIZE_PX, IMAGE_SIZE_PX),
getImageUrl('S7VCcp6KCKE', IMAGE_SIZE, IMAGE_SIZE),
]
const PriorityExample = ({ onPressReload, bust }) => (
<View>
<Section>
<FeatureText text="• Prioritize images (low, normal, high)." />
</Section>
<SectionFlex onPress={onPressReload}>
<FastImage
style={styles.image}
source={{
uri: IMAGE_URLS[0] + bust,
priority: FastImage.priority.low,
}}
/>
<FastImage
style={styles.image}
source={{
uri: IMAGE_URLS[1] + bust,
priority: FastImage.priority.normal,
}}
/>
<FastImage
style={styles.image}
source={{
uri: IMAGE_URLS[2] + bust,
priority: FastImage.priority.high,
}}
/>
</SectionFlex>
</View>
)
const styles = StyleSheet.create({
image: {
flex: 1,
height: 100,
backgroundColor: '#ddd',
margin: 10,
},
})
export default withCacheBust(PriorityExample)

View File

@ -0,0 +1,49 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
import withCacheBust from './withCacheBust'
import SectionFlex from './SectionFlex'
import FastImage from 'react-native-fast-image'
import Section from './Section'
import FeatureText from './FeatureText'
const IMAGE_URL = 'https://media.giphy.com/media/GEsoqZDGVoisw/giphy.gif'
const getTestProgressCallbacks = label => ({
onLoadStart: () => console.log(`${label} - onLoadStart`),
onProgress: e =>
console.log(
`${label} - onProgress - ${e.nativeEvent.loaded / e.nativeEvent.total}`,
),
onLoad: () => console.log(`${label} - onLoad`),
onError: () => console.log(`${label} - onError`),
onLoadEnd: () => console.log(`${label} - onLoadEnd`),
})
const ProgressExample = ({ onPressReload, bust }) => (
<View>
<Section>
<FeatureText text="• Progress callbacks." />
</Section>
<SectionFlex onPress={onPressReload}>
<FastImage
style={styles.image}
source={{
uri: IMAGE_URL + bust,
}}
{...getTestProgressCallbacks('ProgressExample')}
/>
</SectionFlex>
</View>
)
const styles = StyleSheet.create({
image: {
height: 100,
backgroundColor: '#ddd',
margin: 20,
width: 100,
flex: 0,
},
})
export default withCacheBust(ProgressExample)

View File

@ -0,0 +1,13 @@
import React from 'react'
import { View, StyleSheet } from 'react-native'
export default ({ children }) => <View style={styles.section}>{children}</View>
const styles = StyleSheet.create({
section: {
marginTop: 10,
marginBottom: 10,
marginLeft: 40,
marginRight: 40,
},
})

View File

@ -0,0 +1,20 @@
import React from 'react'
import { TouchableOpacity, StyleSheet } from 'react-native'
export default ({ children, onPress, style }) => (
<TouchableOpacity style={[styles.sectionFlex, style]} onPress={onPress}>
{children}
</TouchableOpacity>
)
const styles = StyleSheet.create({
sectionFlex: {
backgroundColor: '#eee',
flexDirection: 'row',
justifyContent: 'center',
marginTop: 10,
marginBottom: 10,
marginLeft: -10,
marginRight: -10,
},
})

View File

@ -0,0 +1,28 @@
import React, { Component } from 'react'
import uuid from 'uuid/v4'
export default BaseComponent => {
class WithCacheBust extends Component {
state = { bust: '?bust' }
onPressReload = () => {
// Force complete re-render and bust image cache.
const key = uuid()
const bust = `?bust=${key}`
this.setState({ bust })
}
render() {
return (
<BaseComponent
bust={this.state.bust}
onPressReload={this.onPressReload}
/>
)
}
}
WithCacheBust.displayName = `withCacheBust${BaseComponent.displayName}`
return WithCacheBust
}