React-Native RefreshControl displaces Sticky Header iOS - ios

Having an issue inside a ListView that uses sticky headers. When I scroll down while the refresh is still occurring, my sticky header is shifted down roughly equal to the height of the refresh control.
Any idea what's causing this?
Here is the code for my ListView and the refreshControl:
<View style={{backgroundColor: Colors.stickyHeaderGray, height: SCREEN_HEIGHT-20}}>
<ListView
ref='list'
style={this.container}
dataSource={this.state.ds}
initialListSize={12}
scrollRenderAheadDistance={0}
onEndReached={() => this.setState({ hideLoadingFooter: true })}
onEndReachedThreshold={10}
pageSize={10}
renderRow={(data) => <FeedItem {...data} navigator={this.props.navigator} />}
renderSeparator={this._renderSeparator}
renderSectionHeader={(sectionData, sectionID) =>
<View style={{backgroundColor: Colors.stickyHeaderGray, opacity: 0.96}}>
<TouchableHighlight
onPress={() => this.refs.list.scrollTo({x:0,y:0,animated:true})}
underlayColor={Colors.stickyHeaderGray}>
<View>
<Heading1 style={styles.headers}>{sectionID}
</Heading1>
</View>
</TouchableHighlight>
</View>
}
renderFooter={() =>
this.state.hideLoadingFooter ? null : <View style={styles.footer}><Heading1>Loading </Heading1><Spinner type={'ThreeBounce'} size={40} color={Colors.wabashRed} isVisible={true} /></View>
}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
tintColor={Colors.charcoal}
/>
}
/>
</View>

Related

How to make the React Native app to ask if I want to save username and password? (iOS 11+)

