Problems with TouchableOpacity not working with position:"absolute" - javascript

first time posting.
I am creating a kind of popup menu to select a color for a draggable object.
I've created the components and it's all working fine, except for the fact that I can't click the buttons, or nothing happens when I do.
at the moment I am using the package: 'react-native-easy-gestures' as I was too time-consuming to create the panhandlers myself for this project
Because I am using draggable components, the half circle of colors are positioned around a view that is set to position: 'absolute', and I think that's the problem.
This is my style for the popover component (plus i dynamically set the top and left positions when mapping through the colors.
and there is of course a higher leveled style for the actual "item" that I can drag which is all placed inside the Gesture component from the node modules mentioned above.
button: {
height: '100%',
width: '100%',
justifyContent: 'center',
alignItems: 'center',
zIndex: 6,
},
buttonView: {
position: 'absolute',
zIndex: 5,
},
popoutMenu: {
position: 'absolute',
alignSelf: 'center',
alignContent: 'center',
justifyContent: 'center',
},
Screenshot of the menu and item
I do believe that the problems lies in how absolute is working. I have the buttons inside their own view at the moment, but I also tried by just having them alone, still, nothing :/
Any help would be much appreciated

So I figured it out eventually. First I changed to using the TouchableOpacity from 'react-native-gesture-handler' and then I created a View inside of this touchable that has the dimensions (width and height) of the "button" and it seems to work quite well now.
The problem was as far as I can understand that the touchableXs usually take the style components of their child, so since I didn't really have any children inside of it, the button was just not there.
I also used the one from a different package as it allowed me to set the zIndex of the button without affecting if it is clickable.
At the moment I placed an Icon inside of it, but I am considering removing it and just creating a circle from the view with borderRadius.
Above here is a map function that goes through all my colors from an array.
<View
key={color}
style={[
styles.button,
{
top: coords.y - buttonSize / 2,
right: coords.x - buttonSize / 2,
height: buttonSize,
width: buttonSize,
padding: 5,
borderRadius: buttonSize,
// backgroundColor: 'red',
},
]}>
<TouchableOpacity
color={color}
onPress={() => {
!isExitButton
? !isResetButton
? setTintColor(color)
: setTintColor(null)
: setPopoutActive(false);
}}>
<View
style={[
styles.circleInTouchable,
{
width: buttonSize,
height: buttonSize,
},
]}>
<Icon
name={'circle'}
solid
size={buttonSize}
color={color}
/>
</View>
</TouchableOpacity>
</View>

Import TouchableOpacity from react-native-gesture-handler instead react-native.
import { TouchableOpacity} from 'react-native-gesture-handler'

Related

Is there a way to decrease the height of dropdown picker (react-native-dropdown-picker module)

Dropdown Picker Screenshot
There is no problem in increasing its height but I want to style the container to decrease its height. I have tried changing all the props with style properties but I still can't decrease its height. This is my code below.
import {
ThemeProvider,
createTheme,
Header,
Text,
SocialIcon,
Button,
Divider,
Overlay,
SearchBar,
ListItem,
Avatar,
} from '#rneui/themed';
import DropDownPicker from 'react-native-dropdown-picker';
// code here
<View>
<View>
<Text
style={{
fontSize: 14,
color: COLORS.gray_header2,
}}>
Label 2:
</Text>
<DropDownPicker
open={open}
value={value}
items={items}
setOpen={setOpen}
setValue={setValue}
setItems={setItems}
style={styles.dropdown_container}
textStyle={styles.dropdown_itemstyle}
/>
</View>
</View>
//code here
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
dropdown_container: {
width: '100%',
backgroundColor: COLORS.dirty_white,
borderRadius: 6,
borderColor: COLORS.gray_filter,
},
dropdown_itemstyle: {
color: COLORS.gray_header,
borderColor: COLORS.gray_filter,
marginLeft: 10,
},
});
Dropdown Picker Screenshot with react-devtools
Upon using react-devtools module, I have debugged where the height could be changed. Is there any way to decrease its height? (apparently minHeight in devtools)
Edit
Height of the container itself (not the dropdown menu when clicked)
If anyone is having the issue of size, minHeight worked for me. See example below.
<DropDownPicker
style={{
borderWidth: 1,
borderColor: '#d5d5d9',
backgroundColor: '#eee',
borderRadius: 40,
paddingHorizontal: 5,
minHeight: 30, // <---- here
}}
/>
You have to set minHeight and paddingHorizontal in your dropdown_container. In this way you will be able to decrease the height of your dropdown.
dropdown_container: {
width: '100%',
backgroundColor: COLORS.dirty_white,
borderRadius: 6,
borderColor: COLORS.gray_filter,
paddingHorizontal: 5,
minHeight: 30,
},
Hi there try adding maxHeight as follow?
maxHeight={200}
Check out the docs from their website: https://hossein-zare.github.io/react-native-dropdown-picker-website/
As Glen suggested, maxHeight is your answer.
You can check the react-native-dropdown-picker source code in your node_modules folder, in src/themes/dark/index.js or src/themes/light/index.js. The author did a minHeight:50 for the container height in the stylesheet class which name is style. You can pass your own minHeight through DropDownPicker style property to override it.
I think same as the list Item, just find the correct style property and override it.
Min height is ignored because it looks like it is hardcoded in theme files.
A good exmaple is this MR - https://github.com/hossein-zare/react-native-dropdown-picker/pull/555
So I plan to create custom theme like it is described in docs https://hossein-zare.github.io/react-native-dropdown-picker-website/docs/advanced/themes

