react-native-tab-view icon indicating copy to clipboard operation
react-native-tab-view copied to clipboard

TextInput auto blur on first click (Android only)

Open devWaleed opened this issue 4 years ago • 29 comments

Current behaviour

I have 2 tabs. First tab is active by default (i.e initial tab). Second tab has a TextInput. When I start app, click on second tab header it shows me second tab contents i.e the TextInput. When I click on the text field for typing it opens keyboard than auto closes for first time only. I am getting blur event on TextInput field. If I click again everything works fine.

Expected behaviour

On click on TextInput should open keyboard like normal.

Code sample

Simple Two tabs code with first as default open and second as inactive but having TextInput.

What have you tried

I have verified by putting blur event handler on TextInput. I am getting this event on Android only.

Your Environment

software version
ios or android Android 10
react-native 0.63.4
react-native-tab-view 3.0.1
react-native-pager-view 5.1.9
node 14.13.1
npm or yarn yarn

devWaleed avatar May 19 '21 14:05 devWaleed

Couldn't find version numbers for the following packages in the issue:

  • expo

Can you update the issue to include version numbers for those packages? The version numbers must match the format 1.2.3.

The versions mentioned in the issue for the following packages differ from the latest versions on npm:

  • react-native (found: 0.63.4, latest: 0.64.1)
  • react-native-pager-view (found: 5.1.3, latest: 5.1.9)

Can you verify that the issue still exists after upgrading to the latest versions of these packages?

github-actions[bot] avatar May 19 '21 14:05 github-actions[bot]

Not using Expo but react-native-cli and pager-view version is 5.1.9 updated but still issue.

devWaleed avatar May 19 '21 15:05 devWaleed

Same problem here, I have 2 tabs when TextInput triggers onchange the keyboard automatically dismiss.

nathangabriel27 avatar May 22 '21 18:05 nathangabriel27

Code example:

import React, { useState } from 'react';

import { View, useWindowDimensions, TextInput } from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view';

export default function TabViewExample() {
  const layout = useWindowDimensions();
  
  const SecondRoute = () => (
  <View style={{ flex: 1, backgroundColor: '#ff4081' }} />
);
const [enterprise_types, setEnterprise_types] = useState('test')
const FirstRoute = () => (
   <View style={{ flex: 1, backgroundColor: '#673ab7' }} >
  <TextInput
           keyboardType="decimal-pad"
            returnKeyType={'search'}
            value={enterprise_types}
            onChangeText={(text) => setEnterprise_types(text)}
/>
  </View>
 );
const renderScene = SceneMap({
  first: FirstRoute,
  second: SecondRoute,
});

  const [index, setIndex] = React.useState(0);
  const [routes] = React.useState([
    { key: 'first', title: 'First' },
    { key: 'second', title: 'Second' },
  ]);

  return (
    <TabView
      navigationState={{ index, routes }}
      renderScene={renderScene}
      onIndexChange={setIndex}
      initialLayout={{ width: layout.width }}
    />
  );
}

nathangabriel27 avatar May 22 '21 18:05 nathangabriel27

Currently having this issue as well. The only way that I've been able to prevent the dismissal is to set keyboardDismissMode: 'none' on the TabView. I tried setting it to 'on-drag' but it still kept dismissing the keyboard once the tab view re-renders.

<TabView
    keyboardDismissMode="none" // set keyboardDismissMode to 'none'
    navigationState={{index, routes}}
    onIndexChange={setTabIndex}
    initialLayout={{width: layout.width}}
/>

samakintunde avatar May 23 '21 17:05 samakintunde

@samakintunde37 keyboardDismissMode="none" doesn't work for me. I am getting the same error.

devWaleed avatar May 24 '21 09:05 devWaleed

Same problem

nicolak avatar May 25 '21 14:05 nicolak

@nathangabriel27 The issue with your component is the level you're declaring enterprise_types at. If the state isn't being shared between both tabs, you should move the state into the FirstRoute component, where you need it and you should be good.

samakintunde avatar May 25 '21 17:05 samakintunde

@devWaleed and @nicolak, check above. Same situation?