Based on this excellent question and answer, I tried to implement autofill function in my app. While the username and password sections can be auto-filled (i.e, Above the keyboard, there is a password button, and once I press the button, Face ID is activated, and I can select an option), but it does not ask when I typed a username and password and pressed the sign in button.
Any suggestion is very appreciated!
import { useForm } from 'react-hook-form';
// Just in case
// "#react-navigation/bottom-tabs": "^5.4.2",
// "#react-navigation/native": "^5.2.6",
// "#react-navigation/stack": "^5.3.1",
...
export default function screen({navigation, route}) {
useEffect(()=> {
register("email");
register("password")
return () => {
console.log("Unmounted");
}
}, [register]);
...
return (
...
<View
style={[
styles.container,
styles.emailSection,
styles.paddingHorizontal,
]}>
<View style={styles.textInputContainer}>
<TextInput
onChangeText={text => {
setValue('email', text);
}}
placeholder={'Email'}
placeholderTextColor="grey"
keyboardType="email-address"
autoCapitalize={'none'}
autoCorrect={false}
textContentType={'username'}
style={styles.textInputFont}
/>
</View>
<View style={styles.textInputContainer}>
<TextInput
onChangeText={text => {
setValue('password', text);
}}
placeholder={'Password'}
placeholderTextColor="grey"
keyboardType="default"
autoCapitalize={'none'}
autoCorrect={false}
secureTextEntry={true}
textContentType={'password'}
style={styles.textInputFont}
/>
</View>
<View>
<TouchableOpacity
onPress={
isEmailLoading ? null : handleSubmit(_onPressEmailSignIn)
}>
<View style={[styles.wideButtonContainer]}>
<Text style={styles.secondaryFont}>Sign In</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.textContainer}>
<TouchableOpacity
onPress={() => navigation.navigate('ForgotPassword')}>
<View>
<Text style={styles.secondaryFont}>Forgot Password</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => navigation.navigate('EmailSignUp')}>
<View>
<Text style={styles.secondaryFont}>Sign Up</Text>
</View>
</TouchableOpacity>
</View>
</View>
...
)
- Tried on simulator (iPhone Xs (12.0) and my device (iPhone Xr (13.0))

How to use KeyboardAvoidingView with FlatList?

I have a FlatList component with an Input inside each row. When I select the input I want it to scroll up above the keyboard.
My code:
return (
<KeyboardAvoidingView behavior='padding' style={{ flex: 1 }} >
<FlatList
style={{ flex: 1, backgroundColor: '#fff' }}
data={ds}
renderItem={({ item }) => <ListItem data={item} />}
ListFooterComponent={this.renderButton}
/>
</KeyboardAvoidingView>
);
In this scenario, the FlatList is never loaded. When I delete flex:1 from both components, FlatList renders properly but selecting an Input does not make it scroll up
You can trying using react-native-keyboard-aware-scroll-view
https://github.com/APSL/react-native-keyboard-aware-scroll-view
It comes with KeyboardAware[ScrollView, ListView, SectionView, FlatList] which accepts the same props as their corresponding components from RN. I have used that and it worked for me.
render() {
return (
<KeyboardAwareFlatList
style={{flex: 1}}
data={this.state.data}
renderItem={({item}) => (
<View style={{flex: 1}}>
<Image
source={item.v}
style={{height:200, width: 200}}
/>
<TextInput
placeholder="enter text1"
/>
</View>
)}
/>
);
}
You could try using the library react-native-keyboard-spacer as an alternative to KeyboardAvoidingView.
Install:
npm install --save react-native-keyboard-spacer
Use it like this:
import KeyboardSpacer from 'react-native-keyboard-spacer'
...
<View style={{flex: 1}}>
<FlatList
style={{flex: 1}}
data={ds}
renderItem={({ item }) => <ListItem data={item} />}
/>
{/* The view that will expand to match the keyboard height */}
<KeyboardSpacer />
</View>
Try this:
<KeyboardAvoidingView behavior='position' keyboardVerticalOffset={xyz} >
You can remove the property 'keyboardVerticalOffset' or play with the value of xyz,
just find out the better value which fits in your case.
For anyone on a similar path as mine. I was not able to use KeyboardAvoidingView because it depends on ScrollView which conflicts with Flatlist. I couldn't used the header and footer option in Flatlist as I'm using it as a generated thing in a search selection box so it has to be contained.
For me there is a difference in how Android and iOS calculate absolute position. Android considers the bottom to be the top of the keyboard and iOS it is the bottom of the screen when the keyboard is showing.
It turns out to be not that difficult to just put a View around the content you want to remain above the keyboard and just dynamically set the height of it on iOS. This isn't even really necessary on Android as it follows the keyboard if the View is position: absolute and bottom: 0.
This heavily borrows from here: https://stackoverflow.com/a/60682069/438322
Thanks to Kevin Amiranoff
Here's a basic example using hooks.
function YourComponent(props){
const onKeyboardWillShow = e => {
setKeyboardHeight(e.endCoordinates.height);
};
const onKeyboardWillHide = () => {
setKeyboardHeight(0);
};
useEffect(() => {
// These listeners on ios are a little more snappy but not available on Android
// If you want to use this on Android use keyboardDidShow/Hide
if (Platform.OS === 'ios') {
Keyboard.addListener('keyboardWillShow', onKeyboardWillShow);
Keyboard.addListener('keyboardWillHide', onKeyboardWillHide);
}
return () => {
if (Platform.OS === 'ios') {
Keyboard.removeListener('keyboardWillShow', onKeyboardWillShow);
Keyboard.removeListener('keyboardWillHide', onKeyboardWillHide);
}
};
}, []);
const buttonHeight = 50;
return(
<View>
<Content bla={'bla'}/>
<View style={{
height: Platform.OS === 'ios'
? keyboardHeight + buttonHeight : buttonHeight,
position: 'absolute',
bottom: 0
}}>
{/* Keep this button above the keyboard */}
<Button style={{ height: buttonHeight }}/>
</View
</View>
)
}
this is my solution.
inverted={true} is the key
const dummy = [1,2,3,4,5,6,7,8,9,10]
<KeyboardAvoidingView >
<FlatList
data={dummy.reverse()}
inverted={true}
/>
</KeyboardAvoidingView>

How can I use this with FlatList not with ListView?

I took this code from react-native-gifted-chat
and I want to use FlatList
<ListView
enableEmptySections={true}
automaticallyAdjustContentInsets={false}
initialListSize={20}
pageSize={20}
{...this.props.listViewProps}
dataSource={this.state.dataSource}
renderRow={this.renderRow}
renderHeader={this.renderFooter}
renderFooter={this.renderLoadEarlier}
renderScrollComponent={this.renderScrollComponent}
/>
Here's an example for using FlatList to do what you're trying to do:
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={someArrayWithDataObjects} // your data source
renderItem={({ item }) => this.renderSearchResults(item)} // how you want each item rendered
keyExtractor={item => item.id} // unique identifier for performance reasons
/>
</View>
);
}

TouchableHighlight one click not work two works