React Native : Subviews of KeyboardAvoidingView have lag / move at different speeds

I would like them all the subviews to move in one clean motion, but if you look at the gif, you can see that the Text subview and the TextInput subview overlap and move at different speeds. It looks like the Text subview adjusts its position instantly where as the button and TextInput subviews adjust their position in more of an Ease in Ease out manner.
Main exported component
class SearchScreen extends React.Component {
state = {search:""}
render(){
getArguments = {
search: this.state.search
}
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<Text style={styles.searchTitle}>Search for a Movie in the OMDB Database</Text>
<TextInput style={styles.searchField} onChangeText={text => this.setState({search:text})} ></TextInput>
<SearchButton navigation = {this.props.navigation} getArguments={getArguments}/>
</KeyboardAvoidingView>
)
}
}
Styling
const styles = StyleSheet.create({
container: {
flex:1,
backgroundColor: '#C8FEFE',
alignItems: 'center',
justifyContent: 'center'
},
searchButton: {
marginTop: 20,
backgroundColor: '#24D9E8',
borderRadius: 5,
padding: 5
},
searchField: {
backgroundColor: '#FFF',
textAlign: 'center',
width: 200,
borderRadius: 5,
margin: 20,
height: 30
},
searchTitle:{
fontWeight: 'bold',
fontSize: 20,
textAlign:'center'
}
});
Github
Full project on github
Solution 1: Quick fix for iOS
You can wrap your elements in a View, which will make them react to keyboard the way you want:
// styles
contentContainer: {
alignItems: 'center',
}
// SearchScreen
<View style={styles.contentContainer}>
<Text style={styles.searchTitle}>Search for a Movie in the OMDB Database</Text>
<TextInput style={styles.searchField} onChangeText={text => this.setState({search:text})} ></TextInput>
<SearchButton navigation = {this.props.navigation} getArguments={getArguments}/>
</View>
However, this will only work on iOS. Keyboard works slightly differently on Android. So solution 2 is a more solid way to do things.
Solution 2: Animations
Keyboard avoidance is quite tricky, Spencer Carli's article that Dominik referred to is a great resource for solutions using KeyboardAvoidingView. Those usually give you what you need. But if you want a smooth, controlled transition between keyboard states, you should use animations. The flow would go like this:
Add Keyboard event listeners to your component (keyboardDidShow and keyboardDidHide)
Wrap the content you want to move in an Animated.View
on keyboardDidShow, animate the y position of the Animated.View by the offset you want. The event returned (of type KeyboardEvent), along with the Dimensions API have all the measurements you need. Tip: use an Animated.timing animation with bezier Easing to control how the view moves.
on keyboardDidHide, repeat the animation but in the opposite direction.
Hope this helps!
<KeyboardAvoidingView keyboardVerticalOffset={Platform.OS === 'ios' ? 40 : 0}>
...
<KeyboardAvoidingView/>
You can try adding some offset to the view.
I would definitely style it with flexbox, try styling your container like this:
(it should move them at once, as flexbox will fit them on current width and height)
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;

How to put a sticky Touchable within an horizontal ScrollView in React Native?

