React Native fit Text Component - javascript

I'm trying to fit my text inside available area and my constraints are something like this:
Text should not overflow,
Text must scales up inside all available view,
Words should not broken into characters and goes to next line sentences can be,
When I'm using flex inside parent view text should not expand view more than screen width horizontally.
Here is my code snippet:
import React from "react";
import { StyleSheet, Text, View } from "react-native";
import { Font } from "expo";
import Lorem from "./src/helpers/lorem-ipsum-gen";
export default class App extends React.Component {
constructor() {
super()
this.state = {
fontLoaded: false,
};
}
//theboldfont.ttf
async componentWillMount() {
await Font.loadAsync({
"akzidenz-grotesk-bq-bold": require("./assets/fonts/AkzidenzGrotesk_BQ_Bold.otf"),
});
this.setState({ fontLoaded: true });
}
render() {
let loremText = new Lorem().generate(20)
return (
<View style={styles.container}>
<View>
<View style={{ flex: 0.37 }} > </View>
<View style={{ flex: 0.25, backgroundColor: "red" }} >
<View >
{
this.state.fontLoaded ? (<Text
style={{ fontFamily: "akzidenz-grotesk-bq-bold", fontSize: 50 }}
adjustsFontSizeToFit={true}
>
{loremText}
</Text>) : null
}
</View>
</View>
<View style={{ flex: 0.38 }} >
<Text>
{loremText}
</Text>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
And result of it:
What I've tried to achieve my goal:
I thought it's related with custom font & changed to default font(Not worked)
In some github issues people wrote adjustsFontSizeToFit={true} inside text style prop (Not worked)
I tried allowFontScaling (Not worked)
Removed fontsize (Not worked)
Removed flex and set static width and height to view (Not worked)
Combinations of all steps above (Not worked)

So after trying new things on text component I've found that adjustsFontSizeToFit={true} is not working without specifying numberOfLines={number} however it is dividing my words into characters sometimes at the end of the line. And from the docs probably it's not available in android. So I still need a better way to find a solution to my problem

Note: this solution takes trial and error and assumes a container of fixed size.
You can use an interpolation function to scale down text based on the length of the longest line.
Interpolation function example (Feel free to take my interpolation function):
const fontSizeInterpolator = Interpolator.getInterpolator({
input: [4, 5, 6, 7, 8, 10, 11, 13, 40],
output: [45, 45, 32, 28, 28, 22, 19, 15, 10]
});
This means if the longest line is four characters long, set the font size very large. If the longest line is forty characters long, set the font size very small. From trial and error, specific line lengths are mapped to specific font sizes.
Find the longest line in the text via normal logic (here I only have one word per line):
const words = props.text.split(' ');
let longestWord = words[0];
for (const word of words) {
if (word.length > longestWord.length) {
longestWord = word;
}
}
Then get the font size from your interpolator:
const fontSize = fontSizeInterpolator(longestWord.length);
Example output:

Related

Can I word-break at a specific character with react native?

I'm using react native to create a category table.
Is there any way I can make the characters(texts) inside the table to line break at after or before a specific character?
for example : apple/banana/avocado
I want it to render like this (line break at after 'slashes') :
apple/banana/</ br>avocado
Thanks,
Yes, it is possible. Like in a normal react application you can use the following javascript functions:
Split your string on each "/", example:
var elements = yuourString.split(/\//)
Then you can use Map to render an object for each element, example:
elements.map(x => <SomeReactNativeComponent />);
You could take match instead of split by taking some non breaking character, a breaking character and other non breking character.
const names='banana/apple/mango/grapes';
const result=names.match(/([A-z]+\/[A-z]+)/g);
console.log(result)
After breaking the names into an array you can simply map them in react native
Expanding on my comment demo:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
const string = 'apple/banana/avocado';
export default function App() {
return (
<View style={styles.container}>
<Text style={{ marginBottom: 10 }}>
Before Change:{'\n '} {string}
</Text>
<Text style={{ marginBottom: 10 }}>
After Change:{'\n '} {string.replaceAll('/', '\n ')}
</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});

React Native: fit square in container

I have the following code:
import React from "react";
import { StyleSheet, View } from "react-native";
function App() {
return (
<View style={styles.container}>
<View style={styles.row_1}>
<View style={styles.square} />
</View>
<View style={styles.row_2}>
<View style={styles.square} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
},
row_1: {
flex: 1,
backgroundColor: "red",
alignItems: "center",
padding: 10
},
row_2: {
flex: 5,
backgroundColor: "blue",
alignItems: "center",
//flexDirection: 'row',
padding: 10
},
square: {
flex: 1,
aspectRatio: 1,
backgroundColor: "white"
}
});
export default App;
I'm trying to insert a white square in the center of the rows, without knowing a priori the height and the width of the rows. In the example, on a 4:3 phone, the first row is larger then higher and the second row higher than larger.
The square in the first row is correct, but the square in the second row exceeds the margins. I can manually set flexDirection: 'row' in the row_2 to achieve the expected result, but just because I know the container is higher than larger. How can I achieve the same result, without specifing the flex direction?
Sandbox here
Not exactly sure what the final result you're looking for, but for something responsive like this I would consider using a dynamic unit on width/height properties on your squares like viewport units -- vw, vh, vmin, vmax.
Alternatively you can get the viewport dimensions in pixels:
//e.g.
document.documentElement.clientWidth
document.documentElement.clientHeight
//or including scrollbar:
window.innerWidth
window.innerWidth
Then use a css styles library like emotion use the viewport dimensions in your styles.

React Native Paper ProgressBar Not visible

Hello i was following along a tutorial and it was going fine, until the tutor used react-native-paper ProgressBar in his project, I wrote exactly same but it was not visible, I found the documentation and plugged it, still not visible.
What am i Doing wrong?
import {View, StyleSheet, Text} from 'react-native' ;
import { ProgressBar, Colors } from 'react-native-paper';
import CountDown from '../comps/CountDown.js' ;
const Timer = ({task}) => {
return (
<View style={styles.container}>
<CountDown />
<Text style={styles.text}> Focusing On:</Text>
<Text style={[styles.text, styles.textBold]}> {task} </Text>
<ProgressBar progress={0.4} color='#5E84E2' style={styles.progress}/>
</View>
) ;
}
const styles = StyleSheet.create({
container : {
flex: 1,
width: 100,
alignItems: 'center' ,
justifyContent: 'center',
paddingTop: 40,
},
text: {
// flex: 0.5,
color: 'white'
},
textBold: {
fontWeight: 'bold' ,
// borderColor: 'white',
// borderWidth: 1,
// borderStyle: 'solid' ,
},
progress: {
height: 10,
// borderColor: 'white',
// borderWidth: 1,
// borderStyle: 'solid' ,
}
}) ;
export default Timer ;
Also, If i were to Give border to the progressBar, it appears but keep on increasing in width even when width is more than the viewport width. I dont know what is happening
The problem here is when you use alignItems the children components need to have a fixed width, your progress bar doesnet have a fixed width.
You will have to provide a with in the styles.
progress: {
height: 10,
width:50
}
Based on documentation default value for width is
auto (default value) React Native calculates the width/height for the
element based on its content, whether that is other children, text, or
an image.
Better have a value for width which will solve your issue.
A responsive solution
Currently ProgressBar doesn't support the flex styling system.
If someone is also looking to make the width equal to 100% if it's parrent component, there is a good recommended solution provided here.
Just set the width to undefined:
progress: {
height: 10,
width:undefined
}
e.g.
<View style={{ flex: 2, other flex styles }}>
<ProgressBar progress={0.5} color="white" style={{ height: 5, width: undefined }} />
</View>

Why the text is separated in some devices with fontSize: 25? REACT-NATIVE

i have an about component that just render two text component, this is the code:
class about extends Component {
render() {
return (
<>
<View style = {this.styles.container}>
<Text style = {this.styles.text}>Hi</Text>
<Text style = {this.styles.text}>A very simple notebloc.</Text>
</View>
</>
);
}
styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
marginTop: - Math.round(Dimensions.get("window").height * 0.5) / 2,
flexDirection: "column"
},
text: {
fontSize: 25,
fontFamily: "serif",
textAlign: "center",
color: "#1E90FF",
}
})
}
pertty simple, the problem now, is that I want them with FontSize: 25 but when I taste it in real devices, in some of them the second text is separated, gonna post some screen so you can see the issue:
this is how I want it works in all devices:
but in some devices I get this:
how can I solve this? I set the fontSize to 24 and I think it will work in all devices, but when its in 25, it doesnt, something to add, the first image is a device that the width is bigger than the second one, so I think the width isnt the problem
To solve that, try to use react-native-size-matters to scale the font size no matter the device pixel density.
For example
fontSize: moderateScale(24, 0.3)

react native - screen cut off at bottom

I'm building a React Native app for the first time using an iOS Simulator with XCode, and it seems that my elements on the bottom of the screen are being cut off, as if the screen can only scroll so far. I've tried changing the overall container View's height, but it doesn't change how far down I can scroll. I've also tried removing the styling, as well as changing View to ScrollView, but neither helped. Another strange thing is that I need to add paddingTop, otherwise, the first Text is displayed over the time in the simulator
Here's the code:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Fields from './components/Fields.js'
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Calculator</Text>
<Text>1099 Calculator</Text>
<Fields />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
paddingTop: 50
},
});
Here's the top of the screen without the padding
And here's how it looks cut off
This is an issue I also had. To fix it just wrap your container with another view without padding but with flex. So like this:
export default class App extends React.Component {
render() {
return (
<View style={styles.main}>
<View style={styles.container}>
<Text>Calculator</Text>
<Text>1099 Calculator</Text>
<Fields />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
paddingTop: 50
},
main: {
flex: 1
}
});
I was facing the same problem, it turned out to be the padding that I added to my ScrollView. Maybe it is not the solution, it is simply to discard ideas..

Categories