I am having a strange problem. I wrote up a simple player app with react native and everything is fine in simulator. But when it comes to real device, its play button does not work properly. I tried the app on iPhone 6s and iPhone 5. The problem is that the play button works at second tap. The first tap does nothing.
Here is my whole render code:
render() {
let playIcon = this.state.isPlaying ? 'pause' : 'play';
let titleA = 'Set A: ' + (this.state.isASet ? this._toTime(this.state.pointA) : '-');
let titleB = 'Set B: ' + (this.state.isBSet ? this._toTime(this.state.pointB) : '-');
let time = this._toTime(this.state.time);
let remaining = this._toTime(this.state.duration - this.state.time);
return (
<View style={styles.container}>
<View style={styles.info}>
<Text>Name: {this.props.song.name}</Text>
<Text>Artist: {this.props.song.artist.name}</Text>
<Text># of channels: {this.props.song.tracks.length}</Text>
</View>
<View style={styles.channels}>
{
this.props.song.tracks.map((track, index) => {
return (
<VolumeSlider
key={index}
title={track.name}
volume={this.state.channelVolumes[index]}
onVolumeChange={this._handleChannelVolumeChange.bind(this, index)}
onMutePress={this._handleChannelMutePress.bind(this, index)}
onSoloPress={this._handleChannelSoloPress.bind(this, index)}
isPlayingSolo={this.state.channelSolos[index]}
/>
);
})
}
<VolumeSlider
title='Main'
volume={this.state.mainVolume}
onVolumeChange={this._handleMainVolumeChange.bind(this)}
onMutePress={this._handleMainMutePress.bind(this)}
hideSolo={true}
/>
</View>
<View style={{flexDirection: 'row', justifyContent: 'center'}}>
<TouchableHighlight style={styles.button} onPress={this._handleAPress.bind(this)}>
<Text numberOfLines={1}>{titleA}</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button} onPress={this._handleBPress.bind(this)}>
<Text numberOfLines={1}>{titleB}</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.button}
onPress={this._handleClearLoopPress.bind(this)}
>
<Text numberOfLines={1}>Clear</Text>
</TouchableHighlight>
</View>
<View style={styles.player}>
<TouchableHighlight onPress={this._handlePlayPress.bind(this)}>
<Icon
name={playIcon}
style={styles.playButton}
/>
</TouchableHighlight>
<View style={styles.center}>
<Text style={styles.timelineText}>{time}</Text>
</View>
<View style={styles.sliderContainer}>
<Slider
style={[styles.slider, styles.timelineSlider]}
onSlidingComplete={this._handleTimelineChange.bind(this)}
maximumValue={this.state.duration}
value={this.state.time}
step={0.01}
/>
</View>
<View style={styles.center}>
<Text style={styles.timelineText}>-{remaining}</Text>
</View>
</View>
</View>
);
}
And this is how it looks like on simulator:
I tried changing the location of the play button (I mean I placed it at the top of the app) and it worked. But I don't understand why it does not work when it is at bottom-left corner?
Thank you for your answers.
I found the problem. The problem is NavigatorIOS which is parent of the PlayerScreen of which render function is given belove. The navigator has swipe back gesture and it blocks the first tap on the play button. When I disabled the swipe back gesture of the navigator by falsing its interactivePopGestureEnabled pro, the play button properly worked.

Constricting WebView in React Native to certain part of page

I am attempting to constrict the webview of youtube urls to only show the video (and not the rest of the youtube page). How do you do this? I have figured out some of the props of the webview but would like to gain a deeper understanding of the following props:
automaticallyAdjustContentInsets bool
contentInset {top: number, left: number, bottom: number, right: number}
Here is what I have so far:
Of course, I don't want to see the youtube search tab - and would like to change the dimensions of the webview to do so. How can this be better done? Here is the code to the custom component of each video 'card':
<TouchableHighlight
style={styles.touchCard}
underlayColor={'transparent'}
onPress={this.props.onPress} >
<View style={styles.card}>
<WebView
scrollEnabled={false}
style={styles.videoPreview}
url={this.props.source}
renderLoading={this.renderLoading}
renderError={this.renderError}
automaticallyAdjustContentInsets={false} />
<View style={[styles.container, this.border('organge')]}>
<View style={[styles.header, this.border('blue')]}>
<Text style={[styles.previewText]}>{this.props.text}</Text>
</View>
<View style={[styles.footer, this.border('white')]}>
<View style={styles.sourceRow}>
<View style={[this.border('white')]}>
<ImageButton
style={[styles.logoBtn, , this.border('red'), styles.row]}
resizeMode={'contain'}
onPress={this.onHeartPress}
source={this.props.src} />
</View>
<View style={[this.border('white')]}>
<Text style={[styles.rowText, {fontWeight: 'bold'}]}>{this.props.entryBrand}</Text>
<Text style={[styles.rowText]}>{this.props.postTime}</Text>
</View>
</View>
<View style={[styles.heartRow, this.border('black')]}>
<KeywordBox
style={[styles.category, this.border('blue')]}
key={this.props.key}
text={this.props.category}
onPress={this.props.categoryPress}
selected={this.props.selected} />
</View>
</View>
</View>
</View>
</TouchableHighlight>

Resources