Camera Roll adding borderColor - javascript

So I want to create a beautiful UI of Camera Roll that has a borderColor instead of margin or padding because it will make the images do not fit on the width of the screen. I do not want to add borderColor to the right and left the side of the images too. It just likes on Instagram.
This is what I want to achieve:
Here are my codes:
CameraRoll.js
setIndex = (index) => {
if (index === this.state.index) {
index = null
}
this.setState({ index });
};
getPhotos = () => {
CameraRoll.getPhotos({
first: 200,
assetType: 'All'
})
.then(res => {
this.setState({
photos: res.edges,
});
})
.catch((err) => {
console.log('Error image: ' + err);
});
};
render() {
return(
<View style={styles.container}>
<Image
source={{uri: this.state.pickedImage}}
style={styles.image}
/>
<ScrollView contentContainerStyle={styles.scrollView} showsVerticalScrollIndicator={false}>
{this.state.photos.map((photos, index) => {
return(
<TouchableHighlight
style={{opacity: index === this.state.index ? .5 : 1}}
onPress={() => this.setState({pickedImage: photos.node.image.uri})}
key={index}
underlayColor='transparent'
>
<Image
style={[{width: width / 3, height: width /3}]}
source={{uri: photos.node.image.uri}}
resizeMode='cover'
/>
</TouchableHighlight>
);
})}
</ScrollView>
</View>
);
}
}

Change style of TouchableHighlight or Image, adding borderColor:"red", borderWidth:10
setIndex = (index) => {
if (index === this.state.index) {
index = null
}
this.setState({ index });
};
getPhotos = () => {
CameraRoll.getPhotos({
first: 200,
assetType: 'All'
})
.then(res => {
this.setState({
photos: res.edges,
});
})
.catch((err) => {
console.log('Error image: ' + err);
});
};
render() {
return(
<View style={styles.container}>
<Image
source={{uri: this.state.pickedImage}}
style={styles.image}
/>
<ScrollView contentContainerStyle={styles.scrollView} showsVerticalScrollIndicator={false}>
{this.state.photos.map((photos, index) => {
return(
<TouchableHighlight
style={{
opacity: index === this.state.index ? .5 : 1,
borderColor:"red", borderWidth:10
}}
onPress={() => this.setState({pickedImage: photos.node.image.uri})}
key={index}
underlayColor='transparent'
>
<Image
style={[{width: width / 3, height: width /3}]}
source={{uri: photos.node.image.uri}}
resizeMode='cover'
/>
</TouchableHighlight>
);
})}
</ScrollView>
</View>
);
}
}

Related

React Native - Setting item width according to the screen

I want 3 items to appear in each row and I want their size to be adjusted according to the screen itself, how can I do this?
I tried giving justifyContent to the flatlist columnWrapperStyle prop but the display turned out to be ridiculous
const renderSearchItem = ({
item: { id, type, title, original_title, poster },
}) => (
<Item
id={id}
type={type}
title={title == null ? original_title : title}
poster={poster}
navigation={navigation}
style={{ width: 115, height: 175 }}
/>
);
<FlatList
data={data?.datas}
renderItem={renderSearchItem}
keyExtractor={(item, index) => index.toString()}
key={search}
numColumns={3}
onEndReachedThreshold={1}
onEndReached={() => {
fetchMore({
variables: {
search,
offset: data?.datas?.length + 18,
},
updateQuery: (
previousResult,
{ fetchMoreResult }
) => {
if (
!fetchMoreResult ||
fetchMoreResult?.datas?.length === 0
) {
return previousResult;
}
return {
datas: previousResult?.datas?.concat(
fetchMoreResult?.datas
),
};
},
});
}}
ListHeaderComponent={headerComponent()}
showsVerticalScrollIndicator={false}
/>
You can get screen's width from Dimensions.
const width = Dimensions.get('screen').width
this will be the whatever the size of width the application running on.
export default function Item(props) {
const { id, type, title, poster, navigation, style } = props;
return (
<TouchableHighlight
style={styles.container}
onPress={() =>
navigation.navigate(
type == 'movie' ? 'MovieDetail' : 'SeriesDetail',
{
id,
title: title == null ? original_title : title,
}
)
}
>
<Image
style={[{ ...style }, { borderRadius: 5 }]}
source={{ uri: poster }}
/>
</TouchableHighlight>
);
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
marginBottom: 18,
marginLeft: 6,
},
});

