1import {
2  Image,
3  ImageContentFit,
4  ImageContentPosition,
5  ImageContentPositionString,
6} from 'expo-image';
7import { ScrollView, StyleSheet, Text, View } from 'react-native';
8
9import HeadingText from '../../components/HeadingText';
10import { Colors } from '../../constants';
11
12const CONTENT_FITS = [
13  ImageContentFit.COVER,
14  ImageContentFit.CONTAIN,
15  ImageContentFit.FILL,
16  ImageContentFit.NONE,
17  ImageContentFit.SCALE_DOWN,
18];
19
20const CONTENT_POSITIONS: ImageContentPositionString[] = [
21  'center',
22  'top',
23  'right',
24  'bottom',
25  'left',
26  'top center',
27  'top right',
28  'top left',
29  'right center',
30  'right top',
31  'right bottom',
32  'bottom center',
33  'bottom right',
34  'bottom left',
35  'left center',
36  'left top',
37  'left bottom',
38];
39
40type ContentFitExample = {
41  size: [number, number];
42  position?: ImageContentPosition;
43};
44
45const EXAMPLES: ContentFitExample[] = [
46  {
47    size: [1500, 1000],
48  },
49  {
50    size: [300, 200],
51  },
52  {
53    size: [200, 300],
54  },
55  {
56    size: [240, 160],
57    position: { top: 10, left: 20 },
58  },
59  {
60    size: [240, 160],
61    position: { top: 0, right: 0 },
62  },
63  {
64    size: [240, 160],
65    position: { bottom: 5, left: 10 },
66  },
67  {
68    size: [240, 160],
69    position: { bottom: '10%', right: '10%' },
70  },
71  {
72    size: [240, 160],
73    position: { left: '15%' },
74  },
75  {
76    size: [240, 160],
77    position: { top: '-50%', right: '10%' },
78  },
79];
80
81function sourceWithSize(size: [number, number]): string {
82  return `https://picsum.photos/seed/138/${size[0]}/${size[1]}`;
83}
84
85function renderExample(contentFit: ImageContentFit, example: ContentFitExample, index: number) {
86  const sizeText = example.size.join(' x ');
87  const positionText = example.position
88    ? JSON.stringify(example.position).replaceAll(/[{}"]/g, '').replaceAll(/[:,]/g, ' ')
89    : null;
90
91  return (
92    <View key={index} style={styles.imageContainer}>
93      <Image
94        style={styles.image}
95        source={{ uri: sourceWithSize(example.size) }}
96        contentFit={contentFit}
97        contentPosition={example.position}
98      />
99      <Text style={styles.description}>{[sizeText, positionText].filter(Boolean).join('\n')}</Text>
100    </View>
101  );
102}
103
104function renderContentFitExamples(contentFit: ImageContentFit, index: number) {
105  return (
106    <View key={index} style={styles.contentFitExamples}>
107      <HeadingText style={styles.headingText}>{`Content fit: "${contentFit}"`}</HeadingText>
108      <ScrollView style={styles.examplesScrollView} horizontal indicatorStyle="black">
109        {EXAMPLES.map((example, index) => renderExample(contentFit, example, index))}
110      </ScrollView>
111    </View>
112  );
113}
114
115function renderContentPositionExample(contentPosition: ImageContentPositionString, index: number) {
116  const example: ContentFitExample = {
117    size: [100, 100],
118    position: contentPosition,
119  };
120  return renderExample(ImageContentFit.NONE, example, index);
121}
122
123export default function ImageContentFitScreen() {
124  return (
125    <ScrollView style={styles.container}>
126      <HeadingText style={styles.headingText}>Full-size image</HeadingText>
127      <Image style={styles.fullImageExample} source={{ uri: sourceWithSize([1500, 1000]) }} />
128      <Text style={styles.description}>1500 x 1000</Text>
129
130      {CONTENT_FITS.map(renderContentFitExamples)}
131
132      <View style={styles.contentFitExamples}>
133        <HeadingText style={styles.headingText}>Content positions (strings)</HeadingText>
134        <ScrollView style={styles.examplesScrollView} horizontal indicatorStyle="black">
135          {CONTENT_POSITIONS.map(renderContentPositionExample)}
136        </ScrollView>
137      </View>
138    </ScrollView>
139  );
140}
141
142const styles = StyleSheet.create({
143  container: {
144    flex: 1,
145  },
146  contentFitExamples: {
147    backgroundColor: Colors.greyBackground,
148    borderTopColor: Colors.border,
149    borderTopWidth: StyleSheet.hairlineWidth,
150  },
151  fullImageExample: {
152    width: 300,
153    height: 200,
154    margin: 10,
155    alignSelf: 'center',
156  },
157  headingText: {
158    marginTop: -6,
159    marginBottom: 6,
160    marginHorizontal: 10,
161  },
162  examplesScrollView: {
163    padding: 10,
164  },
165  imageContainer: {
166    marginRight: 15,
167    alignItems: 'center',
168  },
169  image: {
170    width: 100,
171    height: 100,
172    borderColor: Colors.tintColor,
173    borderWidth: 1,
174  },
175  description: {
176    padding: 5,
177    fontSize: 11,
178    textAlign: 'center',
179  },
180});
181