TouchableWithoutFeedback breaks ScrollView. How to fix without putting view inside ScrollView? - ios

I'm trying to get a TouchableWithoutFeedback wrapped ScrollView work.
In the real problem I'm unable to access the ScrollView.
Here's a working Expo Snack for easy testing.
And here's the code.
import * as React from 'react';
import {
Text,
View,
StyleSheet,
ScrollView,
FlatList,
TouchableWithoutFeedback,
} from 'react-native';
import Constants from 'expo-constants';
import LongText from './components/LongText';
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1, paddingTop: Constants.statusBarHeight }}>
{/* https://stackoverflow.com/a/46606223/25197
BROKE on iOS
*/}
<TouchableWithoutFeedback onPress={() => console.log('Pressed 2')}>
<View style={[styles.container, { borderColor: 'red' }]}>
<Text style={styles.label}>
{'2) Touchable > View > View > ScrollView\n'}
{' - iOS: BROKE\n - Android: WORKING\n'}
</Text>
<View
style={{ flex: 1 }}
onStartShouldSetResponder={() => true}
// onStartShouldSetResponderCapture={() => true}
onResponderGrant={() => console.log('Granted View 2')}>
<ScrollView
style={{ flex: 1 }}
keyboardShouldPersistTaps={true}
onResponderGrant={() => console.log('Granted ScrollView 2')}>
<LongText />
</ScrollView>
</View>
</View>
</TouchableWithoutFeedback>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
borderWidth: 5,
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
label: { fontWeight: 'bold' },
});
The ScrollView works as expected on Android.
How can I get it working on iOS?
In the real problem I'm unable to access the ScrollView.

Snack working link https://snack.expo.io/#mehran.khan/touchable-wrapped-scrollview
You should change this code
<View
style={{ flex: 1 }}
onStartShouldSetResponder={() => true}
// onStartShouldSetResponderCapture={() => true}
onResponderGrant={() => console.log('Granted View 2')}>
<ScrollView
Add onStartShouldSetResponder={() => true} to View instead of Scrollview
<ScrollView
style={{ flex: 1 }}>
<View onStartShouldSetResponder={() => true}><LongText /></View>
</ScrollView>
App Preview

Related

Keyboard not being dismissed with Keyboard.dismiss in React Native

I'm looking to dismiss the keyboard when the user clicks on anywhere outside the keyboard or the input, but the keyboard is not being dismissed when I click elsewhere:
<TouchableWithoutFeedback style={styles.container} onPress={Keyboard.dismiss}>
<View style={styles.inputContainer}>
<TextInput
placeholder="Search Term"
style={styles.input}
onChangeText={setSearch}
value={search}
returnKeyType="search"
onSubmitEditing={handleSubmit}
/>
</View>
</ TouchableWithoutFeedback>
The styling is pretty standard:
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
inputContainer: {
position: 'absolute',
top: stackHeaderHeight + 10,
height: height * .1,
width: '100%',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
You need to change your onPress code of TouchableWithoutFeedback
<TouchableWithoutFeedback style={styles.container} onPress={()=> Keyboard.dismiss()}>
</ TouchableWithoutFeedback>
Sample working code.
render() {
return (
<TouchableWithoutFeedback onPress={()=>Keyboard.dismiss()} >
<View style={{ flex: 1 }}>
<TextInput returnKeyType="search" style={{borderWidth:1,borderColor:'grey',marginTop:100,height:50,marginHorizontal:50}}/>
</View>
</TouchableWithoutFeedback>
);
}
I think you have a problem with your style properties. Please check on your container and inputcontainer style properties. If you have any ScrollView in your render method add following
<ScrollView keyboardShouldPersistTaps='always'>

React native IOS InputAccessoryView disappear from the screen after close modal

When I have on my screen InputAccessoryView which has component without nativeID (So it is constantly showing even if the keyboard is not shown) and I open and close Modal (react-native modal) then InputAccessoryView disappear from the screen with the component. I don't know why this is happening and also I don't know how to keep this InputAccessoryView on the screen.
Here is the code to reproduce it:
import * as React from 'react';
import { View, ScrollView, AppRegistry, TextInput, InputAccessoryView, Button } from 'react-native';
import {Modal, Text, TouchableHighlight, Alert} from 'react-native';
import Constants from 'expo-constants';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: 'Placeholder Text', modalVisible: false,};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{flex:1}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{marginTop: 22, padding: 50, backgroundColor: '#0066ff'}}>
<View>
<TouchableHighlight
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text style={{color:"#ffffff"}}>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
<ScrollView style={{ backgroundColor: '#6ED4C8'}}>
<Text></Text>
<TouchableHighlight
onPress={() => {
this.setModalVisible(true);
}}>
<Text style={{padding: 40, backgroundColor: "#ff3300"}}>Show Modal</Text>
</TouchableHighlight>
</ScrollView>
<InputAccessoryView backgroundColor="#ff9900" >
<TextInput
style={{
padding: 20,
paddingTop: 50,
}}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
</InputAccessoryView>
</View>
);
}
}
Here you can find the online version (Keep in mind that the issue is only relevant for IOS):
https://snack.expo.io/SJB7ipm6B
Some Images:
Thank you for your time and your help!
Try with this. I am re-rendering InputAccessoryView once the modal is closed
{(!this.state.modalVisible) && <InputAccessoryView backgroundColor="#ff9900">
<TextInput
style={{
padding: 20,
paddingTop: 50,
}}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
</InputAccessoryView>}
I just hit the same issue. After digging around for a while I figured out that setting the presentationStyle prop to overFullScreen on the modal fixes it for me without re-rendering the InputAccessoryView.