How to animate only pressed index on array.map

I have a list of Views , and each view contain delete button.
I want to start scale out animation only on pressed view.
For now, with the next code , when I press on delete button, all views in this list are animated.
Here is my functional component :
export const SubTasksView = ({subTasks, onAddSubTask, subTaskValue, setSubTaskValue, onPressDeleteSubTask}) => {
const removeAnim = new Animated.Value(1);
const startRemoveAnimation = () => {
Animated.timing(
removeAnim,
{
toValue: 0,
duration: 300,
useNativeDriver: true
}
).start();
};
const onPressDeleteSubTaskHandler = index => {
startRemoveAnimation();
setTimeout(() => {
onPressDeleteSubTask(index);
}, 300);
};
return (
<View style={styles.mainContainer}>
<View style={styles.textInputContainerStyle}>
<TextInput
style={styles.textInputStyle}
placeholder={strings.PLACEHOLDER_SUB_TASK}
value={subTaskValue}
onChangeText={setSubTaskValue}
/>
<TouchableOpacity style={styles.addButtonStyle} onPress={onAddSubTask}>
<Ionicons name={icons.ICON_ADD} size={35} color={color.ORANGE}/>
</TouchableOpacity>
</View>
{subTasks.map((subTask, index) => {
return (
<Animated.View key={subTask + 'd' + index}
style={[styles.subTasksContainer,
{
transform: [
{scale: removeAnim}
]
}
]}>
<Text style={styles.subTaskText}>{subTask}</Text>
<TouchableOpacity onPress={() => {
onPressDeleteSubTaskHandler(index)
}}>
<Ionicons name={icons.ICON_TRASH} size={20} color={color.DARK_GREY}/>
</TouchableOpacity>
</Animated.View>
);
})}
</View>
);
};
Ok I fixed it within next way:
Just created new component and rendered it with FlatList
export const SubTaskItem = ({subTask, renderedIndex, onPressDeleteButton}) => {
const removeAnim = new Animated.Value(1);
const onDeletePressHandler = () => {
Animated.timing(
removeAnim,
{
toValue: 0,
duration: 100,
useNativeDriver: true
}
).start(() => {
onPressDeleteButton(renderedIndex)
});
};
return(
<Animated.View style={[styles.subTasksContainer,
{
transform: [
{scale: removeAnim}
]
}]}>
<Text style={styles.subTaskText}>{subTask}</Text>
<TouchableOpacity onPress={() => onDeletePressHandler()} >
<Ionicons name={icons.ICON_TRASH} size={20} color={color.DARK_GREY}/>
</TouchableOpacity>
</Animated.View>
)
};

TypeError: Cannot read property 's_path' of undefined (React Native)

How to solve this issue ?
i'm new in React Native, i'm try to solve this issue last 2 days.
TypeError: Cannot read property 's_path' of undefined
This error is located at:
in List (at SearchScreen.js:119)
I'm try to get images from server
I have searched a lot, but couldn't solve it. Please help.
SearchPage.js
useEffect(() => {
loadItem();
}, [query, pageCurrent, refreshing]);
const loadItem = async () => {
const response = await client.get(
`api.php?key=test-api-key&type=read&object=search&action=latestItems&limit=${pageCurrent}`
);
if (!response.ok) return setError(true);
setError(false);
setRefreshing(false);
dispatch(adDeatailsRequiested());
dispatch(adsData(response.data.response));
};
handleSearch = (text) => {
setQuery(text);
dispatch(searchQuery(query1));
};
loadMore = () => {
setpageCurrent(pageCurrent + 10);
};
pageRefreshing = () => {
setRefreshing(true);
};
return (
<View style={styles.container}>
<ActivityIndicator visible={loading} />
<View style={styles.listing}>
<FlatList
showsVerticalScrollIndicator={false}
numColumns={!liked ? 1 : 2}
key={!liked ? "ONE COLUMN" : "TWO COLUMN"}
style={styles.list}
data={Data}
keyExtractor={(item) => item.pk_i_id}
initialNumToRender={10}
removeClippedSubviews={true}
onEndReached={loadMore}
onEndReachedThreshold={0}
refreshing={refreshing}
onRefresh={pageRefreshing}
renderItem={({ item }) => (
LINE 119=>>>>> <List
title={item.s_title}
description={item.s_description}
subTitle={"₹" + item.i_price}
location={item.s_city}
region={item.s_region}
date={item.dt_pub_date}
adId={item.fk_i_item_id}
onPress={() =>
navigation.navigate(
routes.ITEM_SCREEN,
{
itemId: item.fk_i_item_id,
title: item.s_title,
description: item.s_description,
price: item.i_price,
date: item.dt_pub_date,
region: item.s_region,
city: item.s_city,
userName: item.s_contact_name,
userId: item.fk_i_user_id,
}
)
}
/>
)}
</>
)}
/>
</View>
</View>
);
}
list.js
useEffect(() => {
loadImage();
}, []);
const loadImage = async () => {
const response = await itemApi.getImage(+adId);
if (!response.ok) return setError(true);
setError(false);
setImage(response.data.response);
};
return (
<TouchableWithoutFeedback onPress={onPress}>
<View style={styles.container}>
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={
image
? {
uri: `${baseURL}${image[0].s_path}${image[0].pk_i_id}.${image[0].s_extension}`,
}
: defaultImg
}
/>
</View>
</View>
</TouchableWithoutFeedback>
);
Please add condition to check that image[0] is not null or undefined like that
{image[0] &&
<Image
style={styles.image}
source={
image
? {
uri: `${baseURL}${image[0].s_path}${image[0].pk_i_id}.${image[0].s_extension}`,
}
: defaultImg
}
/>}

