I am trying to create a small tooltip in react native. For the most part it works. But want to use alignself, to auto size the view that contains text. It works with position relative, but that pushes the content away. Position absolute puts all the text inside the tooltip below each other and the tooltip is very narrow.
I have seen some modules for react native tooltip, but those use actions, and I just need to use text.
Anybody an idea on how to get this working?
The is what I have:
constructor(props) {
super(props);
this.state = {
visible: false,
};
}
toggleStatus() {
this.setState({visible: true});
setTimeout(() => {
this.setState({visible: false});
}, 3000);
}
toolTip = () => {
return (
<View style={styles.containerMain}>
{renderIf(this.state.visible,
<View style={styles.tooltipWrapper}>
<Text style={styles.tooltipStyle}>{this.props.tooltipText}</Text>
</View>
)}
<View style={styles.questionMarkWrapper}>
<TouchableOpacity disabled={this.state.visible} onPress={()=>this.toggleStatus()}>
<Text style={styles.questionMark}>?</Text>
</TouchableOpacity>
</View>
</View>
)
}
render() {
return (
<View style={styles.containerStyle}>
{this.toolTip()}
</View>
)
}
And styling I use:
containerMain: {
alignItems: 'flex-end',
},
tooltipWrapper: {
position: 'absolute',
top: 0,
right: 10,
padding: 5,
borderRadius: 4,
backgroundColor: 'rgba(0,0,0,0.6)',
},
tooltipStyle: {
fontSize: 11,
color: 'white',
},
questionMarkWrapper: {
justifyContent: 'center',
flexDirection: 'row',
marginRight: 10,
},
questionMark: {
fontSize: 16,
color: 'rgba(255,255,255,0.4)',
borderRadius: 50,
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.4)',
borderStyle: 'solid',
height: 26,
width: 26,
paddingLeft: 9,
paddingTop: 2,
}
This is how the tooltip should look like (not the actual location):
And this is how it looks like now:
Related
I'm implementing a custom header for #react-navigation/native-stack. Using React Navigation v6.
One of the elements within the custom header has a native shadow on iOS added (via the style prop). The shadow is a tad bigger than the header and unfortunately, I can't get it to display beyond the boundaries of the header. Of course, I've tried using overflow: visible on basically every component in the tree, but no success. The shadow is clipped off:
Here's my custom header:
function CustomHeader(props: NativeStackHeaderProps) {
const { options, route, navigation } = props;
const insets = useSafeAreaInsets();
const headerHeight = Helpers.getHeaderHeight(insets);
return (
<View style={{
height: headerHeight,
paddingTop: insets.top,
width: '100%',
backgroundColor: Colors.white,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingLeft: 20,
paddingRight: 20,
overflow: 'visible',
}}
>
<View style={{
flex: 1, display: 'flex', alignItems: 'flex-start',
}}
>
{ options.headerLeft ? options.headerLeft({ canGoBack: false }) : (
<TouchableOpacity
onPress={() => route.name === 'Home'
? null
: navigation.reset({ index: 0, routes: [{ name: 'Home' }] })}
>
<Image
style={{ width: Sizing.logo, height: Sizing.logo }}
source={Logo}
/>
</TouchableOpacity>
)}
</View>
<Text style={{
textAlign: 'center', color: Colors.purple,
}}
>
{(options.title || route.name).toUpperCase()}
</Text>
<View style={{
flex: 1, display: 'flex', alignItems: 'flex-end', overflow: 'visible',
}}
>
{ options.headerRight ? options.headerRight({ canGoBack: false }) : null}
</View>
</View>
);
}
The button on the right with the shadow is passed in through the headerRight option and contains this shadow style:
nativeShadow: {
shadowColor: Colors.gray,
shadowOffset: { width: 0, height: 8 },
shadowRadius: Colors.shadows.gray.distance,
shadowOpacity: 0.5,
},
Any idea what I could try next? I don't want to increase the headers' height since this would break the layout elsewhere.
I had a similar problem with the menu. I think i was taking another way and maybe you should try it.
Be sure that all the parent elements has at least the same height than the navmenu's height.
import React, { Component } from 'react';
import { TouchableOpacity, StyleSheet, Image, View, Text } from 'react-native';
const styles = StyleSheet.create({
menuParent: {
marginLeft: 30,
justifyContent: "flex-start",
alignItems: "flex-end",
flex: 1,
height: 250
},
btnContainer: {
width: 40,
height: 40,
elevation: 50,
zIndex: 50,
marginTop: 5
},
image: {
width: 40,
height: 40,
},
menuContainer: {
position: "absolute",
top: 5,
left: -5,
right: -5,
padding: 20,
borderRadius: 10,
elevation: 10,
zIndex: 10,
flex: 1,
height: 230,
backgroundColor: "#fff",
}
});
export default class DefaultHeaderMenu extends Component {
state = {
menuVisible: false
};
constructor(props) {
super(props);
}
render() {
return (
<View style={ styles.menuParent }>
{this.state.menuVisible ? <View style={ styles.menuContainer }></View> : null }
<TouchableOpacity
style={ styles.btnContainer }
onPress={ () => this.setState({ menuVisible: !this.state.menuVisible }) }
>
<Image
source={ require('#/assets/img/menu.png') }
style={ styles.image }
/>
</TouchableOpacity>
</View>
);
}
}
This is the component i used and the passed it to nav as headerRight element.
In my case, the problem was that height: 250 was missing in menuParent.
I hope it helps you and good luck
I had a problem like this once and fixed it by using 'zIndex'. Try setting it as the* max index in your project. Hope it helps
I'm practicing some react native code and I'm currently stuck with an overlapping problem.I've got this custom component:
const MobileNumberInput = ({ value, valueChanged, placeholder, valid }) => {
return (
<View style={{ flexDirection: "row", flex: 1 }}>
<TextInput
editable={false}
style={[styles.textBoxCountryCode, !valid ? styles.invalidTextBox : ""]}
value="+90"
/>
<TextInput
style={[styles.textBoxPhoneNumber, !valid ? styles.invalidTextBox : ""]}
placeholder={placeholder}
value={value}
onChangeText={valueChanged}
keyboardType="number-pad"
maxLength={9}
/>
</View>
);
};
export default MobileNumberInput;
onst styles = StyleSheet.create({
container: {
flexDirection: "row",
flex: 1,
height: 40
},
textBoxCountryCode: {
height: 40,
borderColor: "gray",
borderTopWidth: 1,
borderBottomWidth: 1,
borderLeftWidth: 1,
borderTopLeftRadius: 5,
borderBottomLeftRadius: 5,
padding: 5,
flex: 2
},
textBoxPhoneNumber: {
height: 40,
borderColor: "gray",
borderTopWidth: 1,
borderBottomWidth: 1,
borderRightWidth: 1,
borderTopRightRadius: 5,
borderBottomRightRadius: 5,
paddingTop: 5,
paddingRight: 5,
paddingBottom: 5,
marginBottom: 10,
flex: 11
},
invalidTextBox: {
borderColor: "red"
}
});
And here, I'm using that component:
renderError = id => {
const { validationErrors } = this.state;
if (validationErrors[id]) {
return (
<Text style={styles.validationError}>{validationErrors[id][0]}</Text>
);
}
return null;
};
render() {
const keyboardVerticalOffset = Platform.OS === "ios" ? 40 : 0;
return (
<View style={styles.container}>
<KeyboardAvoidingView
behavior="padding"
style={styles.textBoxContainerContainer}
keyboardVerticalOffset={keyboardVerticalOffset}
>
<View style={styles.textBoxContainer}>
<TextBoxMA
style={styles.textBox}
placeholder={Strings.USERNAME_PLACEHOLDER}
value={this.state.userName}
onChangeText={this.handleTextChange("userName")}
valid={this.fieldIsValid("userName")}
/>
{this.renderError("userName")}
</View>
<View style={styles.textBoxContainer}>
<MobileNumberInput
value={this.state.originalMobile}
valueChanged={this.handleTextChange("originalMobile")}
placeholder={Strings.ORIGINAL_MOBILE_PHONE_PLACEHOLDER}
valid={this.fieldIsValid("originalMobile")}
/>
{this.renderError("originalMobile")}
</View>
</KeyboardAvoidingView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
padding: 20
},
textBoxContainerContainer: {
flex: 4,
justifyContent: "flex-end"
},
textBoxContainer: {
height: 40,
marginBottom: 20
},
validationError: {
fontSize: 12,
color: "red",
fontWeight: "bold",
paddingTop: 3
}
});
The {this.renderError("originalMobile")} portion is responsible for rendering an error text.
I put it there to get a small red warning just under the text box. But the warning stretches to inside mobile number component while the username warning is displayed correctly. Here's the output:
I've tried wrapping the error Text inside another View, didn't help. Wrapped the container View inside the MobileNumberInput component into yet another View with explicit flex-direction ="column". It didn't help either. I even changed the flex-direction of that container View to "column" just to see what would happen. But it didn't have any effect either. As you can see from the screenshot the problem is with the MobileNumberInput component part. The error text for the Username textinput is ok.
And if you wonder what the TextBoxMA looks like, it's just a TextInput component with predefined properties. Here it is:
export const TextBoxMA = props => {
return (
<TextInput
secureTextEntry={props.isPassword || false}
{...props}
style={[
props.style,
styles.textBox,
Platform.OS === "ios" ? styles.textBoxIos : styles.textBoxAndroid,
!props.valid ? styles.invalidTextBox : ""
]}
/>
);
};
const styles = StyleSheet.create({
textBox: {
height: 40,
borderColor: "gray",
borderWidth: 1,
borderRadius: 5,
padding: 5
},
invalidTextBox: {
borderColor: "red"
}
});
You've set your input height to 40, but then the View with style styles.textBoxContainer which wraps both input and error text, is also set to 40 height, squishing MobileNumberInput in half. You can't visually notice this effect because TextInputs inside MobileNumberInput go outside of the parent
To handle cases like this you need to create one container to wrap TextInputs and another container to wrap the first container and the error text. It's best to not set explicit height for containers but rather set their paddings to get desired size
I have integrated React Native navigation package. I want to add badge with the dynamic value on my topBar rightButton.
Github link of the package:: https://github.com/wix/react-native-navigation
I want an output like this. You can check this screenshot::
Issue::
If I am adding a count value on notification icon then there is no event occurs when I am trying to click on button. On click of this button I want to open up my notification screen.
Code:
static options({ menuIcon }) {
return {
topBar: {
title: {
fontFamily: font,
fontSize: fontSize.heading,
color: colors.white,
alignment: 'center',
text: strings.dashboard
},
alignment: 'center',
elevation: 0,
noBorder: true,
background: {
color: colors.dark
},
leftButtons: [
{
id: 'openSideMenu',
icon: menuIcon ? menuIcon : APIURLServiceSingleton.getInstance()._menuIcon
}
],
rightButtons: [
{
id: 'notificationButton',
component: {
name: 'component.notificationButton'
}
}
]
}
}
}
Code for my custom component::
<TouchableOpacity
onPress={() => this.openSystemAlerts()}
style={{ position: 'absolute', right: 0, bottom: -13 }}
>
<View style={styles.button}>
<View style={[posRelative]}>
<Icon
name="notifications-none"
size={27}
color={colors.white}
/>
{(unseen_count && unseen_count > 0) &&
<Text style={styles.badge}>{unseen_count}</Text>
}
</View>
</View>
</TouchableOpacity>
Environment
React Native Navigation version: 2.12.0
React Native version: 0.58
Platform(s) : IOS only(on version 10.0)
It seems that, position:'absolute' is creating problem,
Either ,
add zIndex:2 ...here, number must be greater than any other zIndex in its parent or if there is not any zIndex used then any number>0 is fine.
or
remove position:'absolute' and try styling without it.
try this component; worked fine for me
https://github.com/RajenderDandyal/smart-city-Mobile-App/blob/master/src/UI/TopBarCartCount/index.js
`
class TopBarCartCount extends Component {
handleCartPress = () => {
if (!this.props.isAuthenticated) {
NavigateUser(2, componentIds.myAccountStack, screenNames.signIn)
} else {
NavigateUser(2, componentIds.myAccountStack, screenNames.myCart)
}
};
render() {
return (
<View style={styles.containerWrapper}>
<TouchableOpacity onPress={this.handleCartPress}>
<View style={styles.container}>
{cartPlus}
<View style={styles.badge}>
<Text style={styles.countText}>
{this.props.cart.length}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
);
}
}
let mapStateToProps = (state) => {
return {
cart: state.auth.user.cart ? state.auth.user.cart : [],
isAuthenticated: state.auth.isAuthenticated
}
}
export default connect(mapStateToProps)(TopBarCartCount);
const styles = StyleSheet.create({
containerWrapper: {
flex: 1,
height: 40,
width: 50,
justifyContent: 'center',
paddingTop: 15,
paddingRight: 5,
alignItems: 'center'
},
container: {
flex: 1,
height: 40,
width: 50,
paddingLeft: 5,
flexDirection: 'row',
alignItems: 'flex-start'
},
badge: {
backgroundColor: themeConstants.danger,
width: 15,
height: 15,
alignItems: 'center',
justifyContent: 'center',
paddingLeft: 0,
paddingTop: 1,
paddingBottom: 2,
marginLeft: 0,
borderRadius: 10
},
countText: {
fontSize: 10,
paddingLeft: 0,
color: themeConstants.offWhite
}
});`
I have a problem with my react native layout iPhone 5c.
But iPhone 7 and iPad look good.
How to fix it?
My buttons code:
_renderButton(title, onPress, active) {
var style = (active) ? styles.activeButtonText : styles.buttonText;
return (
<TouchableHighlight style={styles.button} onPress={onPress}>
<Text style={style}>
{title}
</Text>
</TouchableHighlight>
);
}
render() {
return (
<View style={styles.container}>
<View style={styles.controls}>
{this._renderButton("LISTEN", () => {this._playOriginalAudio()})}
{this._renderButton(this.state.recordingText, () => {this._record()}, this.state.recording )}
{this._renderButton("LISTEN TO RECORDING", () => {this._play()} )}
{this._renderButton("SUBMIT", () => {this._send()} )}
</View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#2b608a",
},
controls: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
button: {
padding: 20
},
disabledButtonText: {
color: '#eee'
},
buttonText: {
fontSize: 20,
color: "#fff"
},
activeButtonText: {
fontSize: 20,
color: "#B81F00"
},
points: {
backgroundColor: 'transparent',
position: 'absolute',
top: 72,
left: 56,
width: 90,
textAlign: 'center',
color: '#69d2e7',
fontSize: 50,
fontWeight: "100"
},
headerText: {
paddingBottom: 10,
fontSize: 20,
color: "#69d2e7"
}
});
I've tried to test app with iPhone 5 simulator, and I have no any style problem. Looks like the problem only with real iPhone 5 device. Maybe it is bug.
It might help to see your specific style sheet, but I am guessing you would benefit by importing the Dimensions module that React Native provides.
Dimensions Module
Then you can get the height and width of the device your app is running on, to change the styles appropriately.
class Main extends Component {
constructor(props) {
super(props)
this.state = {
id: '',
password: '',
}
console.log('yes')
this._handleTextChange = this._handleTextChange.bind(this)
}
_handleTextChange(id, text) {
console.log(text)
var newState = Object.assign({}, this.state);
var newState = Object.assign({}, this.state);
newState[id] = text
this.setState(newState)
}
render() {
console.log('ass')
return (
<View style={MainStyle.justFlexOne}>
<View style={MainStyle.coverImageWrapper}>
<Image source={require('../assets/images/cursive.jpg')} style={MainStyle.coverImage}/>
</View>
<View style={MainStyle.mainBackground}>
<TouchableHighlight>
<Text style={MainStyle.bigFontDefault}>
Comma
</Text>
</TouchableHighlight>
<TextInput
style={MainStyle.TextInputs}
value={this.state.id}
editable={true}
onChangeText={(text) => {console.log('asdf');this.setState({id:text})}}
placeholder='text'
/>
</View>
</View>
)
}
}
const MainStyle = StyleSheet.create({
justFlexOne: {
flex: 1,
},
mainBackground: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent',
},
bigFontDefault: {
color: '#fafafa',
fontSize: 60,
textShadowOffset: {width: 0, height: 1},
textShadowRadius: 8,
textShadowColor: 'rgba(21,42,55,0.4)',
fontFamily: 'Optima-Italic',
fontWeight: '500',
},
coverImageWrapper: {
position: 'absolute',
top: 0, left: 0, bottom: 0, right: 0,
},
coverImage: {
flex: 1,
width: null,
height: null,
resizeMode: 'cover',
},
textInputs: {
height: 40,
width: 200,
color: '#fcc439',
backgroundColor: 'rgba(0,0,0,0.4)',
borderColor: '#fcc439',
}
})
Problem is, I can't focus into TextInput on iOS Simulator operated by XCode(Version 8.2.1).(it means I can't type some characters in input.) I have done what I can handle (like click, enter etc...) using mac keyboard, trackpad even apple mouse. In despite of Connect hardware Keyboard is turned on.
Also StyleSheet doesn't work on TextInput as well.(it works well on other component.)
How can I fix this problem??
change
style={MainStyle.TextInputs}
to
style={MainStyle.textInputs}