Text exceeds View on Iphone

Check this snippet:
import React, { Component } from 'react';
import { Text, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View style={{margin: 80}}>
<View style={{ padding: 5, backgroundColor: 'honeydew', borderWidth: '1', borderColor: 'black'}}>
<View style={{margin:5, flexDirection: 'row'}}>
<View>
<Text style={{width:50}}>Test </Text>
</View>
<View style={{backgroundColor:'yellow'}}>
<Text>this text exceeds the bordered view on iphone, should just wrap and fill the view</Text>
</View>
</View>
</View>
</View>
);
}
}
The text with yellow background is rendered partially outside the view with the black border.
This can be tested here: https://snack.expo.io/HJRRjutuW
Why doesn't it render properly? And what should I change so it does?
Just remove flexDirection: 'row' from
<View style={{margin:5, flexDirection: 'row'}}>
also updated snack
https://snack.expo.io/rJ6N8tKdb
Or you can add flexWrap
<View style={{margin:5, flexDirection: 'row',flexWrap: 'wrap'}}>
output will be like
EDIT
import React, { Component } from 'react';
import { Text, View} from 'react-native';
export default class App extends Component {
render() {
return (
<View style={{margin: 80}}>
<View style={{ padding: 5, backgroundColor: 'honeydew', borderWidth: '1', borderColor: 'black'}}>
<View style={{margin:5, flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between'}}>
<View >
<Text style={{width:50}}>Test </Text>
</View>
<View style={{flex:1,backgroundColor:'yellow'}}>
<Text>this text exceeds the bordered view on iphone, should just wrap and fill the view</Text>
</View>
</View>
</View>
</View>
);
}
}
If I measure the screenwidth and subtract the rest from it, it looks like I want it to, but this is not an elegant solution:
https://snack.expo.io/r1xCX5td-
import React, { Component } from 'react';
import { Text, View, Dimensions} from 'react-native';
export default class App extends Component {
render() {
let stretchWidth = Dimensions.get('window').width - 240;
return (
<View style={{margin: 80}}>
<View style={{ padding: 5, backgroundColor: 'honeydew', borderWidth: '1', borderColor: 'black'}}>
<View style={{margin:5, flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between'}}>
<View style={{flexDirection: 'row'}}>
<Text style={{width:50}}>Test</Text>
</View>
<View style={{width:stretchWidth,backgroundColor:'yellow'}}>
<Text>this text exceeds the bordered view on iphone, should just wrap and fill the view</Text>
</View>
</View>
</View>
</View>
);
}
}

React Native button does not work on iPhone 7

I am using react-native-deck-swiper and have cards with buttons on them. The buttons do not work on iPhone 7 only. Tried several phones. What's even more interesting is that react-native-tinder-swipe-cards has the same issues, so it seems to be something that I'm doing wrong. Code:
import React from 'react';
import {Alert, Text, TouchableHighlight, View, StyleSheet} from "react-native";
import Swiper from "react-native-deck-swiper";
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Swiper
ref='swiper'
cards={['asdf','23423']}
renderCard={(question) => {
return (
<TouchableHighlight
onPress={() => Alert.alert('I work')}>
<Text> {question} </Text>
</TouchableHighlight>
)
}}
cardIndex={0}
>
</Swiper>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Same code without swiper works fine:
import React from 'react';
import {Button, Alert, Text, TouchableHighlight, View, StyleSheet} from "react-native";
import Swiper from "react-native-deck-swiper";
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={() => Alert.alert('asdf')}>
<Text> I like pants </Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
I highly appreciate any help. Thanks!

Stack two buttons like in a horizontal UIStackView in React Native

I have a login form with two text inputs stacked vertically and a container view with two buttons below the inputs:
I want the two buttons to stretch to fill the width of the button container (red), so each button would take half its size. However I can't get it to work. I've tried various combinations of flex* properties with no luck.
In native iOS I would use a UIStackView for this with orientation = horizontal. React Native documentation says that pretty much any layout can be achieved with flexbox.
This is what my component looks like right now:
import React, {Component} from 'react';
import {KeyboardAvoidingView, TextInput, View, StyleSheet} from 'react-native';
import Button from 'react-native-button';
export default class Login extends Component {
render() {
return (
<KeyboardAvoidingView style={styles.container}>
<TextInput
placeholder="LOGIN"
placeholderTextColor="#505050"
style={styles.input}/>
<TextInput
placeholder="PASSWORD"
placeholderTextColor="#505050"
style={styles.input}/>
<View style={styles.buttonContainer}>
<Button
onPress={() => this.logIn()}
style={[styles.button, styles.loginButton]}>
Log in
</Button>
<Button
onPress={() => this.register()}
style={[styles.button, styles.registerButton]}>
Register
</Button>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 16,
backgroundColor: 'lightgray'
},
input: {
height: 40,
marginBottom: 12,
paddingHorizontal: 8,
backgroundColor: 'white'
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red'
},
button: {
padding: 8,
color: 'white',
backgroundColor: 'steelblue'
},
loginButton: {
marginRight: 8
}
});
If I add flex: 1 to the button style they become:
What am I doing wrong?
Yes. Its because of the react-native-button component. You have to use the containerStyle property of the Button component to style the container.
import React, {Component} from 'react';
import {KeyboardAvoidingView, TextInput, View, StyleSheet} from 'react-native';
import Button from 'react-native-button';
export default class Login extends Component {
render() {
return (
<KeyboardAvoidingView style={styles.container}>
<TextInput
placeholder="LOGIN"
placeholderTextColor="#505050"
style={styles.input}/>
<TextInput
placeholder="PASSWORD"
placeholderTextColor="#505050"
style={styles.input}/>
<View style={styles.buttonContainer}>
<Button
onPress={() => this.logIn()}
style={styles.buttonText}
containerStyle={styles.button}
>
Log in
</Button>
<Button
onPress={() => this.register()}
style={styles.buttonText}
containerStyle={styles.button}
>
Register
</Button>
</View>
</KeyboardAvoidingView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 16,
backgroundColor: 'lightgray'
},
input: {
height: 40,
marginBottom: 12,
paddingHorizontal: 8,
backgroundColor: 'white'
},
buttonContainer: {
height: 60,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red'
},
button: {
flex: 2,
padding: 8,
backgroundColor: 'steelblue',
alignSelf: 'stretch',
justifyContent: 'center',
},
buttonText: {
color: 'white',
}
});

Resources