I think something went wrong when I reorganized my RN project in order to export APK. Here is the issue:
I'm using checkbox and some other icons from #expo//vector-icons in one of my components.
Everytime I launch it, I have a font which is missing. Feather, MaterialCommunityIcons,...
I face the same issue in my searchbar in an other component.
Checkboxes and icons look like after i Dismiss the error in my app
I'm really trying hard to fix it (for hours) and to import my font in some way or an another...
There is the beginning of my code if someone see what is wrong ... Thank you all !
"sdkVersion": "35.0.0",
componentDidMount() {
this.loadAssetsAsync()
}
loadAssetsAsync = async () => {
await Font.loadAsync({
MaterialCommunityIcons,
Feather: require('../assets/Fonts/Feather.ttf'),
FontAwesome: require('../assets/Fonts/FontAwesome.ttf'),
'Material Icons': require('../assets/Fonts//MaterialIcons.ttf'),
'MaterialIcons': require('../assets/Fonts//MaterialIcons.ttf'),
'MaterialCommunityIcons': require('../assets/Fonts//MaterialCommunityIcons.ttf'),
'Material-Community-Icons': require('../assets/Fonts//MaterialCommunityIcons.ttf'),
})
}
The fatal error
A warning
The fonts are loading async AFTER the component was mounted. So you need to wait for fonts before rendering your component's childs. So you can try somthing like
loadAssetsAsync = async () => {
await Font.loadAsync({
MaterialCommunityIcons,
Feather: require('../assets/Fonts/Feather.ttf'),
FontAwesome: require('../assets/Fonts/FontAwesome.ttf'),
'Material Icons': require('../assets/Fonts//MaterialIcons.ttf'),
'MaterialIcons': require('../assets/Fonts//MaterialIcons.ttf'),
'MaterialCommunityIcons': require('../assets/Fonts//MaterialCommunityIcons.ttf'),
'Material-Community-Icons': require('../assets/Fonts//MaterialCommunityIcons.ttf'),
})
this.setState({fontsLoaded: true})
}
render(){
if(this.state.fontsLoaded){
return(
// Your component
)
}
else{
return(
<View>
<ActivityIndicator />
</View>
)
}
}
Related
We are facing some very weird issue with opening keyboard on Android device.
It works great on iOS, 90% on Android devices, but on some devices it simply don't work = the keyboard don't show despite the input field has focus.
We tried it with different approaches (with refs, with timeout and without ref either).
All with the same result :/. One of the devices we are trying has API 30, so it even doesn't seem to be an old API problem.
Have anybody facing similar issue? What can cause the issue? Any tips how to debug it?
Here is code:
export const AddNotificationModal: AddNotificationModalT = ({
visible,
category,
onCloseModal,
}) => {
const input = useRef<TextInput>(null);
...
useEffect(() => {
if (visible) {
// 1.
// InteractionManager.runAfterInteractions(() => {
// if (input?.current) {
// input.current.focus();
// }
// });
// 2.
input.current?.focus();
// 3.
// setTimeout(() => input.current?.focus(), 150);
}
}, [visible]);
return (
<Modal
name={AddNotificationModal.name}
visible={visible}>
...
<View>
<TextInput autoFocus={true} ref={input} />
<Button dark onPress={() => onConfirm()}>
{t('shared:buttons.safe')}
</Button>
</View>
</Modal>
);
};
Coming from reactjs i was expecting "alt" attribute on the image component that will show text in case the image could not be loaded.
I read the documentation here and the closest thing I found is the on error event.
Is there an attribute equal to alt in React Native image component? And what is the easiest way to replace your image with a default text if i don't have the alt attribute?
You can make such a component yourself, it requires a very minimal amount of code. Here's a basic example:
export default class AccessibleImage extends Component {
state = {
error : false
};
_onImageLoadError = (event) => {
console.warn(event.nativeEvent.error);
this.setState({ error : true });
}
render() {
const { source, alt, style } = this.props;
const { error } = this.state;
if (error) {
return (
<Text>{alt}</Text>
);
}
return (
<Image
accessible
accessibilityLabel={alt}
source={source}
style={style}
onError={this._onImageLoadError} />
);
}
}
This will show the provided alt if there was an error loading the image and also use that text as the accessibilityLabel for screen readers which is closer to web behaviour.
A better answer than the previous if using React Native 0.68+ is to include the alt attribute on an <Image> Component like so
<Image
style={styles.yourImageStyles}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
alt={'Alternate text that will be read be screen readers'}
/>
Chatgpt said:
let displayImage;
try {
displayImage = <Image source={require('./secondImage.png')} />;
} catch (error) {
displayImage = <Text>Second Image not available</Text>;
}
and to use the image/text:
{displayImage}
For the case of this question let's say I'm building Medium as a React Native app, specifically the screen where you read a story.
This is a long screen, with different types of content appearing as you scroll down. The title, the author information, the content (paragraphs, images, videos, etc), some meta information at the end, social features like comments, etc.
What's the recommended way to build a view like this? ScrollView doesn't seem performant enough especially if there were videos or other media types that needed to be loaded within the content. ListViews seem like they are the more performant option but don't seem like they are designed for this use-case.
Has anyone else faced this challenge? What's the best way to approach it?
<ScrollView> renders all its children first. So, let say you have thousands of elements(medium articles), <ScrollView> will first render all of them, which is pretty much slow and is visible.
For these cases, you can use <FlatList>, which renders the child when it enters the viewport. So, it is performant.
You can refer <FlatList> documentation here: https://facebook.github.io/react-native/docs/flatlist
I had a similar problem for one screen in my app where there were various categories of components involved, for my case <FlatList> worked very well, performance was also up-to the mark.
Solution
Example.js
import React, { Component } from "react";
import { FlatList } from "react-native";
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
showProgress: false,
content: [{}, {}, {}] // list of objects
};
}
onRefresh() {
this.setState({ showProgress: true });
// call methods here to load new data, once loaded make sure to reset the loading state to false
this.setState({ showProgress: false });
}
showParagraph() {
return <React.Fragment>{/* Your paragraph */}</React.Fragment>;
}
showVideo() {
return <React.Fragment>{/* Your Videos */}</React.Fragment>;
}
showAudio() {
return <React.Fragment>{/* Your Audio */}</React.Fragment>;
}
renderItem(item) {
return (
<React.Fragment>
{item.isVideo ? showVideo() : showParagraph()}
</React.Fragment>
);
}
NoDataMessage() {
return <React.Fragment>{/* Empty screen message goes here */}</React.Fragment>;
}
render() {
return (
<FlatList
data={this.state.content}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => this.renderItem(item)}
onRefresh={() => this.onRefresh()}
refreshing={this.state.showProgress}
ListEmptyComponent={this.NoDataMessage()}
/>
);
}
}
read more about props from here, also you can make an infinite news feed like facebook home page check this React native infinite scroll with flatlist
hope this helps..!
I'm trying to call a function that will fire upon onFoucs on TextInput that will scroll the scrollView all the way down (using scrollToEnd())
so this is my class component
class MyCMP extends Component {
constructor(props) {
super(props);
this.onInputFocus = this.onInputFocus.bind(this);
}
onInputFocus() {
setTimeout(() => {
this.refs.scroll.scrollToEnd();
console.log('done scrolling');
}, 1);
}
render() {
return (
<View>
<ScrollView ref="scroll">
{ /* items */ }
</ScrollView>
<TextInput onFocus={this.onInputFocus} />
</View>
);
}
}
export default MyCMP;
the component above works and it does scroll but it takes a lot of time ... I'm using setTimeout because without it its just going down the screen without calculating the keybaord's height so it not scrolling down enough, even when I keep typing (and triggering that focus on the input) it still doesn't scroll all the way down.
I'm dealing with it some good hours now, I did set the windowSoftInputMode to adjustResize and I did went through some modules like react-native-keyboard-aware-scroll-view or react-native-auto-scroll but none of them really does the work as I need it.
any direction how to make it done the right way would be really appreciated. thanks!
Rather than using a setTimeout you use Keyboard API of react-native. You add an event listener for keyboard show and then scroll the view to end. You might need to create some logic on which input is focused if you have more than one input in your component but if you only have one you can just do it like the example below.
Another good thing to do is changing your refs to functional ones since string refs are considered as legacy and will be removed in future releases of react. More info here.
class MyCMP extends Component {
constructor(props) {
super(props);
this.scroll = null;
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
}
componentWillUnmount () {
this.keyboardDidShowListener.remove();
}
_keyboardDidShow() {
this.scroll.scrollToEnd();
}
render() {
return (
<View>
<ScrollView ref={(scroll) => {this.scroll = scroll;}}>
{ /* items */ }
</ScrollView>
<TextInput />
</View>
);
}
}
export default MyCMP;
If you have a large dataset React Native docs is telling you to go with FlatList.
To get it to scroll to bottom this is what worked for me
<FlatList
ref={ref => (this.scrollView = ref)}
onContentSizeChange={() => {
this.scrollView.scrollToEnd({ animated: true, index: -1 }, 200);
}}
/>
I'm trying to use shoutem/ui with exponent and I’m getting an error using the shoutem/ui textinput component, where I get the following error message fontFamily Rubik is not a system font and has not been loaded through Exponent.Font.loadAsync
However I loaded all the custom shoutem fonts that were listed in the blog post https://blog.getexponent.com/using-react-native-ui-toolkits-with-exponent-3993434caf66#.iyiwjpwgu
Using the Exponent.Font.loadAsync method.
fonts: [
FontAwesome.font,
{'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf')},
{'Rubik-Black': require('./node_modules/#shoutem/ui/fonts/Rubik-Black.ttf')},
{'Rubik-BlackItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BlackItalic.ttf')},
{'Rubik-Bold': require('./node_modules/#shoutem/ui/fonts/Rubik-Bold.ttf')},
{'Rubik-BoldItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BoldItalic.ttf')},
{'Rubik-Italic': require('./node_modules/#shoutem/ui/fonts/Rubik-Italic.ttf')},
{'Rubik-Light': require('./node_modules/#shoutem/ui/fonts/Rubik-Light.ttf')},
{'Rubik-LightItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-LightItalic.ttf')},
{'Rubik-Medium': require('./node_modules/#shoutem/ui/fonts/Rubik-Medium.ttf')},
{'Rubik-MediumItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-MediumItalic.ttf')},
{'Rubik-Regular': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf')},
{'rubicon-icon-font': require('./node_modules/#shoutem/ui/fonts/rubicon-icon-font.ttf')},
],
});
Looking through the code I couldn't find the obvious fix - had trouble even finding where the style was set to throw the error.
The code above seem to be missing one line. Try adding this line to the array list:
{'Rubik': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf')}
Use this code from the link
import React, { Component } from 'react';
import { StatusBar } from 'react-native';
import { Font, AppLoading } from 'expo';
import { View, Examples } from '#shoutem/ui';
export default class App extends React.Component {
state = {
fontsAreLoaded: false,
};
async componentWillMount() {
await Font.loadAsync({
'Rubik': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf'),
'Rubik-Black': require('./node_modules/#shoutem/ui/fonts/Rubik-Black.ttf'),
'Rubik-BlackItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BlackItalic.ttf'),
'Rubik-Bold': require('./node_modules/#shoutem/ui/fonts/Rubik-Bold.ttf'),
'Rubik-BoldItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BoldItalic.ttf'),
'Rubik-Italic': require('./node_modules/#shoutem/ui/fonts/Rubik-Italic.ttf'),
'Rubik-Light': require('./node_modules/#shoutem/ui/fonts/Rubik-Light.ttf'),
'Rubik-LightItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-LightItalic.ttf'),
'Rubik-Medium': require('./node_modules/#shoutem/ui/fonts/Rubik-Medium.ttf'),
'Rubik-MediumItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-MediumItalic.ttf'),
'Rubik-Regular': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf'),
'rubicon-icon-font': require('./node_modules/#shoutem/ui/fonts/rubicon-icon-font.ttf'),
});
this.setState({ fontsAreLoaded: true });
}
render() {
if (!this.state.fontsAreLoaded) {
return <AppLoading />;
}
return (
<View styleName="flexible">
<Examples />
<StatusBar barStyle="default" hidden={false} />
</View>
);
}
}