react-native-gifted-chat icon indicating copy to clipboard operation
react-native-gifted-chat copied to clipboard

Input Accessory And Keyboard Behavior Like Messenger App

Open 000xuandu opened this issue 2 years ago • 10 comments

Hi guys!

CAN BE DONE?

Can GiftedChat do the same input/keyboard effect as the Messenger app?

The keyboard will be dismiss when user click Gif/Image icon in the accessory, and will come back when user focus text input!

I tried to research about this, and I found: KeyboardAccessoryView component, develop by Wix. But it has problem in Android, I created an issue here, haven’t fixed yet: https://github.com/wix/react-native-ui-lib/issues/2063

https://user-images.githubusercontent.com/33916400/179034560-04211fa3-c1a5-4ea8-b936-147113acbc73.MOV

000xuandu avatar Jul 14 '22 16:07 000xuandu

Same problem

fukemy avatar Jul 19 '22 01:07 fukemy

You can try lib: https://github.com/thomasgazzoni/react-native-keyboard-area for android. You change the SoftInput mode to ADJUST_NOTHING only for the pages, example:

import { RNKeyboard, SoftInputMode } from 'react-native-keyboard-area';

componentDidMount() {
  navigation.addListener('blur', this.componentDidExit);
  navigation.addListener('focus', this.componentDidEnter);
}

componentDidEnter = () => {
  if (Platform.OS === 'android') {
    RNKeyboard.setWindowSoftInputMode(SoftInputMode.SOFT_INPUT_ADJUST_NOTHING,);
  }
};

componentDidExit = () => {
  if (Platform.OS === 'android') {
    RNKeyboard.setWindowSoftInputMode(SoftInputMode.SOFT_INPUT_ADJUST_RESIZE);
  }
};

componentWillUnmount() {
  navigation.removeListener('blur', this.componentDidExit);
  navigation.removeListener('focus', this.componentDidEnter);
}
  • Add callback when the keyboard height changes (when it show/hide): RNKeyboard.addKeyboardListener((height) => { keyboardheight = height });
  • Add a View below TextInput and height of View change when keyboard height change, example:
<>
   <TextInput />
   <Animated.View
      style={[height: keyboardheight, styles.accessoryView]}
   >
      {customKeyboard === ComponentID.IMAGE_GALLERY && (
       <SelectImageGallery />
       )}
    </Animated.View>
</>
  • For IOS, you set isKeyboardInternallyHandled={false}, and use Keyboard API listener keyboard height change, example:
useEffect(() => {
    if (Platform.OS === 'ios') {
      const showSubscription = Keyboard.addListener('keyboardWillShow', (e) => {
        keyboardheight = e.endCoordinates.height;
      });
      const hideSubscription = Keyboard.addListener('keyboardWillHide', (e) => {
        keyboardheight = 0;
      });
      return () => {
        showSubscription.remove();
        hideSubscription.remove();
      };
    }
  }, []);
  • And then you do the same as android

huuthinh95 avatar Jul 21 '22 08:07 huuthinh95

hi @huuthinh95 , can u help my problem? I can not switch keyboard sticker Here is my main view

<View style={{
                position: 'absolute',
                width: '100%',
                height: '100%',
            }}>
                {renderGiftedChat()}
                <KeyboardSpacer
                    ref={kbRef}
                    isOpen={customKeyboard == KEYBOARD_SYSTEM}
                    onChange={(isOpen: boolean, currentHeight: number) => {
                        console.log('onchange', isOpen, currentHeight)
                    }}>   

                    {renderAccessory()}
                </KeyboardSpacer>
            </View>



  const renderAccessory = (props) => {
        if (customKeyboard == KEYBOARD_EMOJI) return <ChatEmojiKeyboardInput width={width} height={getKbHeight} onSelectEmoji={onSelectEmoji} />
        if (customKeyboard == KEYBOARD_MORE) return <ChatMoreKeyboardInput width={width} height={getKbHeight} onSelectedFile={onSelectedFile} onShareContact={onShareContact}/>
        if (customKeyboard == KEYBOARD_VOICE) return <ChatVoiceKeyboardInput width={width} height={getKbHeight} onSendVoice={onSendVoice} />
        return null
    }

Can u tell me what's wrong with my code? Thanks so much

fukemy avatar Jul 25 '22 08:07 fukemy

hi @fukemy Your problem on android or IOS. If on android, you need set SoftInput mode to ADJUST_NOTHING.

import { RNKeyboard, SoftInputMode } from 'react-native-keyboard-area';

componentDidMount() {
  navigation.addListener('blur', this.componentDidExit);
  navigation.addListener('focus', this.componentDidEnter);
}