unique "key" prop error using RN FlatList with List ITem

I have a screen in which I display a list of products.
I am trying to set up a pagination. I am using List item from react-native-elements and looking at Using RN FlatList as possible in the documentation for this package.
I set up the ability to do pagination, but I got confused in my code. I don't know how to fix it anymore. I would like to know if it would be possible for you to give me a boost and reread my code to give me your opinion.
There for the moment I have the error:
Each child in a list should have a unique "key" prop
I'm a bit lost and need some guidance please. Thanks for any explanation.
The code :
export default class Products extends Component {
constructor(props) {
super(props);
this.state = {
productId: (props.route.params && props.route.params.productId ? props.route.params.productId : -1),
listData: '',
currentPage: 1,
loadMoreVisible: true,
loadMoreVisibleAtEnd: false,
displayArray: []
}
};
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
loadMoreVisible: (list.length >= 10 ? true : false),
currentPage: 2
});
}
};
setNewData = async (page) => {
let list = await getProducts(parseInt(page));
if (list) {
this.setState({
displayArray: this.state.displayArray.concat(list),
loadMoreVisible: (list.length >= 10 ? true : false),
loadMoreVisibleAtEnd: false,
currentPage: parseInt(page)+1
});
}
};
loadMore() {
this.setNewData(this.state.currentPage);
}
displayBtnLoadMore() {
this.setState({
loadMoreVisibleAtEnd: true
});
}
async UNSAFE_componentWillMount() {
this.initListData();
}
renderItem = ({ item, i }) => (
<ListItem key={i}
bottomDivider
containerStyle={{backgroundColor: i % 2 === 0 ? '#fde3a7' : '#fff' }}
onPress={() => this.props.navigation.navigate('ProductDetails', {productId:parseInt(item.id)})}>
<Icon name='shopping-cart' />
<ListItem.Title style={{width: '65%', fontSize: 14, color: i % 2 === 0 ? '#212121' : '#F78400' }}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400'}}>{i18n.t("information.cost")}:{item.cost}</ListItem.Subtitle>
</ListItem>
);
render() {
//console.log('displayArray', this.state.displayArray)
return (
<View style={{flex: 1}}>
{this.state.displayArray !== null && this.state.displayArray.length > 0 ? (
<View style={{ flex: 1}}>
<SafeAreaView>
{
this.state.displayArray.map((item, i) => (
<FlatList
keyExtractor={(item, i) => {
return item.id;
}}
data={this.state.displayArray}
onEndReached={() => this.displayBtnLoadMore()}
renderItem={this.renderItem}
/>
))
}
</SafeAreaView>
{this.state.loadMoreVisible === true && this.state.loadMoreVisibleAtEnd === true ? (
<Button title=" + " onPress={()=>{this.loadMore()}}></Button>
) : null
}
<View style={styles.container}>
<Text>{"\n"}</Text>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.container}>
<Button
color="#F78400"
title= 'Back'
onPress={() => this.props.navigation.goBack()}>BACK
</Button>
</View>
</TouchableOpacity>
</View>
<Text>{"\n\n"}</Text>
</View>
) : (
<View style={styles.container}>
<Text>{"\n\n" + (this.state.displayArray === null ? i18n.t("products.searching") : i18n.t("products.nodata")) + "\n\n\n"}</Text>
<Button
color="#F78400"
title= 'Back'
onPress={() => this.props.navigation.goBack()}>BACK
</Button>
</View>
)}
</View>
);
};
}
The problem is not in your list items but in the FlatList itself - you are rendering an array of FlatList components but they don't have unique keys.
this.state.displayArray.map((item, i) => (
<FlatList
key={item.id} // or key={i} if item doesn't have ID
... rest of your flat list props
/>
))

