Improve image layout
This commit is contained in:
parent
f609794bd2
commit
55500e2f66
3 changed files with 192 additions and 79 deletions
|
@ -10,7 +10,8 @@ import {
|
|||
ViewStyle,
|
||||
} from 'react-native'
|
||||
import {Text} from '../text/Text'
|
||||
import {colors} from '../../../lib/styles'
|
||||
import {useTheme} from '../../../lib/ThemeContext'
|
||||
import {usePalette} from '../../../lib/hooks/usePalette'
|
||||
|
||||
const MAX_HEIGHT = 300
|
||||
|
||||
|
@ -23,12 +24,16 @@ export function AutoSizedImage({
|
|||
uri,
|
||||
onPress,
|
||||
style,
|
||||
containerStyle,
|
||||
}: {
|
||||
uri: string
|
||||
onPress?: () => void
|
||||
style: StyleProp<ImageStyle>
|
||||
style?: StyleProp<ImageStyle>
|
||||
containerStyle?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const [error, setError] = useState<string | undefined>()
|
||||
const theme = useTheme()
|
||||
const errPal = usePalette('error')
|
||||
const [error, setError] = useState<string | undefined>('')
|
||||
const [imgInfo, setImgInfo] = useState<Dim | undefined>()
|
||||
const [containerInfo, setContainerInfo] = useState<Dim | undefined>()
|
||||
|
||||
|
@ -77,15 +82,22 @@ export function AutoSizedImage({
|
|||
<View style={style}>
|
||||
<TouchableWithoutFeedback onPress={onPress}>
|
||||
{error ? (
|
||||
<View style={[styles.container, styles.errorContainer]}>
|
||||
<Text style={styles.error}>{error}</Text>
|
||||
<View style={[styles.errorContainer, errPal.view, containerStyle]}>
|
||||
<Text style={errPal.text}>{error}</Text>
|
||||
</View>
|
||||
) : calculatedStyle ? (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.container, containerStyle]}>
|
||||
<Image style={calculatedStyle} source={{uri}} />
|
||||
</View>
|
||||
) : (
|
||||
<View style={[style, styles.placeholder]} onLayout={onLayout} />
|
||||
<View
|
||||
style={[
|
||||
style,
|
||||
styles.placeholder,
|
||||
{backgroundColor: theme.palette.default.backgroundLight},
|
||||
]}
|
||||
onLayout={onLayout}
|
||||
/>
|
||||
)}
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
|
@ -96,18 +108,12 @@ const styles = StyleSheet.create({
|
|||
placeholder: {
|
||||
width: '100%',
|
||||
aspectRatio: 1,
|
||||
backgroundColor: colors.gray1,
|
||||
},
|
||||
errorContainer: {
|
||||
backgroundColor: colors.red1,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
container: {
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
error: {
|
||||
color: colors.red5,
|
||||
},
|
||||
})
|
||||
|
|
148
src/view/com/util/images/ImageLayoutGrid.tsx
Normal file
148
src/view/com/util/images/ImageLayoutGrid.tsx
Normal file
|
@ -0,0 +1,148 @@
|
|||
import React from 'react'
|
||||
import {
|
||||
Image,
|
||||
ImageStyle,
|
||||
LayoutChangeEvent,
|
||||
StyleProp,
|
||||
StyleSheet,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from 'react-native'
|
||||
|
||||
interface Dim {
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
export type ImageLayoutGridType = 'two' | 'three' | 'four'
|
||||
|
||||
export function ImageLayoutGrid({
|
||||
type,
|
||||
uris,
|
||||
onPress,
|
||||
style,
|
||||
}: {
|
||||
type: ImageLayoutGridType
|
||||
uris: string
|
||||
onPress?: (index: number) => void
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const [containerInfo, setContainerInfo] = React.useState<Dim | undefined>()
|
||||
|
||||
const onLayout = (evt: LayoutChangeEvent) => {
|
||||
setContainerInfo({
|
||||
width: evt.nativeEvent.layout.width,
|
||||
height: evt.nativeEvent.layout.height,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={style} onLayout={onLayout}>
|
||||
{containerInfo ? (
|
||||
<ImageLayoutGridInner
|
||||
type={type}
|
||||
uris={uris}
|
||||
onPress={onPress}
|
||||
containerInfo={containerInfo}
|
||||
/>
|
||||
) : undefined}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function ImageLayoutGridInner({
|
||||
type,
|
||||
uris,
|
||||
onPress,
|
||||
containerInfo,
|
||||
}: {
|
||||
type: ImageLayoutGridType
|
||||
uris: string
|
||||
onPress?: (index: number) => void
|
||||
containerInfo: Dim
|
||||
}) {
|
||||
const size1 = React.useMemo<ImageStyle>(() => {
|
||||
if (type === 'three') {
|
||||
const size = (containerInfo.width - 10) / 3
|
||||
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
|
||||
} else {
|
||||
const size = (containerInfo.width - 5) / 2
|
||||
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
|
||||
}
|
||||
}, [type, containerInfo])
|
||||
const size2 = React.useMemo<ImageStyle>(() => {
|
||||
if (type === 'three') {
|
||||
const size = ((containerInfo.width - 10) / 3) * 2 + 5
|
||||
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
|
||||
} else {
|
||||
const size = (containerInfo.width - 5) / 2
|
||||
return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
|
||||
}
|
||||
}, [type, containerInfo])
|
||||
|
||||
if (type === 'two') {
|
||||
return (
|
||||
<View style={styles.flexRow}>
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(0)}>
|
||||
<Image source={{uri: uris[0]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
<View style={styles.wSpace} />
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(1)}>
|
||||
<Image source={{uri: uris[1]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
if (type === 'three') {
|
||||
return (
|
||||
<View style={styles.flexRow}>
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(0)}>
|
||||
<Image source={{uri: uris[0]}} style={size2} />
|
||||
</TouchableWithoutFeedback>
|
||||
<View style={styles.wSpace} />
|
||||
<View>
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(1)}>
|
||||
<Image source={{uri: uris[1]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
<View style={{height: 5}} />
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(2)}>
|
||||
<Image source={{uri: uris[2]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
if (type === 'four') {
|
||||
return (
|
||||
<View style={styles.flexRow}>
|
||||
<View>
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(0)}>
|
||||
<Image source={{uri: uris[0]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
<View style={styles.hSpace} />
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(1)}>
|
||||
<Image source={{uri: uris[1]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
<View style={styles.wSpace} />
|
||||
<View>
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(2)}>
|
||||
<Image source={{uri: uris[2]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
<View style={styles.hSpace} />
|
||||
<TouchableWithoutFeedback onPress={() => onPress?.(3)}>
|
||||
<Image source={{uri: uris[3]}} style={size1} />
|
||||
</TouchableWithoutFeedback>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
return <View />
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
flexRow: {flexDirection: 'row'},
|
||||
wSpace: {width: 5},
|
||||
hSpace: {height: 5},
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue