React-Native Tooltip Issue - react-native

I'm trying to find a simple working tooltip for react-native but I can't find any. All of them has many many bugs. I'd like to describe an issue in "react-native-elements/Tooltip" (version 3.4.2) and also ask for a working tooltip component.
...
render() {
return (
<View>
<Text style={styles.pageTitle}>{this.props.messages.account}</Text>
<View style={styles.horizontalFlex}>
<Text
style={styles.userInfo}>{this.props.messages.subscriptionModel}: {this.props.route.params.userProfile}
</Text>
<Tooltip popover={<Text>Info here</Text>}>
<EntypoIcon style={styles.infoIcon} name="info-with-circle" size={20} color={Colors.DARK_BLUE}/>
</Tooltip>
</View>
</View>
);
}
...
let styles = EStyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
},
pageTitle: {
...
},
userInfo: {
textAlign: "left",
justifyContent: "center",
marginLeft: "20rem",
color: Colors.DARK_BLUE,
fontSize: "15rem",
marginBottom: "10rem"
},
infoIcon: {
paddingLeft: "20rem",
},
horizontalFlex: {
flexDirection: "row"
}
});
...
The output for the above code is the following:
Somehow the icon which I'm putting a Tooltip to, slides above. It doesn't matter if it's an icon or a text, same issue occurs. How do I fix this? Do you know any other working tooltip in react-native which you tried and saw that it is working recently?

I had to set withOverlay to false and skipAndroidStatusBar to true. This wasn't what I needed but still it's acceptable. Here is the code:
<Tooltip
popover={<Text style={...text style here...}>Change here</Text>}
withOverlay={false}
skipAndroidStatusBar={true}
containerStyle={...container style here...}
backgroundColor={...color...}>

Related

How to display a button at the bottom of a Webview in react-native?

Inside my component (PrivacyPolicy.js), i have a header view, a webview, and a footer view. the webview, depending on the size, gets scrollable. my issue is that the footer view is displayed at the bottom of the screen like if its style was "position: 'absolute'" so it keeps displayed while scrolling. I need to have it after all webview is displayed.
<View style={styles.main_container}>
<View style={styles.header_container}>
...
</View>
<WebView originWhitelist={['*']} source={{ html: privacyPolicyContent }}/>
<View style={styles.footer_container}>
<CheckBox
disabled={false}
value={this.state.isChecked}
onValueChange={(newValue) => this.setState({
isChecked: newValue
})}
style={styles.checkbox}
tintColors={{ true: '#157dfa' }}
/>
<Text style={styles.checkbox_text}>I have read and accept the Privacy Polic</Text>
</View>
</View>
My styles:
const styles = StyleSheet.create({
main_container: {
flex: 1,
paddingHorizontal:'5%'
},
header_container: {
height: scale(90),
flexDirection: 'row',
marginLeft: 10
},
checkbox_container: {
flexDirection: 'row'
},
checkbox: {
marginLeft: -5,
},
checkbox_text: {
marginTop: 8,
fontSize: 10
}
})
I can see few suggestions:
Since your button is a React Native Button => You can show/hide based on the scrollY positions. For that, you need to communicate over the Bridge to dispatch an event accordingly.
As an alternative solution => You can create the button on the Webview its self to have the same functionality.

React Native styles not working for parent view?

I'm getting a white background and the parent view is not filling the whole screen.
here's my render function. I'm totally baffled. This usually just works. This is very simple. I just want a view with a background color and some text and a button. The button renders but the formatting for the parent view component isn't working. Feedback is appreciated.
render(){
return(
<View style={stylesAM.container}>
<View style={stylesAM.textContainer}>
<Text style={stylesAM.title}>You're all signed up!</Text>
<Text style={stylesAM.body}>Please check your email to verify your account.</Text>
</View>
<View style={stylesAM.buttonContainer}>
<AuthButton type='Back'/>
</View>
</View>
)
}
}
stylesAM=StyleSheet.create({
containter:{
flex: 1,
backgroundColor:'#323AB3',
alignItems:'center',
paddingTop:44
},
textContainer:{
paddingLeft:35,
paddingRight:35,
alignItems:'center',
paddingTop:100
},
title:{
fontFamily:'GlacialIndifference',
fontSize:20,
color:'black'
},
body:{
fontFamily:'GlacialIndifference',
fontSize:15,
color:'black'
},
buttonContainer:{
flex:1,
paddingBottom:40,
justifyContent:'flex-end'
}
})
You have typo in your style name :)
double check it again.
There is a typo mistake in style
containter:{
flex: 1,
backgroundColor:'#323AB3',
alignItems:'center',
paddingTop:44
},
It should be container.