React Native - How to pass the Image from the other Component without using React Redux

The goal is to pass the State of the Photos from my CameraRoll.js (Modal) to EventCreator.js(Modal) without using the React Redux. I'm using React Native Navigation V1.
I'm wondering maybe it is possible state of photos: [] become props? Just don't know how to do it. Need help, thank you guys!
Here are my codes:
CameraRoll.js:
state = {
photos: [],
index: null,
pickedImage: null
}
getPhotos = () => {
CameraRoll.getPhotos({
first: 200,
assetType: 'All'
})
.then(res => {
this.setState({
photos: res.edges,
});
})
.catch((err) => {
console.log('Error image: ' + err);
});
};
render() {
return(
<View style={styles.container}>
<Image source={{uri: this.state.pickedImage}} style={styles.image}/>
<ScrollView contentContainerStyle={styles.scrollView} showsVerticalScrollIndicator={false}>
{this.state.photos.map((photos, index) => {
return(
<TouchableHighlight
style={{opacity: index === this.state.index ? .5 : 1}}
onPress={() => this.setState({pickedImage: photos.node.image.uri})}
key={index}
underlayColor='transparent'
>
<Image
style={{width: width / 3, height: width /3}}
source={{uri: photos.node.image.uri}}
resizeMode='cover'
/>
</TouchableHighlight>
);
})}
</ScrollView>
</View>
);
}
EventCreator.js:
render(){
return(
<View style={styles.container}>
<EventInput
titleOnChangeText={this.eventNameChangedHandler}
descriptionOnChangeText={this.eventDescriptionChangedHandler}
titleEvent={this.state.controls.eventName}
descriptionEvent={this.state.controls.eventDescription}
/>
<Image
style={styles.image}
source={"I want to pass the image here from CameraRoll.js"}
resizeMode='contain'
/>
</View>
);
}
if you mean this:
onPress={() => this.setState({pickedImage: photos.node.image.uri})}
it just change the state value. What you should do is put an if statement on the return of cameraRoll.js:
private onPress = (img) => {
this.props.onImagePicked(img)
}
render() {
return(
<View style={styles.container}>
<Image source={{uri: this.state.pickedImage}} style={styles.image}/>
<ScrollView contentContainerStyle={styles.scrollView} showsVerticalScrollIndicator={false}>
{this.state.photos.map((photos, index) => {
return(
<TouchableHighlight
style={{opacity: index === this.state.index ? .5 : 1}}
onPress={() => this.onPress(photos.node.image.uri))}
key={index}
underlayColor='transparent'
>
<Image
style={{width: width / 3, height: width /3}}
source={{uri: photos.node.image.uri}}
resizeMode='cover'
/>
</TouchableHighlight>
);
})}
</ScrollView>
</View>
);
}
And in EventCreator.js:
constructor(){
super(props);
this.state = {
pickedImg: undefined
}
}
private onImagePicked = (newImg) => {
this.setState({
pickedImg: newImg
})
}
render(){
return(
<View style={styles.container}>
<EventInput
titleOnChangeText={this.eventNameChangedHandler}
descriptionOnChangeText={this.eventDescriptionChangedHandler}
titleEvent={this.state.controls.eventName}
descriptionEvent={this.state.controls.eventDescription}
/>
<Image
style={styles.image}
source={this.props.source}
resizeMode='contain'
/>
<CameraRoll props={...} onImagePicked={this.onImagePicked}/>
</View>
);
}

Categories