Nativebase: Needs to tap twice to fire onPress function when keyboard is open

Created on 29 Jul 2017  路  17Comments  路  Source: GeekyAnts/NativeBase

react-native, react and native-base version

react-native: 0.46.4
react: 16.0.0-alpha.12
native-base: 2.3.0

Expected behaviour

When the keyboard is open and a tap on button is performed, the onPress function should be fired immediatly.

Actual behaviour

When a tap on login button cause only the keyboard dismissal and the user have to perform another tap on login button to fire the onPress function.

Steps to reproduce (code snippet or screenshot)

Fill fields and tap on login button without dismiss keyboard.

Is the bug present in both ios and android or in any one of them?

The is present on Android but I've not tested on iOS yet.

Any other additional info which would help us debug the issue quicker.

My component is:

class LoginScreen extends Component<Props, State> {
  static propTypes = {
    isLoggedIn: PropTypes.bool.isRequired,
    isAuthenticating: PropTypes.bool.isRequired,
    actions: PropTypes.shape({
            auth: PropTypes.object
        })
  }

  constructor(props) {
    super(props)

    this.state = {
      username: '',
      password: '',
      error: null
    }

    this._onLogin = this._onLogin.bind(this)
  }

  componentWillUnmount(): void {
    this.setState({
      username: '',
      password: null,
      error: null
    })
  }

  _onLogin = (): void => {    
    if (this.isFormValid()) {
      this.props.actions.auth.authenticate(this.state.username, this.state.password)
        .catch((error: Error) => {
          this.setState({
            error: error ? error.message : 'Si e\' verificato un errore.'
          })
        })
    } else {
      // Form validation error
      this.setState({error: 'Specificare username e password.'})
    }
  }

  isFormValid(): boolean {
    this.setState({ error: null })

    if (!this.state.username || this.state.username === '') {
      this.setState({ error: 'Username non valido.' })
      return false
    }

    if (!this.state.password || this.state.password === '') {
      this.setState({ error: 'Password non valida.' })
      return false
    }

    return true
  }

  render(): JSX.Element {
    return (
      <Content padder style={styles.content} contentContainerStyle={styles.contentContainer}>
        <Spinner visible={this.props.isAuthenticating} textContent={'Accesso in corso...'} textStyle={{color: '#FFF'}} />

        <View style={styles.logoContainer}>
          <Image style={styles.logo}
            source={require('../../assets/logo.png')} />
        </View>

        <Form style={styles.form}>
          <Item floatingLabel error={this.state.error ? true : false}>
            <Label>Username</Label>
            <Input
              value={this.state.username} autoCapitalize='none' autoCorrect={false}
              onChangeText={ (username) => this.setState({ username: username }) } />
          </Item>
          <Item floatingLabel error={this.state.error ? true : false}>
            <Label>Password</Label>
            <Input
              value={this.state.password} autoCapitalize='none' autoCorrect={false} secureTextEntry
              onChangeText={ (password) => this.setState({ password: password }) } />
          </Item>
        </Form>

        {this.state.error ? (<FormMessage message={this.state.error} />) : null}

        {/* {(Platform.OS === 'android') ? (
          <TouchableNativeFeedback onPress={this._onLogin} background={TouchableNativeFeedback.SelectableBackground()}>
            <View style={styles.loginButton}>
              <Text style={{margin: 30}}>Accedi</Text>
            </View>
          </TouchableNativeFeedback>
        ) : (
          <Button block success style={styles.loginButton} onPress={this._onLogin}>
            <Text>Accedi</Text>
          </Button>
        )} */}
        <Button block success style={styles.loginButton} onPress={this._onLogin}>
          <Text>Accedi</Text>
        </Button>
      </Content>
    )
  }
}

const mapStateToProps = (state: AppState, ownProps: any) => ({
  isLoggedIn: authSelectors.isLoggedIn(state),
  isAuthenticating: stateSelectors.isAuthenticating(state)
})

const mapDispatchToProps = (dispatch: Dispatch<any>) => ({
    actions: {
        auth: bindActionCreators(authActionCreators, dispatch)
    }
})

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen)

Most helpful comment

@bm-software Use keyboardShouldPersistTaps={'handled'} and will works fine.

All 17 comments

Content is using ScrollView component under the hood. You might want to check this.

@sanketsahusoft Ok but can I set keyboardShouldPersistTaps on Content?

Yes you can.

I've just tried this but:

immagine

Is it only a typings error? (I'm using tsx)

@bm-software Use keyboardShouldPersistTaps={'handled'} and will works fine.

@lucianomlima I've tried your solution but the error still exists.

I've solved for now by creating a new file called typings.tsx with missing typings:

import React from 'react'

declare module 'native-base' {
    export class Root extends React.Component<any, any> {}

    namespace NativeBase {
        interface Content {
            keyboardShouldPersistTaps?: string
            keyboardDismissMode?: string
        }
    }
}

I have the same problem, but even with keyboardShouldPersistTaps={'always'} or handled it doesn't work on my case :(!

Here's my code:

onChange={value => {
this.setState({
cca2: value.cca2,
callingCode: value.callingCode
});
}}
cca2={this.state.cca2}
translation="eng"

                    <View
                        style={{
                            flexDirection: "row",
                            height: 60,
                            marginTop: 20,
                            alignItems: "center"
                        }}

                        {CountryPicker.renderFlag(this.state.cca2)}
                        <Text>+{this.state.callingCode}</Text>
                    </View>
                </CountryPicker>
            </Item>
            <Item
                floatingLabel
                style={[styles.textInput, { flex: 7 }]}

                <Label>Phone Number:</Label>
                    <Input
                        keyboardType={"numeric"}
                        value={this.state.phone}
                        onChangeText={phone => this.setState({ phone })}
                    />
            </Item>
        </View>
        <Button title={"..."} full onPress={() => this.verify()}>
            {!this.state.buttonIsLoading ? (
                <Text>Verify</Text>
            ) : (
                <Spinner color="blue" />
            )}
        </Button>
    </Form>
</Content>

I found the issue, I had another Content as a parent, removing that fixed the issue.

I Have the same problem how can we solve.??

@rammi44 try adding keyboardShouldPersistTaps={'handled'} prop to <Content/> component.

Where do I add, i am using scroll view.. can you explain it

@rammi44
If you are using NativeBase <Content> component use it like this

<Content keyboardShouldPersistTaps={'handled'}>
 .  
 .  
 . 
</Content>

For ReactNative <ScrollView/>

<ScrollView keyboardShouldPersistTaps={'handled'}>
 . 
 . 
 .  
</ScrollView> 

Not working for me..
Below is my sample code:
{this.props.IsPickerVisible &&
{colors}


}

@rammi44 This is fixed
Check release notes

its also working after adding below code in app.json:
{
"expo": {
"sdkVersion": "23.0.0",
"androidStatusBar": {
"backgroundColor": "#000000"
}

}
}

@lucianomlima when set keyboardShouldPersistTaps={'handled'}, the button click works, but keyboard does not dismiss! Who has the same issue?

@lucianomlima Set keyboardShouldPersistTaps={'handled'} then

_onButtonClick() {
        Keyboard.dismiss()
}

It works

Was this page helpful?
0 / 5 - 0 ratings