componentDidEnter = () => {
  if (Platform.OS === 'android') {
    RNKeyboard.setWindowSoftInputMode(SoftInputMode.SOFT_INPUT_ADJUST_NOTHING,);
  }
};

componentDidExit = () => {
  if (Platform.OS === 'android') {
    RNKeyboard.setWindowSoftInputMode(SoftInputMode.SOFT_INPUT_ADJUST_RESIZE);
  }
};

componentWillUnmount() {
  navigation.removeListener('blur', this.componentDidExit);
  navigation.removeListener('focus', this.componentDidEnter);
}

And you can try your code on IOS.

huuthinh95 avatar Aug 01 '22 01:08 huuthinh95

ya, it's work as expected, im using KeyboardArea it's almost do the job for me. Thanks

fukemy avatar Aug 01 '22 03:08 fukemy

@huuthinh95 Thank you! The iOS is smooth but Android still flickers

000xuandu avatar Aug 02 '22 17:08 000xuandu

@000xuandu you can try this code.

import React, { useState, useCallback, useEffect, useRef } from 'react';
import { TextInput, TouchableOpacity, View, Text, Keyboard, Animated, Platform } from 'react-native';
import { GiftedChat } from 'react-native-gifted-chat';
import { RNKeyboard, SoftInputMode, KeyboardArea, KeyboardAreaRef } from 'react-native-keyboard-area';

export function App() {
  const [messages, setMessages] = useState([]);
  const heightAni = useRef(new Animated.Value(0)).current;
  const flag = useRef(false);
  const componentDidEnter = () => {
    if (Platform.OS === 'android') {
      RNKeyboard.setWindowSoftInputMode(SoftInputMode.SOFT_INPUT_ADJUST_NOTHING,);
    }
  };
  
  const componentDidExit = () => {
    if (Platform.OS === 'android') {
      RNKeyboard.setWindowSoftInputMode(SoftInputMode.SOFT_INPUT_ADJUST_RESIZE);
    }
  };

  useEffect(() => {
    RNKeyboard.addKeyboardListener(keyboardAreaHeightChanged);
    return () => {
      RNKeyboard.removeKeyboardListener(keyboardAreaHeightChanged)
    }
  }, [])

  const keyboardAreaHeightChanged = useCallback((currentHeight) => {
    // Your logic
    if (flag.current) {
      flag.current = false;
      return;
    }
    Animated.timing(heightAni, {
      toValue: currentHeight,
      duration: 0,
      useNativeDriver: false
    }).start();
  }, []);

  useEffect(() => {
    componentDidEnter()
    return () => {
      componentDidExit()
    };
  }, [])

  useEffect(() => {
    setMessages([
      {
        _id: 1,
        text: 'Hello developer',
        createdAt: new Date(),
        user: {
          _id: 2,
          name: 'React Native',
          avatar: 'https://placeimg.com/140/140/any',
        },
      },
    ])
  }, []);
  const onSend = useCallback((messages = []) => {
    setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
  }, []);

  const renderInputToolbar = () => {
    return (
      <Animated.View style={{borderWidth: 1, borderColor: 'red', flex: 1}}>
        <TextInput style={{borderWidth: 1, borderColor: 'blue'}} />
        <TouchableOpacity onPress={handleChangeMode}>
          <Text>Test</Text>
        </TouchableOpacity>
      </Animated.View>
    )
  }

  const handleChangeMode = () => {
    if (heightAni._value === 0) {
      Animated.timing(heightAni, {
        toValue: 305,//get height of keyboard
        duration: 100,
        useNativeDriver: false
      }).start();
    } else {
      flag.current = true'''
      Keyboard.dismiss()
    }
  }

  return (
    <View style={{flex: 1}}>
      <GiftedChat
        messages={messages}
        onSend={messages => onSend(messages)}
        user={{
          _id: 1,
        }}
        multiline
        renderComposer={renderInputToolbar}
      />
      {/* <KeyboardArea
        ref={keyboardSpacerRef.current}
        isOpen={false}
        onChange={keyboardAreaHeightChanged}
      >
      </KeyboardArea> */}
      <Animated.View style={{height: heightAni }}>
        <Text>custom content</Text>
      </Animated.View>
    </View>
  )
}

export default App;

huuthinh95 avatar Aug 05 '22 03:08 huuthinh95

hi @huuthinh95 , i want to make the view below keyboard look like bottom sheet, such as the sticker keyboard of Messenger, did u faced this?

fukemy avatar Aug 10 '22 08:08 fukemy

@huuthinh95 Android reported this error. Do you have any better suggestions? Thank you

image

OPEN-9 avatar Aug 10 '22 09:08 OPEN-9

did u used expo?

fukemy avatar Aug 10 '22 09:08 fukemy