leecade / leecade/react-native-swiper
Android only: The specified child already has a parent
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.5k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
Which OS ?
Android only.
iOS works fine.
Version
Which versions are you using:
"react": "16.0.0-alpha.12",
"react-native": "0.47.1",
"react-native-swiper": "^1.5.13",
Actual behaviour
Swiper renders the first view give to it but once I call this.refs.swiper.scrollBy(1) to programatically scroll to the next view, the app crashes with the error:
The specified child already has a parent. You must call removeView() on the child's parent first.
Same error as here.
It works fine in the iOS simulator, however when I run it on the android simulator or my device I encounter this error. I am adding my render method. Its a bit messy.
How to reproduce it>
render() {
const {
nameInput,
textInput,
questionText,
nextTextStyle,
metaDataStyle,
inputContainer,
upperContainer,
arrowBackStyle,
buttonContainer,
} = styles;
return (
<View style={{ height: '100%', width: '100%', backgroundColor: 'rgb(220, 220, 220)' }}>
<Header label='Añade tu banco' customCallBack={this.handleBackPress}/>
<Swiper
index={this.state.currentSlide}
onIndexChanged={this.handleIndexChanged}
ref={'swiper'}
loop={false}
scrollEnabled={false}
dot={<View style={{backgroundColor: 'rgba(0,0,0,.0)'}} />}
activeDot={<View style={{backgroundColor: 'rgba(0,0,0,.0)'}} />}
>
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={upperContainer}>
<Text style={questionText}>{'¿Eres individual o\nuna compañia / empresa?'}</Text>
</View>
<View style={[inputContainer, { flexDirection: 'row' }]}>
<View style={{ width: '50%', height: '100%', ...centerItems }}>
<Text style={[questionText, { fontSize: width/22, marginBottom: 10 }]}>
Compañia
</Text>
<Checkbox
customStyles={{ width: 60, height: 40 }}
isChecked={this.state.type === "company" ? true: false}
onPress={() => this.setState({ type: "company" }, () => setTimeout(() => this.nextSlidePlease(), 200))}
/>
</View>
<View style={{ width: '50%', height: '100%', ...centerItems }}>
<Text style={[questionText, { fontSize: width/22, marginBottom: 10 }]}>
Individual
</Text>
<Checkbox
customStyles={{ width: 60, height: 40 }}
isChecked={this.state.type === "individual" ? true: false}
onPress={() => this.setState({ type: "individual" }, () => setTimeout(() => this.nextSlidePlease(), 200))}
/>
</View>
</View>
</View>
</View>
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow, alignItems: 'center' }}>
<View style={[upperContainer, { height: '18%' }]}>
<Text style={questionText}>{'¿Cuál es tu\nfecha de nacimiento?'}</Text>
</View>
<View style={{ width: '80%', ...centerItems }}>
<Text style={{ textAlign: 'center', color: 'rgb(70,70,70)' }}>Incluye un 0 adelante, si tu mes o día es un solo dígito: Día 5 → Día 05</Text>
</View>
<View style={[inputContainer, { flexDirection: 'row' }]}>
<View style={{ width: '30%', height: '80%', ...centerItems }}>
<TextInput
ref={'dobday'}
style={[textInput, this.state.dob_day_focused ? { borderColor: 'rgb(0, 173, 237)', borderWidth: 3 } : {}]}
placeholder={'05'}
keyboardType={'numeric'}
numberOfLines={1}
maxLength={2}
underlineColorAndroid='transparent'
onFocus={() => this.handleDobFocus('day')}
value={this.state.dob_day}
onChangeText={text => this.handleDobInput(text, 'day')}
/>
<Text style={metaDataStyle}>Día</Text>
</View>
<View style={{ width: '30%', height: '80%', ...centerItems }}>
<TextInput
ref={'dobmonth'}
style={[textInput, this.state.dob_month_focused ? { borderColor: 'rgb(0, 173, 237)', borderWidth: 3 } : {}]}
placeholder={'01'}
keyboardType={'numeric'}
numberOfLines={1}
maxLength={2}
underlineColorAndroid='transparent'
onFocus={() => this.handleDobFocus('month')}
value={this.state.dob_month}
onChangeText={text => this.handleDobInput(text, 'month')}
/>
<Text style={metaDataStyle}>Mes</Text>
</View>
<View style={{ width: '30%', height: '80%', ...centerItems }}>
<TextInput
ref={'dobyear'}
style={[textInput, this.state.dob_year_focused ? { borderColor: 'rgb(0, 173, 237)', borderWidth: 3 } : {}]}
placeholder={'1993'}
keyboardType={'numeric'}
numberOfLines={1}
maxLength={4}
underlineColorAndroid='transparent'
onFocus={() => this.handleDobFocus('year')}
value={this.state.dob_year}
onChangeText={text => this.handleDobInput(text, 'year')}
/>
<Text style={metaDataStyle}>Año</Text>
</View>
</View>
</View>
</View>
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={upperContainer}>
<Text style={questionText}>{'¿Cuál es tu\nnombre y apellido?'}</Text>
</View>
<View style={[inputContainer, { flexDirection: 'row', height: '15%', marginBottom: 20 }]}>
<View style={{ width: '30%', height: '100%', alignItems: 'flex-start', paddingLeft: 15, justifyContent: 'space-around' }}>
<Text style={{ fontSize: width/22, fontWeight: '500', color: 'rgb(90,90,90)' }}>Nombre(s)</Text>
<Text style={{ fontSize: width/22, fontWeight: '500', color: 'rgb(90,90,90)' }}>Apellido(s)</Text>
</View>
<View style={{ width: '60%', height: '100%', alignItems: 'flex-start', paddingLeft: 15, justifyContent: 'space-around' }}>
<TextInput
value={this.state.first_name}
style={nameInput}
onChangeText={firstName => this.setState({ first_name: firstName })}
maxLength={20}
returnKeyType={'next'}
underlineColorAndroid='transparent'
onSubmitEditing={Keyboard.dismiss}
/>
<TextInput
value={this.state.last_name}
style={nameInput}
onChangeText={lastName => this.setState({ last_name: lastName })}
maxLength={20}
returnKeyType={'next'}
underlineColorAndroid='transparent'
onSubmitEditing={Keyboard.dismiss}
/>
</View>
</View>
<View style={{ width: '100%', ...centerItems }}>
<TouchableOpacity onPress={this.handleOnNamePress} style={{ width: '90%' }}>
<LinearGradient
colors={['#56CCF2', '#309ae8']}
style={buttonContainer}
start={{x: 0.0, y: 0.0}} end={{x: 1.2, y: 0.5}}
>
<Text style={nextTextStyle}>Siguiente</Text>
</LinearGradient>
</TouchableOpacity>
</View>
</View>
</View>
{
this.state.type === 'individual'
?
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={upperContainer}>
<Text style={questionText}>{'¿Cuál es tu DNI o NIE?'}</Text>
</View>
<View style={[inputContainer, { flexDirection: 'row', height: '7%', marginBottom: 20 }]}>
<View style={{ width: '35%', height: '100%', alignItems: 'flex-start', paddingLeft: 15, justifyContent: 'space-around' }}>
<Text style={{ fontSize: width/24, fontWeight: '500', color: 'rgb(90,90,90)' }}>DNI o NIE</Text>
</View>
<View style={{ width: '60%', height: '100%', alignItems: 'flex-start', paddingLeft: 15, justifyContent: 'space-around', borderWidth: 1 }}>
<TextInput
value={this.state.dni_nie}
onChangeText={nie => this.handleDniInput(nie)}
maxLength={9}
autoCapitalize={'characters'}
returnKeyType={'next'}
underlineColorAndroid='transparent'
onSubmitEditing={Keyboard.dismiss}
style={[nameInput,
this.state.dniIsValid === false
?
{ borderWidth: 1, borderColor: 'rgb(244, 66, 66)' }
:
this.state.dniIsValid === true
?
{ borderWidth: 1, borderColor: 'rgb(39, 209, 86)' }
:
{ borderWidth: 1.5, borderColor: 'rgb(180,180,180)', }
]}
/>
</View>
</View>
<View style={{ width: '100%', ...centerItems }}>
<TouchableOpacity onPress={this.handleDniOrNieNextPress} style={{ width: '90%' }}>
<LinearGradient
colors={['#56CCF2', '#309ae8']}
style={buttonContainer}
start={{x: 0.0, y: 0.0}} end={{x: 1.2, y: 0.5}}
>
<Text style={nextTextStyle}>Siguiente</Text>
</LinearGradient>
</TouchableOpacity>
</View>
</View>
</View>
:
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={upperContainer}>
<Text style={[questionText, { fontSize: width/17, width: '97%' }]}>{'¿Cuál es el nombre (Razón social) y el NIF de la empresa?'}</Text>
</View>
<View style={[inputContainer, { flexDirection: 'row', height: '15%', marginBottom: 20 }]}>
<View style={{ width: '35%', height: '100%', alignItems: 'flex-start', paddingLeft: 15, justifyContent: 'space-around' }}>
<Text style={{ fontSize: width/24, fontWeight: '500', color: 'rgb(90,90,90)' }}>Nombre</Text>
<Text style={{ fontSize: width/22, fontWeight: '500', color: 'rgb(90,90,90)' }}>NIF</Text>
</View>
<View style={{ width: '60%', height: '100%', alignItems: 'flex-start', paddingLeft: 15, justifyContent: 'space-around' }}>
<TextInput
value={this.state.businessName}
style={nameInput}
onChangeText={input => this.setState({ businessName: input })}
maxLength={20}
returnKeyType={'next'}
underlineColorAndroid='transparent'
onSubmitEditing={Keyboard.dismiss}
/>
<TextInput
value={this.state.nif}
onChangeText={nif => this.handleNifInput(nif)}
maxLength={9}
autoCapitalize={'characters'}
returnKeyType={'next'}
underlineColorAndroid='transparent'
onSubmitEditing={Keyboard.dismiss}
style={[nameInput,
this.state.nifIsValid === false
?
{ borderWidth: 1, borderColor: 'rgb(244, 66, 66)' }
:
this.state.nifIsValid === true
?
{ borderWidth: 1, borderColor: 'rgb(39, 209, 86)' }
:
{}
]}
/>
</View>
</View>
<View style={{ width: '100%', ...centerItems }}>
<TouchableOpacity onPress={this.handleBusinessDataInput} style={{ width: '90%' }}>
<LinearGradient
colors={['#56CCF2', '#309ae8']}
style={buttonContainer}
start={{x: 0.0, y: 0.0}} end={{x: 1.2, y: 0.5}}
>
<Text style={nextTextStyle}>Siguiente</Text>
</LinearGradient>
</TouchableOpacity>
</View>
</View>
</View>
}
{
this.state.type === 'individual'
?
null
:
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={upperContainer}>
<Text style={questionText}>{'¿Cúal es la dirección\nde la empresa?'}</Text>
</View>
<View style={{ width: '100%', ...centerItems }}>
<TouchableOpacity
onPress={() => Actions.googlePlaces({ isComingFromBankDetailsComponent: true })}
style={{ width: '90%' }}
>
<LinearGradient
colors={['#56CCF2', '#309ae8']}
style={buttonContainer}
start={{x: 0.0, y: 0.0}} end={{x: 1.2, y: 0.5}}
>
<Text style={nextTextStyle}>Buscar dirección</Text>
</LinearGradient>
</TouchableOpacity>
</View>
</View>
</View>
}
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={upperContainer}>
<Text style={questionText}>{'Añade los datos de tu banco\ny empieza a recibir tu dinero.'}</Text>
</View>
<View style={{ width: '100%', height: 'auto', paddingLeft:20, paddingRight: 20 }}>
<View style={{ width:'18%', height: 22, justifyContent: 'center' }}>
<Text style={{ fontWeight: '600', fontSize: width/22, color: 'rgb(70,70,70)' }}>IBAN</Text>
</View>
<View style={{ width: '100%', height: 45, ...centerItems }}>
<TextInput
maxLength={29}
autoCapitalize={'characters'}
numberOfLines={1}
keyboardType={'default'}
autoCorrect={false}
value={IBAN.printFormat(this.state.ibanInput)}
returnKeyType={'next'}
onChangeText={iban => this.verifyIban(iban)}
style={[{ borderWidth: 1, borderRadius: 2, height: '100%', width: '100%', textAlign: 'center', fontSize: width/24 },
this.state.ibanIsValid === false
?
{ borderWidth: 1, borderColor: 'rgb(244, 66, 66)' }
:
this.state.ibanIsValid === true
?
{ borderWidth: 1, borderColor: 'rgb(39, 209, 86)' }
:
{}
]}
/>
</View>
</View>
<View style={{ width: '100%', height: 'auto', paddingLeft:20, paddingRight: 20, marginTop: 20 }}>
<View style={{ width:'100%', height: 22, justifyContent: 'center' }}>
<Text style={{ fontWeight: '600', fontSize: width/22, color: 'rgb(70,70,70)' }}>TITULAR DE LA CUENTA</Text>
</View>
<View style={{ width: '100%', height: 45, ...centerItems }}>
<TextInput
ref={'owner'}
autoCapitalize={'words'}
maxLength={24}
numberOfLines={1}
keyboardType={'default'}
autoCorrect={false}
returnKeyType={'next'}
value={this.state.bankOwnerName}
onChangeText={owner => this.verifyBankOwnerName(owner)}
style={[{ borderWidth: 1, borderRadius: 2, height: '100%', width: '100%', textAlign: 'center', fontSize: width/24 },
this.state.bankOwnerNameIsValid === false
?
{ borderWidth: 1, borderColor: 'rgb(244, 66, 66)' }
:
this.state.bankOwnerNameIsValid === true
?
{ borderWidth: 1, borderColor: 'rgb(39, 209, 86)' }
:
{}
]}
/>
</View>
</View>
<View style={{ height: 80 }}>
{
this.state.ibanIsValid && this.state.bankOwnerNameIsValid
?
<View style={{ width: '100%', height: 'auto', paddingLeft:20, paddingRight: 20, marginTop: 30, ...centerItems }}>
<TouchableOpacity onPress={this.createTokenFromBankAccount} style={{ width: '100%' }}>
<LinearGradient
colors={['#56CCF2', '#309ae8']}
style={buttonContainer}
start={{x: 0.0, y: 0.0}} end={{x: 1.2, y: 0.5}}
>
{
this.state.makingBankAccountRequest
?
<ActivityIndicator color='white' />
:
<Text style={nextTextStyle}>¡Añadir!</Text>
}
</LinearGradient>
</TouchableOpacity>
</View>
:
null
}
</View>
<View style={{ width: '100%', height: '20%', ...centerItems, marginTop: 0}}>
<View style={{ width: '95%', height: '100%', ...centerItems }}>
<Text style={{ fontSize: width/22, textAlign: 'center', color: 'rgb(90,90,90)' }}>
{'Para tu completa serguridad:\nLos datos de tu banco son\nmanejados por Stripe®.'}
</Text>
</View>
</View>
<TouchableOpacity
style={{ width: '100%', ...centerItems}}
onPress={() => Linking.openURL('https://www.stripe.com').catch(err => console.error('An error occurred', err))}
>
<Image
resizeMode={'contain'}
style={{ height: 40 }}
source={require('../assets/stripeLogos/poweredByStripe.png')}
/>
</TouchableOpacity>
</View>
</View>
<View style={{ padding: 10, flex: 1 }}>
<View style={{ flex: 1, ...shadow }}>
<View style={[upperContainer, { height: '30%' }]}>
<Text style={questionText}>¡Registramos tu banco!</Text>
<Text style={[questionText, { fontWeight: '400', width: '98%', marginTop: 20 }]}>Al completar un trabajo, recibirás el dinero en un plazo máximo de 7 días.</Text>
</View>
<View style={{ width: '100%', height: 'auto', paddingLeft:20, paddingRight: 20, marginTop: 30, ...centerItems }}>
<TouchableOpacity onPress={() => Actions.pop()} style={{ width: '100%' }}>
<LinearGradient
colors={['#56CCF2', '#309ae8']}
style={buttonContainer}
start={{x: 0.0, y: 0.0}} end={{x: 1.2, y: 0.5}}
>
<Text style={nextTextStyle}>Finalizar</Text>
</LinearGradient>
</TouchableOpacity>
</View>
</View>
</View>
</Swiper>
<Modal
visible={this.state.debitCardInputVisible}
animationType="fade"
onRequestClose={() => this.setState({ debitCardInputVisible: false })}
transparent={true}
>
<View style={{ height: '100%', backgroundColor: 'rgba(0, 0, 0, 0.9)', justifyContent: 'center' }}>
<View style={{ height: '10%', flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => this.setState({ debitCardInputVisible: false })}
style={{ ...centerItems, width: '25%', height: '100%' }}
>
<Icon name="ios-close-circle-outline" style={arrowBackStyle}/>
</TouchableOpacity>
<View style={{ width: '50%' }}/>
<TouchableOpacity
style={{ ...centerItems, width: '25%', height: '100%' }}
onPress={this.checkCardDataValidity}
>
<Icon name="ios-checkmark-circle-outline" style={arrowBackStyle}/>
</TouchableOpacity>
</View>
<KeyboardAvoidingView
style={{ height: '90%', justifyContent: 'center' }}
behavior='padding'
keyboardVerticalOffset={-20}
>
<CreditCardInput
autoFocus
cardScale={0.9}
onChange={form => this.setState({ ...this.state, cardForm: { ...form } })}
invalidColor={'rgb(234, 82, 65)'}
inputStyle={{ color: 'white', borderWidth: 1, borderColor: 'rgba(0,0,0,.0)' }}
labelStyle={{ color: 'rgb(250,250,250)', fontSize: width/28 }}
containerStyle={{ borderWidth: 0 }}
requiresName
labels={{number: "NÚMERO TARJETA", expiry: "VENCE", cvc: "CVC/CCV", name: "NOMBRE"}}
/>
</KeyboardAvoidingView>
</View>
</Modal>
</View>
);
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the Swiper scrollBy call and the Android rendering path, using the supplied render method and React Native versions to reproduce the crash. Done means programmatic scrolling to the next view works on Android without the specified-child-parent error, while the existing iOS behavior remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react-native
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100