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,
},
});
Related
I am using JavaScript + React Native to make an app for my university project. I am using expo to manage my packaging and for viewing the app in the iOS simulator. I am also new to both JavaScript and React Native.
I have been having trouble with implementing a React Native module known as Secure Storage.
https://docs.expo.io/versions/latest/sdk/securestore/
I would like to store user data for the app. Specifically I would like to store a JavaScript object such as:
User{ name:"Bob", age:"20" }
And recall it later.
Having read the documentation, I have made a helper module called "StorageHelper" as seen below:
import * as SecureStore from 'expo-secure-store';
/**
* Stores data
* #param {} key
* #param {*} value
*/
export async function storeObject(key, value)
{
try
{
const jsonValue = JSON.stringify(value);
await SecureStore.setItemAsync(key, jsonValue);
}
catch(e)
{
console.log(e.message);
}
}
/**
* Retrieves data
* #param {} key
*/
export async function getObject(key)
{
let result = await SecureStore.getItemAsync(key);
if (result != null)
{
return result;
}
else
{
alert('No values stored under that key.');
}
On this screen in the app flow, I would like to generate the userObject object and store it in the SecureStorage. This following is
import React from 'react';
import { Text, View, TouchableOpacity, Image } from 'react-native';
import ProjStyleSheet from "../styles/ProjStyleSheet.js";
import * as StorageHelper from "../resources/StorageHelper.js";
const HomeImage = require('../art/HomeImage.png');
const styles = ProjStyleSheet;
function HomeScreen({ navigation }) {
var userData = "Bob"; // instead of the object, I'm just using a simple variable.
StorageHelper.storeObject("userName",userData);
return (
<View style={{
backgroundColor: "#fff",
flexDirection: "column",
justifyContent: "flex-start",
flex:1,}}>
<View style = {{
paddingTop: 100,
paddingBottom: 20,
paddingLeft: 10,
paddingRight: 10,
}}>
<Text style={styles.titleText}>University Money Management App</Text>
</View>
<View style = {{
justifyContent: "space-evenly",
alignItems: "center",
}}>
<Image
style={{width: 250, height: 250, paddingBottom:20}}
source={HomeImage}/>
<TouchableOpacity style={styles.defaultButton}
onPress={() => navigation.navigate('IntroName')}>
<Text style={styles.text}> Get Started </Text>
</TouchableOpacity>
</View>
</View>
);
}
export default HomeScreen;
In the next screen, I am trying to get the data from the secure storage and show it on the screen. This can be seen below:
import React, { useState } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import ProjStyleSheet from "../styles/ProjStyleSheet.js";
import { TextInput } from 'react-native-gesture-handler';
import * as StorageHelper from "../resources/StorageHelper.js";
const styles = ProjStyleSheet;
function IntroName({ navigation })
{
var name = StorageHelper.getObject("userName"); // retrieve the variable here.
return (
<View style={{
flex: 1,
backgroundColor: "#fff",
alignItems: 'center',
justifyContent: "space-around",}}>
<Text style={styles.titleText}>Please Enter Your Name</Text>
<Text> test = {name} </Text> // show the name here
<TextInput
style={{
borderColor: "#000",
borderRadius: 10,
borderWidth: 2,
padding: 20,
fontSize: 20,
width: "75%",
}}
placeholder="Your name here.">
</TextInput>
<TouchableOpacity
style={styles.defaultButton}
onPress={() => navigation.navigate("IntroIncome")}>
<Text style={styles.text}>Next</Text>
</TouchableOpacity>
</View>
);
}
export default IntroName;
Unfortunately, no name appears in the text where I intend it to. I have gone through the Secure Storage documentation and searched through the internet, however I cannot find any answers that can help me. Does anyone have any good ideas on what I am missing to fully implement SecureStorage?
the solution is quite simple. Thanks to the advice of #Tony, I converted all my function components to class components. Within those class components, I wrote an async method which calls the SecureStore method as such: await SecureStore.setItemAsync("user",this.name).
The async method updates the state of the screen, i.e
class Scren extends React.Component
{
constructor()
{
super();
this.state={
data:0,
};
}
async getObject()
{
let result = JSON.parse(await SecureStore.getItemAsync("data");
this.setState({
data: result,
};
}
}
I created a component at react-native, but the text of the button is always at uppercase, someone knows why it doesn't take the text that pass, because I want to show 'Login', but it shows 'LOGIN'
import React, { Component } from 'react';
import { View, Button} from 'react-native';
import LabelApp from "../../config/labels.app";
const labelApp = LabelApp.loginView;
export default class Login extends Component {
constructor(props){
super(props);
this.handleClickBtnEnter = this.makeLogin.bind(this);
}
makeLogin() {
}
render() {
return (
<View>
<Button title= {labelApp.textButtonLogin} onPress={this.handleClickBtnEnter}/>
</View>
);
}
}
Label of component
const LabelApp = {
loginView: {
textButtonLogin: 'Ingresar',
},
}
export default LabelApp;
The visualization
For react Native Paper button use uppercase={false} prop:
<Button
mode="outlined"
uppercase={false}
accessibilityLabel="label for screen readers"
style={styles.yourButtonStyle}>Button label</Button>
So, the other two answers are correct that you should use TouchableOpacity, but as someone new to React Native, it took me awhile to understand what was going on here. Hopefully this explanation provides a little more context.
The built-in Button component seems to have some weird compatibility/visibility issues on occasion, one of which is rendering the title prop text all uppercase. When viewing the documentation for the Button component in Chrome, the preview shows all text being capitalized under the "Web" view but not Android or iOS (I was having this issue using Expo and Metro Bundler on an Android device, so not sure what to make of this). I couldn't find anything about capitalization/uppercase in the Button docs, so perhaps this is a bug.
The solution is to use a different component called TouchableOpacity. It also has an onPress event you can use and a built-in touch animation, but it has less out of the box styling than the Button component. Important to note from docs: "Opacity is controlled by wrapping the children in an Animated.View, which is added to the view hierarchy. Be aware that this can affect layout." It doesn't have a title prop, so you just put the button text in a Text component, like so:
<Button
title='text will be capitalized'
onPress={onPress}
/>
becomes
<TouchableOpacity onPress={onPress}>
<Text>text will stay lowercase</Text>
</TouchableOpacity>
I was having the same issue as OP, and this solved it for me.
From the official documentation
A basic button component that should render nicely on any platform. Supports a minimal level of customization.
The recommend use of touchable opacity or touchable native feedback
https://facebook.github.io/react-native/docs/touchableopacity
Below I've added textTransform: 'lowercase', as a style rule for the button to override any inherited text casing.
import React, { Component } from 'react'
import {
StyleSheet,
TouchableOpacity,
Text,
View,
} from 'react-native'
export default class App extends Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
onPress = () => {
this.setState({
count: this.state.count+1
})
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPress={this.onPress}
>
<Text> Touch Here </Text>
</TouchableOpacity>
<View style={[styles.countContainer]}>
<Text style={[styles.countText]}>
{ this.state.count !== 0 ? this.state.count: null}
</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 10
},
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
textTransform: 'lowercase', // Notice this updates the default style
},
countContainer: {
alignItems: 'center',
padding: 10
},
countText: {
color: '#FF00FF'
}
})
https://snack.expo.io/Bko_W_gx8
This question is 3 years old and I'm not sure why no one has answered it correctly until now.
Native android buttons are all caps by default starting from android lollipop, which is what react native uses when you use the control Button from react-native in your app. To override the functionality, you just need to add this line in your styles.xml file inside your app theme (not the splash screen style)
<item name="android:textAllCaps">false</item>
You can get more details here: https://stackoverflow.com/a/30464346/11104068
The changes are not going to apply instantly obviously since the change is in the naive xml file and not in a JavaScript file. So you will need to do a npm/yarn run android
I've tried your code and it looks like it's the expected behaviour with Button component from react-native
You can see this at the official documentation
I believe that you need to change Button component, take it from another package to meet your needs.
As an alternative you can create your own button
import React, { Component } from 'react';
import { View, Button, TouchableHighlight, StyleSheet } from 'react-native';
import LabelApp from "../../config/labels.app";
const labelApp = LabelApp.loginView;
export default class Login extends Component {
constructor(props){
super(props);
this.handleClickBtnEnter = this.makeLogin.bind(this);
}
makeLogin() {
}
render() {
return (
<View>
<TouchableHighlight onPress={this.handleClickBtnEnter} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{labelApp.textButtonLogin}</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3'
},
buttonText: {
textAlign: 'center',
padding: 20,
color: 'white'
}
});
<Button
style={{
borderRadius: 10,
backgroundColor: "#000",
width: 200,
height: 50,
}}
>
<Text
uppercase={false}
>
Login
</Text>
</Button>
I'm learning to programming in React-Native (and also in Javascript) and I have a question.
Basically, I have created a Login for 2 categories of users: "Regular" and "Plus".
After the login they are redirect to an HomeUser page.
My problem is that in this "HomeUser" page I should create dynamic Content depending on the type of user.
This is the HomeUser
class HomeUser extends Component {
constructor(props){
super(props);
}
render() {
const FirstName = global.utente.data.Person.FirstName;
const LastName = global.utente.data.Person.LastName;
const Username = global.utente.data.Person.FiscalCode;
const Roles = global.utente.data.Roles
console.log(Roles)
return (
<View style={style.container}>
<View style={style.page}>
<Icon name="user-circle" color="#64c7c0" size={70} onPress={() => Actions.viewprofile()} />
<Text style={{paddingBottom: 15, textAlign: 'center', fontSize: 15, color: '#64c7c0', fontWeight: 'bold'}}>View Profile</Text>
<Text style={{textAlign: 'center', fontSize: 20,}}>{"Welcome"}</Text>
<Text style={{textAlign: 'center', fontSize: 20, color: '#64c7c0', fontWeight: 'bold'}}>{FirstName} {LastName}</Text>
<Text>{Roles}</Text>
//Add here "EDIT PROFILE" button to link a the page to edit profile, only for Regular User.
</View>
</View>
)
}
}
export default HomeUser;
So I should insert content dynamically for the users. Can you explain how can I do for example to the edit profile? I should create a new page and link to this page with a If condition? ( I don't think so xD )
My thought is that if I have to do more checks on the role, the efficiency of the application slows down. Is it possible that this problem occurs?
If i understand your question correctly you want to render a component when the user role is a specific one.
In this case you can use conditional rendering using:
{condition && <Component>}
inside you render return function.
In your code something like:
{Roles==="SpecificRole"&&<Button></Button>}
should do the trick
First Edit profile when you login success you can save user fix information on local storage then you can open new page name UserEditProfile it's a good way for efficiency.
If wanna show 1 page 2 different role stuff component you must create 2 component like that
//it's different .jsx file
<RegularUserComponent /*you can add props here*/ />
<SpecificRoleUserComponent />
then you can call like that
import RegularUserComponent from './components/RegularUserComponent.js'
import SpecificRoleUserComponent from './components/RegularUserComponent.js';
and use like that
// in render
{Roles==="Reqular" ? <RegularUserComponent/> :<SpecificRoleUserComponent/> }
localstorage about the information you must check this link
and An Example for a compornt
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View,Button,Image} from 'react-native';
export default class NameOfYouComponent extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
const {RequestResponse} = this.state;
return (
<View style={styles.container}>
{/*Here is Component include*/}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
you can call like that
import NameOfYouComponent from './../afolder/Component/NameOfYouComponent'
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:
This question already has answers here:
Passing Styles Based on Parent Component in React Native
(2 answers)
Closed 5 years ago.
I have a custom component called CardSection
import React from 'react';
import { View } from 'react-native';
const CardSection = (props) => {
return (
<View style={styles.containerStyle}>
{props.children}
</View>
);
};
const styles = {
containerStyle: {
borderBottomWidth: 1,
padding: 5,
backgroundColor: '#fff',
justifyContent: 'flex-start',
flexDirection: 'row',
borderColor: '#ddd',
position: 'relative'
}
};
export { CardSection };
When I instantiate this component from another class I would like to update one of the style elements while the others remain unchanged. The code below will only update the justifyContent element.
<CardSection style={{ justifyContent: 'space-between' }}>
The solution I have at the minute does not seem to be working and I would like to avoid duplicating the element with just a change to one of the style elements.
You could do the following:
//destruct props
const CardSection = ({ style, children }) => {
return (
// prop 'style' overrides standard containerStyle
<View style={[styles.containerStyle, style]}>
{children}
</View>
);
};
You can merge styles if you pass an array to styles:
const CardSection = (props) => {
return (
<View style={[styles.containerStyle, props.style]}>
{props.children}
</View>
);
};
They 'cascade' from left to right, meaning that latter styles in the array overwrite the former.
Here is the documentation for styling in react-native by default.