Focusing only in renderItem and FlatList.
Avatars are being displayed like this.
Some are circles some with rounded corners and defaultSource avatar are squares.
Can't seem to find a solution..
I've tried using borderRadius as an Image prop instead of using inside of the Image style.
renderItem = ({item}) => (
<ListItem
bottomDivider={true}
Component={TouchableScale}
friction={90}
tension={100}
activeScale={0.95}
title={item.name}
titleStyle={styles.titleStyle}
subtitle={item.email}
subtitleStyle={styles.subStyle}
leftAvatar={<Image source={{uri: 'my URL'}}
defaultSource={require('../resources/defaultAvatar.png')}
style={{width: 45, height: 45, borderRadius: 80}}
resizeMode={'contain'}/>}
onPress={() => this.onUserPress(item)}
chevronColor="white"
chevron
/>
)
render() {
const {search} = this.state;
return (
<View>
<SearchBar
platform={"ios"}
ref={search => this.search = search}
placeholder={'Escrever aqui...'}
color={'#808080'}
onChangeText={this.SearchFilterFunction}
value={search}
round={true}
inputStyle={{fontSize: 16}}
inputContainerStyle={{height: 35}}
containerStyle={{height: 53}}
showLoading={true}
/>
<FlatList
data={this.state.usersFilter.sort((a, b) => a.name.toString().localeCompare(b.name))}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>
</View>
);
}
I would like to all avatars being formatted properly.
I uploaded app print in comments!
import { Platform } from 'react-native';
borderRadius: Platform.OS === 'ios' ? 60 : 100
Try this, it works fine for me.
Related
Please help me out with this problem.
I can able to pick the image from my Local storage. In the Console also it is showing, But I cannot able to display it on the screen.
Here is my code.
import * as ImagePicker from "expo-image-picker";
import React, { useState } from "react";
import {
ActivityIndicator,
Button,
FlatList,
Image,
StyleSheet,
Text,
useWindowDimensions,
View
} from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
export default function App() {
const [images, setImages] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const pickImages = async () => {
// No permissions request is necessary for launching the image library
setIsLoading(true);
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
// allowsEditing: true,
allowsMultipleSelection: true,
selectionLimit: 10,
aspect: [4, 3],
quality: 1,
});
setIsLoading(false);
console.log(result);
if (!result.canceled) {
setImages(result.uri ? [result.uri] : result.selected);
}
};
return (
<>
<FlatList
data={images}
renderItem={({ item }) => (
<Image
source={{ uri: item.uri }}
style={{ width: 100, height: 100 }}
/>
)}
keyExtractor={(item) => item.uri}
contentContainerStyle={{ marginVertical: 50, paddingBottom: 50 }}
ListHeaderComponent={
isLoading ? (
<View>
<Text
style={{ fontSize: 20, fontWeight: "bold", textAlign: "center" }}
>
Loading...
</Text>
<ActivityIndicator size={"large"} />
</View>
) : (
<Button title="Pick images" onPress={pickImages} />
)
}
/>
</>
);
}
I can able to pick the image from my Local storage. In Console also it is showing, But i cannot able to display it in screen.
Kindly help me out.
It looks like you're already passing the uri into the array. by doing [result.uri] and then in the image you're doing it again item.uri. trying just doing the item.
I have a list of items, each having a body and a source. Currently it renders like this:
const ListItem = (props) => {
const {body, source} = props.context;
return (
<View style={styles.item}>>
<View style={{backgroundColor: 'lightblue'}}>
<Text style={styles.body}>{body}</Text>
</View>
<View style={{backgroundColor: 'lightyellow'}}>
<Text style={styles.source}>{source}</Text>
</View>
</View>
);
}
That's a lot of nesting and containers. Could it be done more optimally?
I am going to post my comment as an answer.
Previous comment:
I guess it depends on your design, AFAIK this is fine within React Native assuming you're using an optimized way of rendering your list (e.g. using a FlatList or similar)
As per your following comment, I don't think it's monstrous at all.
Here's an alternative. However, for readability I would much prefer the snippet you posted in your question.
const ListItem = props => {
const items = [
{ key: 'body', backgroundColor: 'lightblue' },
{ key: 'source', backgroundColor: 'lightyellow' }
];
return (
<View style={styles.item}>
{
items.map(({ key, backgroundColor }) =>
<View style={{ backgroundColor }}>
<Text style={styles[key]}>
{ props[key] }
</Text>
</View>
)
}
</View>
)
}
The Text component does take backgroundColor so you can let go of the two Views:
<View style={styles.item}>
<Text style={[styles.body, {backgroundColor: '...'}]}>{body}</Text>
<Text style={[styles.source, {backgroundColor: '...'}]}>{source}</Text>
</View>
Additionally, I don't know what the styles.item consists of, but if you want to go all the way, you might replace the other container View with React.Fragment.
we are currently running React-Native 0.33
We are trying to use the refs to go from 1 text input to another when they hit the next button. Classic username to password.
Anyone have any idea? Below is the code we are using. From other posts I've found on stack this is what they've done; however, it's telling us that this.refs is undefined.
UPDATE
So I've narrowed the problem down to
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
If I just render the code below in the renderScene function inside of the original render it works, however with the navigator it won't work. Does anyone know why? Or how to have the navigator show as well as render the code in renderScene to appear in the original render?
class LoginIOS extends Component{
constructor(props) {
super(props);
this.state={
username: '',
password: '',
myKey: '',
};
}
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
renderScene() {
return (
<View style={styles.credentialContainer}>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="person" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
ref = "FirstInput"
style={styles.input}
placeholder="Username"
autoCorrect={false}
autoCapitalize="none"
returnKeyType="next"
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({username: text})}
value={this.state.username}
onSubmitEditing={(event) => {
this.refs.SecondInput.focus();
}}
>
</TextInput>
</View>
</View>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="lock" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
ref = "SecondInput"
style={styles.input}
placeholder="Password"
autoCorrect={false}
secureTextEntry={true}
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({password: text})}
value={this.state.password}
returnKeyType="done"
onSubmitEditing={(event)=> {
this.login();
}}
focus={this.state.focusPassword}
>
</TextInput>
</View>
</View>
</View>
);
}
Try setting the reference using a function. Like this:
<TextInput ref={(ref) => { this.FirstInput = ref; }} />
Then you can access to the reference with this.FirstInput instead of this.refs.FirstInput
For a functional component using the useRef hook. You can use achieve this easily, with...
import React, { useRef } from 'react';
import { TextInput, } from 'react-native';
function MyTextInput(){
const textInputRef = useRef<TextInput>(null);;
return (
<TextInput ref={textInputRef} />
)
}
Try changing the Navigator's renderScene callback to the following (based on Navigator documentation) cause you will need the navigator object later.
renderScene={(route, navigator) => this.renderScene(route, navigator)}
Then, use 'navigator' instead of 'this' to get the refs.
navigator.refs.SecondInput.focus()
I have a list that will display a certain number of images in a row. What I want is for there to be space between each image. I was trying to use padding but it has not worked.
Here is what I have:
class ImageList extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
require('./images/ex1.jpg'), require('./images/ex2.jpg'), require('./images/ex3.jpg')
])
};
}
render() {
return (
<View>
<ListView
contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
renderRow={(rowData) => <Image source={rowData} style={styles.imageSize}/>}
/>
</View>
);
}
}
var styles = StyleSheet.create({
imageSize: {
//newWidth is the width of the device divided by 4.
//This is so that four images will display in each row.
width: newWidth,
height: newWidth,
padding: 2
},
list: {
flexDirection: 'row',
flexWrap: 'wrap'
}
});
In the main file the code is called:
class Main extends Component {
render(){
return(
<ScrollView>
<View style={{flex: 1}}>
<View>
<ImageList/>
</View>
</View>
</ScrollView>
);
}
};
I have tried putting padding in each View that I have to see if any it works. But so far nothing is working.
I have wrapped the rawData with a view like this:
render() {
return (
<View>
<ListView automaticallyAdjustContentInsets={false}
contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
renderRow={(rowData) => <View style={{padding: 1}}><Image source={rowData} style={styles.imageSize}/></View>}
/>
</View>
But this has caused a problem. When I try to have more than 3 images, only the first 3 appear. The rest are nowhere to be found.
I am building my first app with React Native, an app with a long list of images. I want to show a spinner instead of image while image is loading. It is sounds trivial but i didn't found a solution.
I think for a spinner i suppose to use ActivityIndicatorIOS , but how am i combining it with an Image component?
<Image source={...}>
<ActivityIndicatorIOS />
</Image>
Is this a right direction? Am i missing something?
I will share my solution
<View>
<Image source={{uri: this.state.avatar}} style={styles.maybeRenderImage}
resizeMode={"contain"} onLoadStart={() => this.setState({loading: true})}
onLoadEnd={() => {
this.setState({loading: false})
}}/>
{this.state.loading && <LoadingView/>}
</View>
LoadingView.js
export default class LoadingView extends Component {
render() {
return (
<View style={styles.container}>
<ActivityIndicator size="small" color="#FFD700"/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
position: "absolute",
left: 0,
right: 0,
top: 0,
bottom: 0,
opacity: 0.7,
backgroundColor: "black",
justifyContent: "center",
alignItems: "center",
}
});
Here is a complete solution to providing a custom image component with a loading activity indicator centered underneath the image:
import React, { Component } from 'react';
import { StyleSheet, View, Image, ActivityIndicator } from 'react-native';
export default class LoadableImage extends Component {
state = {
loading: true
}
render() {
const { url } = this.props
return (
<View style={styles.container}>
<Image
onLoadEnd={this._onLoadEnd}
source={{ uri: url }}
/>
<ActivityIndicator
style={styles.activityIndicator}
animating={this.state.loading}
/>
</View>
)
}
_onLoadEnd = () => {
this.setState({
loading: false
})
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
activityIndicator: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
}
})
I will share my own solution based only on CSS manipulation, which in my opinion is easy to understand, and the code is pretty clean. The solution is a little similar to other answers, but doesn't require absolute position of any component, or creating any additional components.
The idea is to switch between showing an <Image> and <ActivityIndicator>, based on some state variable (isImageLoaded in the snippet below).
<View>
<Image source={...}
onLoad={ () => this.setState({ isImageLoaded: true }) }
style={[styles.image, { display: (this.state.isImageLoaded ? 'flex' : 'none') }]}
/>
<ActivityIndicator
style={{ display: (this.state.isImageLoaded ? 'none' : 'flex') }}
/>
</View>
Also you should set image size using flex property (otherwise image will be invisible):
const styles = StyleSheet.create({
image: {
flex: 1,
}
});
Note that you don't have to initiate the isImageLoaded variable to false in the constructor, because it will have undefined value and the if conditions will act as expected.
Just ran into the same issue. So basically you have the correct approach, but the indicator should of course only be rendered when the image is loading. To keep track of that you need state. To keep it simple we assume you have just on image in the component an keep the state for it in the same component. (The cool kids will argue you should use a higher order component for that and then pass the state in via a prop ;)
The idea then is, that your image starts out loading and onLoadEnd (or onLoad, but then the spinner gets stuck on error, which is fine or course) you re-set the state.
getInitialState: function(){ return { loading: true }}
render: function(){
<Image source={...} onLoadEnd={ ()=>{ this.setState({ loading: false }) }>
<ActivityIndicatorIOS animating={ this.state.loading }/>
</Image>
}
You could also start out with { loading: false } and set it true onLoadStart, but I'm not sure what the benefit would be of that.
Also for styling reasons, depending on your layout, you might need to put the indicator in a container view that is absolutely positioned. But you get the idea.
Yes, deafultSource and loadingIndicatorSource is not working properly. Also image component cannot contain children. Try this solutions => https://stackoverflow.com/a/62510268/11302100
You can simply just add a placeholder
import { Image } from 'react-native-elements';
<Image
style={styles(colors).thumbnail}
source={{ uri: event.image }}
PlaceholderContent={<ActivityIndicator color={colors.indicator} />}
/>
const [imageLoading, setIsImageLoading] = useState(true);
<View>
<View
style={[
{justifyContent: 'center', alignItems: 'center'},
imageLoading ? {display: 'flex'} : {display: 'none'},
]}>
<ActivityIndicator />
</View>
<Image
source={{uri: ""}}
onLoadEnd={() => {setIsImageLoading(false)}}
style={[
imageStyle,
imageLoading ? {display: 'none'} : {display: 'flex'},
]}
/>
</View>