samakintunde avatar May 25 '21 17:05 samakintunde

const FirstRoute = () => {
        const [myValue, setMyValue] = useState('');
        return (
            <View style={{ flex: 1, backgroundColor: '#ff4081' }} >
                <C.TextoInput 
                    value={myValue}
                    onChangeText={(t)=>setMyValue(t)}
                />
            </View>
        ) };

That way, the keyboard does not close. However, when switching to another tab, the State myValue is reset to zero.

What to do?

nicolak avatar May 25 '21 17:05 nicolak

export default function TabViewExample() {
  // Keep state outside the components so it persists across tabs
  const [myValue, setMyValue] = useState('');

  const layout = useWindowDimensions();

  const [index, setIndex] = React.useState(0);
  const [routes] = React.useState([
    {key: 'first', title: 'First'},
    {key: 'second', title: 'Second'},
  ]);

  // Use a custom renderScene function instead
  const renderScene = ({route}) => {
    switch (route.key) {
      case 'first':
        return (
          <View style={{flex: 1, backgroundColor: '#ff4081', padding: 48}}>
            <TextInput
              style={{backgroundColor: '#fff'}}
              value={myValue}
              onChangeText={setMyValue}
            />
          </View>
        );
      case 'second':
        return <View style={{flex: 1, backgroundColor: '#ff4081'}} />;

      default:
        return <View />;
    }
  };

  return (
    <TabView
      navigationState={{index, routes}}
      renderScene={renderScene}
      onIndexChange={setIndex}
      initialLayout={{width: layout.width}}
    />
  );
}

samakintunde avatar May 25 '21 17:05 samakintunde

Wow. It worked out. Thanks!

nicolak avatar May 25 '21 17:05 nicolak

You're welcome!👍

samakintunde avatar May 25 '21 17:05 samakintunde

Here is my code. I am using class based components. On my Home component/screen I am returning few views and TabView is one of them. I have used tabsSceneMap as a custom sceneMap function already. All my tab tab screens are React.PureComponent. Still the issue persist for me.

// class Home extends React.Component

state = {
	currentTabIndex: 0,
};

tabRoutes = [
	{
		key: 'home',
		title: 'Home',
		icon: (color) => <Icon name="home" solid size={20} color={color} />,
	},
	{
		key: 'products',
		title: 'Products',
		icon: (color) => (
			<Icon name="shopping-bag" solid size={20} color={color} />
		),
	},
	{
		key: 'consultant',
		title: 'Consultant',
		icon: (color) => (
			<Icon name="user-clock" solid size={20} color={color} />
		),
	},
	{
		key: 'blogs',
		title: 'Blogs',
		icon: (color) => <Icon name="blogger-b" solid size={20} />,
	},
];

render() {
	return <View style={{ flex: 1 }}>
					{this.tabViews()}
				</View>
}

tabsSceneMap({ route }) {
	switch (route.key) {
		case 'home':
			return <HomeTab
				navigation={this.props.navigation}
				changeTabCallback={this.changeTabCallback}
			/>;
		case 'products':
			return <ProductsTab navigation={this.props.navigation} />;
		case 'consultant':
			return <Consultant />;
		case 'blogs':
			return <BlogsListing navigation={this.props.navigation} />;
	}
}

changeTabCallback = (tab) => {
	switch (tab) {
		case 'products':
			this.setState({
				currentTabIndex: 1,
			});
			this.props.setSearchBoolean(false);
			break;
		default:
			this.setState({
				currentTabIndex: 0,
			});
			break;
	}
};

tabViews() {
	return (
		<TabView
			lazy={true}
			swipeEnabled={false}
			renderTabBar={() => null}
			navigationState={{
				index: this.state.currentTabIndex,
				routes: this.tabRoutes,
			}}
			renderScene={this.tabsSceneMap}
			onIndexChange={(currentTabIndex) =>
				this.setState({ currentTabIndex })
			}
			initialLayout={{ width: windowWidth }}
		/>
	);
}

devWaleed avatar May 26 '21 07:05 devWaleed

Same issue

moh3n9595 avatar May 30 '21 19:05 moh3n9595