React-Native onPress doesn't work, when touch the icon

I'am using react-native-element to create a button group, that embedded an Icon from react-native-vector-icons .
the problem is that when the icon is touched, onPress does not get triggered
constructor(props) {
super(props);
this.state = { selectedIndex: 0 };
this.SetSelected = this.SetSelected.bind(this);
}
SetSelected(index) {
this.setState({ selectedIndex: index });
}
return(
<ButtonGroup
selectedIndex={this.state.selectedIndex}
onPress={this.SetSelected}
selectedButtonStyle={{ backgroundColor: 'blue' }}
buttons={[
{
element: () => (
<Icon.Button
name="slack"
style={{ backgroundColor: 'white' }}
color={'black'}
size={30}
title="Inbox"
>
<Text style={{ color: 'black', fontSize: 15, textAlignVertical: 'center', textAlign: 'center' }}
>
All
</Text>
</Icon.Button>
),
})
Thanks to Kyle Roach,
the reason is
because I am using an Icon.Button which is touchable. So when I try to tap to change the ButtonGroup, the touch event will be caught by Icon.Button instead of the button for the buttonGroup.
I should use Icon instead of Icon.Button.
Try making it a function.
onPress={() => {this.SetSelected()}}
If it doesn't work please provide the this.SetSelected function.

React Native FlatList rendering a few items at a time

I have a list of chat messages in my app to which new items are added to the bottom. I used some code from another SO question to make the FlatList stick to the bottom when new items are added, as below
<FlatList
data={messages}
renderItem={({item}) => <ChatMessage message={item}></ChatMessage>}
keyExtractor={(item, index) => index.toString()}
initialNumToRender={messages.length}
initialScrollIndex={messages.length-1}
ref={ref => this.flatList = ref}
onContentSizeChange={(contentWidth, contentHeight)=>{
this.flatList.scrollToEnd();
}}
/>
The problem is that when the initial list renders (only 35 items, hardcoded in an array for now) it seems to render just a few items, then scroll down a bit, then render a few more, then scroll down a bit until it finally completes the rendering and sticks to the bottom. It's choppy and slow, despite adding initialNumToRender={messages.length} and rendering an incredibly simple node for each result.
Ideally I guess I need to wait for it to fully render before displaying anything to the user but (A) they'd have to wait a couple of seconds to start using the chat room and (B) I don't think that's how Flatlist works, I assume the elements have to be viewable before it is rendered.
Is there just a better way to do this? (Testing on Android by the way)
EDIT: Adding ChatMessage component for completeness
// Chat Message
import React, { Component } from 'react'
import {
StyleSheet,
ImageBackground,
Text,
View
} from 'react-native'
class ChatMessage extends Component {
constructor(props) {
super(props)
this.state = { }
}
render() {
return (
<View style={styles.chatMessage}>
<View style={styles.chatMessage_layout}>
<View style={styles.chatMessage_pic}>
<View style={styles.chatMessage_pic_image}>
<ImageBackground
source={require('./assets/images/profile-pics/example-profilr.png')}
style={styles.chatMessage_pic_image_background}
imageStyle={{ borderRadius: 40/2 }}
resizeMode="cover"
>
</ImageBackground>
</View>
</View>
<View style={styles.chatMessage_details}>
<View style={styles.chatMessage_name}>
<Text style={styles.chatMessage_name_text}>
{this.props.message.name}
<Text style={styles.chatMessage_name_time}> 24h</Text>
</Text>
</View>
<View style={styles.chatMessage_message}>
<Text style={styles.chatMessage_message_text}>{this.props.message.text}</Text>
</View>
</View>
</View>
</View>
)
}
}
export default ChatMessage;
const styles = StyleSheet.create({
chatMessage: {
paddingVertical: 10,
paddingHorizontal: 24
},
chatMessage_layout: {
flexDirection: 'row'
},
chatMessage_pic: {
width: 40,
height: 40,
marginRight: 12
},
chatMessage_pic_image: {
width: 40,
height: 40
},
chatMessage_pic_image_background: {
width: 40,
height: 40
},
chatMessage_details: {
flex: 1
},
chatMessage_name_text: {
color: '#FFF',
fontSize: 14,
fontWeight: 'bold'
},
chatMessage_name_time: {
fontSize: 11,
color: 'rgba(255,255,255,0.6)'
},
chatMessage_message: {
flexDirection: 'row',
alignItems: 'center'
},
chatMessage_message_text: {
color: '#FFF',
fontSize: 12
}
})
If you have less number of items and want to render all items at once then you should use ScrollView as mentioned in the docs
ScrollView: Renders all elements at once, but slow if there are large number of elements.
FlatList: Renders items in a lazy mode, when they are about to appear and removes them when they leave the visible display to save memory that makes it usable for performance on large lists.
For Flatlist optimization you need to use PureComponent whenever you render the child so that it only shallow compares the props.
Also in the keyExtractor use a unique id for your item and do not depend upon the index, since when the item updates the index is not reliable and may change

React Native add bold or italics to single words in <Text> field

How do I make a single word in a Text field bold or italics? Kind of like this:
<Text>This is a sentence <b>with</b> one word in bold</Text>
If I create a new text field for the bold character it will separate it onto another line so that's surely not the way to do it. It would be like creating a < p > tag within a < p > tag just to make one word bold.
You can use <Text> like a container for your other text components.
This is example:
...
<Text>
<Text>This is a sentence</Text>
<Text style={{fontWeight: "bold"}}> with</Text>
<Text> one word in bold</Text>
</Text>
...
Here is an example.
For a more web-like feel:
const B = (props) => <Text style={{fontWeight: 'bold'}}>{props.children}</Text>
<Text>I am in <B>bold</B> yo.</Text>
you can use https://www.npmjs.com/package/react-native-parsed-text
import ParsedText from 'react-native-parsed-text';
class Example extends React.Component {
static displayName = 'Example';
handleUrlPress(url) {
LinkingIOS.openURL(url);
}
handlePhonePress(phone) {
AlertIOS.alert(`${phone} has been pressed!`);
}
handleNamePress(name) {
AlertIOS.alert(`Hello ${name}`);
}
handleEmailPress(email) {
AlertIOS.alert(`send email to ${email}`);
}
renderText(matchingString, matches) {
// matches => ["[#michel:5455345]", "#michel", "5455345"]
let pattern = /\[(#[^:]+):([^\]]+)\]/i;
let match = matchingString.match(pattern);
return `^^${match[1]}^^`;
}
render() {
return (
<View style={styles.container}>
<ParsedText
style={styles.text}
parse={
[
{type: 'url', style: styles.url, onPress: this.handleUrlPress},
{type: 'phone', style: styles.phone, onPress: this.handlePhonePress},
{type: 'email', style: styles.email, onPress: this.handleEmailPress},
{pattern: /Bob|David/, style: styles.name, onPress: this.handleNamePress},
{pattern: /\[(#[^:]+):([^\]]+)\]/i, style: styles.username, onPress: this.handleNamePress, renderText: this.renderText},
{pattern: /42/, style: styles.magicNumber},
{pattern: /#(\w+)/, style: styles.hashTag},
]
}
childrenProps={{allowFontScaling: false}}
>
Hello this is an example of the ParsedText, links like http://www.google.com or http://www.facebook.com are clickable and phone number 444-555-6666 can call too.
But you can also do more with this package, for example Bob will change style and David too. foo#gmail.com
And the magic number is 42!
#react #react-native
</ParsedText>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
url: {
color: 'red',
textDecorationLine: 'underline',
},
email: {
textDecorationLine: 'underline',
},
text: {
color: 'black',
fontSize: 15,
},
phone: {
color: 'blue',
textDecorationLine: 'underline',
},
name: {
color: 'red',
},
username: {
color: 'green',
fontWeight: 'bold'
},
magicNumber: {
fontSize: 42,
color: 'pink',
},
hashTag: {
fontStyle: 'italic',
},
});
It is not in a text field as asked but wrapping separate text elements into a view would give the desired output. This can be used if you don't want to add another library into your project just for styling a few texts.
<View style={{flexDirection: 'row'}}>
<Text style={{fontWeight: '700', marginRight: 5}}>Contact Type:</Text>
<Text>{data.type}</Text>
</View>
Would result as follows
You can also put a Text tag inside of another Text tag. The second text tag will inherit the styling of the first, but you maintain the ability to style it independently from its parent.
<Text style={styles.bold}>Level:
<Text style={styles.normal}>Easy</Text>
</Text>
//in your stylesheet...
bold: {
fontSize: 25,
fontWeight: "bold",
color: "blue",
},
normal: {
// will inherit size and color attributes
fontWeight: "normal",
}
Use this react native library
To install
npm install react-native-htmlview --save
Basic Usage
import React from 'react';
import HTMLView from 'react-native-htmlview';
class App extends React.Component {
render() {
const htmlContent = 'This is a sentence <b>with</b> one word in bold';
return (
<HTMLView
value={htmlContent}
/> );
}
}
Supports almost all html tags.
For more advanced usage like
Link handling
Custom Element Rendering
View this ReadMe
You could just nest the Text components with the required style. The style will be applied along with already defined style in the first Text component.
Example:
<Text style={styles.paragraph}>
Trouble singing in. <Text style={{fontWeight: "bold"}}> Resolve</Text>
</Text>
Bold text:
<Text>
<Text>This is a sentence</Text>
<Text style={{fontWeight: "bold"}}> with</Text>
<Text> one word in bold</Text>
</Text>
Italic text:
<Text>
<Text>This is a sentence</Text>
<Text style={{fontStyle: "italic"}}> with</Text>
<Text> one word in italic</Text>
</Text>
I am a maintainer of react-native-spannable-string
Nested <Text/> component with custom style works well but maintainability is low.
I suggest you build spannable string like this with this library.
SpannableBuilder.getInstance({ fontSize: 24 })
.append('Using ')
.appendItalic('Italic')
.append(' in Text')
.build()
for example!
const TextBold = (props) => <Text style={{fontWeight: 'bold'}}>Text bold</Text>
<Text>
123<TextBold/>
</Text>
<Text>
<Text style={{fontWeight: "bold"}}>bold</Text>
normal text
<Text style={{fontStyle: "italic"}}> italic</Text>
</Text>
There seems to be one or two components out there like react-native-markup-text, but if you don't mind using regular expressions to parse small markup.
Snack Demo
import * as React from 'react';
import { Text, View, StyleSheet, Image } from 'react-native';
/**
* #typedef MiniMarkupTextProps
* #type {object}
* #property {string|null|undefined} text - a piece of mini markup text.
* #property {object|null|undefined} itemStyle - itemStyle;
*/
export default React.memo((/** #type {MiniMarkupTextProps} */ props) => {
const markup = props.text;
const mappings = new Map([
[
'p',
(text, index) => {
return (
<Text key={index} style={props.itemStyle}>
{text}
</Text>
);
},
],
[
'b',
(text, index) => {
return (
<Text key={index} style={[{ fontWeight: 'bold' }, props.itemStyle]}>
{text}
</Text>
);
},
],
]);
const keys = Array.from(mappings.keys());
const regExp = new RegExp(
`(${keys.map((e) => `<${e}>`).join('|')})(.*?)(${keys
.map((e) => `<\\/${e}>`)
.join('|')})|(\\s*)`,
'g'
);
return (
<Text>
{markup?.match(regExp)?.map(function (tag) {
const isEmpty = tag.trim().length === 0;
return isEmpty ? (
<Text> </Text>
) : (
tag?.match(/<[a-z]>/g)?.map(function (t, index) {
const text = tag.replace(/<[^>]+>/g, '');
return (
mappings.get?.(t.replace(/<|>/g, ''))?.(text, index) ?? null
);
})
);
})}
</Text>
);
});
Usage
<MiniMarkupText
text="<p>This is a simple</p> <b>test</b> <p>and it could be useful</p> <b>. Then again it all depends...</b>"
itemStyle={{ color: 'red', textAlign: 'center'}}
/>
Nesting Text components is not possible now, but you can wrap your text in a View like this:
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
<Text>
{'Hello '}
</Text>
<Text style={{fontWeight: 'bold'}}>
{'this is a bold text '}
</Text>
<Text>
and this is not
</Text>
</View>
I used the strings inside the brackets to force the space between words, but you can also achieve it with marginRight or marginLeft. Hope it helps.
This worked for me
<h2>
{`Step ${activeStep+1}/3 - `} <strong>{stepName}</strong>
</h2>
//output Step 1/3 - Information