I am trying to make a simple application/game to learn and practice React Native. Currently, I am trying to create a sticky TouchableNativeFeedback that moves with the screen as I am using the ScrollView.
The idea is that left half of the screen would move the character to the left and the right half of the screen would move it to the right. I want these controls to be fixed in the display and not move.
This is how it starts
This is after moving the scrollView a bit
I've initially tried to change value of style.left as I scrolled but that doesn't seem to be a good/stable solution.
Here is the current code:
render() {
return (
<ScrollView
//onScroll={this._onScroll}
ref={(scrollView) => { this.scrollView = scrollView; }}
style={styles.container}
horizontal= {true}
snapToAlignment={"center"}
>
<View style={styles.wrapperView}>
<ImageBackground
style={styles.container}
source={require('../images/second.png')}
>
<TouchableNativeFeedback onPressIn={this._onPressButton} onPressOut={this._onPressButton}>
<View style={
{
width: width/2,
height: '100%',
position: 'absolute',
left: this.state.touchableLeft,
backgroundColor: 'red',
}
}>
</View>
</TouchableNativeFeedback>
... (code about the character)
</ImageBackground>
</View>
</ScrollView>
);
}
and the styles code
const styles = StyleSheet.create({
container: {
width: '100%',
height: '100%',
},
wrapperView:{
width: width*3 + 300,
},
});
and just to have it as a reference, this is what I originally tried:
_onScroll = (event) => {
this.setState( {
touchableLeft: this.state.touchableLeft + event.nativeEvent.contentOffset.x
} )
}
I've looked at the following questions and articles but I couldn't really get to a solution that would help me. Usually people use flex to make their headers sticky above a ScrollView and that is incredibly handy but in this situation I am unsure about how to continue. Articles/Questions:
How to Get ListView Section Header to Stick
http://docs.nativebase.io/docs/examples/StickyHeaderExample.html
Sticky Component inside scrollview
What solved my problem was to take the TouchableNativeFeedback outside of the class. The class in the question was called Background and it was rendered in the class called App.
<View style={styles.container}>
<Background />
<TouchableNativeFeedback onPressIn={this._onPressButton} onPressOut={this._onPressButton}>
<View style={
{
width: '50%',
height: '100%',
position: 'absolute',
left:0,
//left: this.state.touchableLeft,
//backgroundColor: 'red',
}
}>
</View>
</TouchableNativeFeedback>
</View>
As you can see once I moved it to here, it was positioned right where I wanted, even if I move the screeen. What would be good practice, is to take it to another component class and then just call an instance of it.
Thanks to John Ruddell for the help while coming up with the solution

Lottie animation is very small compared to it's container in react native

I have an on click animation that is working perfectly, but I can't get the actual animated element to be more "zoomed" in. It looks like this:
Here's the code:
import { Animated, TouchableHighlight } from 'react-native';
import Animation from 'lottie-react-native';
// a bunch of code here
render() {
return (
<TouchableHighlight
onPress={this.animate}
underlayColor="transparent"
>
<Animation
style={{
backgroundColor: 'red',
width: 150,
height: 150,
}}
source={favoriteHeart}
progress={this.state.progress}
/>
</TouchableHighlight>
);
}
there's nothing funny going on with the parent View, so I'm really confused as to why the heart isn't taking the full width and height of the Animation view. This also makes placing this element next to either icons difficult.
You can try add some properties of Lottie Animation:
<Animation
style={{
backgroundColor: 'red',
width: 150,
height: 150,
}}
source={favoriteHeart}
progress={this.state.progress}
resizeMode = 'cover'
/>

The <Image> component cannot contain children. If you want to render content on top of the image, consider using absolute positioning

I am completing a tutorial on react native. For a certain screen, the instructor recommends the following code:
<Image source={bgImage} style={styles.backgroundContainer}>
<View style={styles.container}>
<Quote quoteText={this.props.text} quoteSource={this.props.source}/>
</View>
</Image>
But when I use this, I get the above error.
I've tried alternatives to this, but when I do, the background image doesn't even load.
EDIT: As requested below, here's my styling code. What I'm going for is using a background gradient image stored locally to the app code with text overlayed over that background. What I currently get by using the suggestion below is just the text at the very top of the screen and no background image.
const styles = StyleSheet.create({
backgroundContainer: {
flex: 1,
resizeMode: 'cover',
width: undefined,
height: undefined,
backgroundColor: '#889DAD',
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent',
},
});
Since react-native 0.50 you can't nest components inside <Image> tag, rather you have to use <ImageBackground> for background images. Release Notes for v0.50.0
You are not allowed to put other components inside an image component. You need to wrap a View around your Image and positioned it as absolute.
<View style={{ flex: 1}}>
<Image source={bgImage} style={styles.backgroundContainer} />
<View style={styles.container}>
<Quote quoteText={this.props.text} quoteSource={this.props.source}/>
</View>
</View>
container: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
justifyContent: 'center',
alignItems: 'center',
},
EDIT:
Since react-native version 50.0, you can simply use ImageBackground
Use
<ImageBackground
source={image}
style={styles.contentContainer} >
// Your view content goes here
</ImageBackground>
const styles = StyleSheet.create({
contentContainer: {
flex: 1,
},
});
Works like a charm

Categories

Resources