same for me

MaxToyberman avatar Jun 15 '21 15:06 MaxToyberman

solution of @samakintunde37 doesn't solve my issue, downgrade to 2.16.0 to temporary solve and wait a bug fix or a solution

I am having this issue in iOS. Any text input in a tabview hides the keyboard and it doesn't open again. Downgraded to 2.16.0 for the fix.

gamingumar avatar Jul 19 '21 12:07 gamingumar

Hey! Thanks for opening the issue. Can you provide a minimal repro which demonstrates the issue? Posting a snippet of your code in the issue is useful, but it's not usually straightforward to run. A repro will help us debug the issue faster. Please try to keep the repro as small as possible and make sure that we can run it without additional setup.

The easiest way to provide a repro is on snack.expo.dev. If it's not possible to repro it on snack.expo.dev, then please provide the repro in a GitHub repository.

github-actions[bot] avatar Jul 29 '21 13:07 github-actions[bot]

I have the same issue too

bayraak avatar Aug 10 '21 16:08 bayraak

I'm having the same issue on IOS (it works fine on Android) for version 3.1.1. Downgraded to 2.16.0 and it worked.

babyrusa avatar Aug 31 '21 19:08 babyrusa

Hello 👋, this issue has been open for more than a month without a repro or any activity. If the issue is still present in the latest version, please provide a repro or leave a comment within 7 days to keep it open, otherwise it will be closed automatically. If you found a solution or workaround for the issue, please comment here for others to find. If this issue is critical for you, please consider sending a pull request to fix it.

github-actions[bot] avatar Oct 01 '21 01:10 github-actions[bot]

The problem still persists. I also have to downgrade to version 2.16.0. When a tab is selected with a focused textinput (via autoFocus or some listener that calls focus via some ref) the focus works, but in a second the keyboard is dismissed and focus is lost. EDIT: Its hapenning in Android (8, 9, 10 and 11)

EduFrazao avatar Jul 04 '22 21:07 EduFrazao

Same issue Still Persists... I changed the function calling from (e) => function_name(e) to function_name but.... As soon as i enter the value it triggers the onChangeText () and hence leads to hiding keyboard... Kindly resolve the error

achalofficial avatar Sep 27 '22 09:09 achalofficial

Happens to me as well

emilianraduu avatar Oct 03 '22 10:10 emilianraduu

Reopening this, since the issue still persists

okwasniewski avatar Oct 03 '22 11:10 okwasniewski

Yep, same issue here.

fmendoza avatar Oct 07 '22 00:10 fmendoza

My app also has the same issue. I checked the call stack of TextInput.blur() and got the following stack trace.

01

This line in react-native-pager-view has keyboard close code that only works on Android (derivatively the TextInput loses focus). https://github.com/callstack/react-native-pager-view/blob/0c65e4dbd296861855a3e3f5b0bb9942f2dc9248/src/PagerView.tsx#L71

After removing this Keyboard.dismiss() the TextInput no longer loses focus in my app.

Update My workaround

  const [
    keyboardDismissMode,
    setKeyboardDismissMode,
  ] = React.useState<'none' | undefined>();
  const navigation = useNavigation();

  React.useEffect(() => {
    if (Platform.OS !== 'android') {
      return;
    }

    const unsubscribeOnFocus = navigation.addListener('focus', () => {
      setKeyboardDismissMode(undefined);
    });
    const unsubscribeOnBlur = navigation.addListener('blur', () => {
      setKeyboardDismissMode('none');
    });

    return () => {
      unsubscribeOnFocus();
      unsubscribeOnBlur();
    };
  }, [navigation]);

  return <TabView keyboardDismissMode={keyboardDismissMode} />;

lotusshinoaki avatar Oct 28 '22 08:10 lotusshinoaki

Adding animationEnabled={false} to <TabView /> solves the problem for me! <TabView animationEnabled={false} navigationState={state} renderScene={_renderScene} renderTabBar={_renderTabBar} onIndexChange={_handleIndexChange} tabBarPosition="bottom" />

AwesomeDracula avatar Nov 03 '22 16:11 AwesomeDracula