I am trying to fix a problem we are having with the keyboard on android. Due to react-native-gifted-chat, we have to use android:windowSoftInputMode="adjustResize" instead of adjustPan. The problem is, that the chat breaks without adjustResize and all the other stuff (e.g. some textfields in a form) break without adjustPan. I also tried adjustResize|adjustPan, adjustPan|adjustResize and tried to use KeyboardAvoidingView on the Form components, but nothing seems to work. Here is how it looks like when using adjustResize without any KeyboardAvoidingView. It creates some not-clickable grey area above the keyboard. Note that there is no way around adjustResize due to the chat...
Thanks in advance!
For anyone struggling with the same:
The package react-native-set-soft-input-mode allows you to change the softInputMode, e.g. for the chat, the following works fine:
useEffect(() => {
if (Platform.OS === 'android') {
SoftInputMode.set(SoftInputMode.ADJUST_RESIZE);
}
return () => {
if (Platform.OS === 'android') {
SoftInputMode.set(SoftInputMode.ADJUST_PAN);
}
};
}, []);
Related
I have the following code to prevent the buttons to stay focused after they are clicked. It works perfectly for desktop but it doesn't work at all when testing on mobile devices (Both iOS & Android), I'm not sure if I'm missing something here (I already tried replacing click with touchstart and touchend).
this.renderer.listen('document', 'click', (event) => {
if (event.target.nodeName === 'BUTTON') {
event.target.blur();
} else if (event.target.parentNode.nodeName === 'BUTTON') {
event.target.parentNode.blur();
}
});
Ok so I figured it out, in case anyone ever comes across this situation:
It WAS actually working, but on mobile devices an "emulated" hover is also applied after pressing buttons, so what I was seeing was the hover state, not the focus one.
I fixed it by wrapping the hover style of my button inside this block, to make sure that the device supports ACTUAL hover (e.g. using a mouse):
#media (hover: hover) {
your-element:hover {
//hover style
}
}
This one's an interesting one.
I created a TextInput that takes a value, then lower cases it, adds it to state, and sets it as the default value. On my android physical device, if you force a capital letter ( autocapitalize is set to none), and then quickly tap other letters, it will duplicate and add extra text.
Is there a way to avoid this?
Here's a snack https://snack.expo.io/Hk1reKHJ4
Run it on your android or on the simulator, tap the upper case button on the keyboard, tap a few other letters, tap the upper case again, tap a few other letters, and you should set this error.
Thanks!
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
text: ''
}
}
render() {
return (
<View style={styles.container}>
<TextInput
style={ styles.inputContainer }
defaultValue={ this.state.text }
autoCapitalize="none"
onChangeText={ value => this.setState({
text: value.trim().toLowerCase()
})}
/>
</View>
);
}
}
add these three lines inside TextInput, it should fix the problem, original answer source
autoCapitalize="none"
secureTextEntry={true}
keyboardType={"visible-password"}
see my this answer for example
Unfortunately this is an issue that has been open for a couple of years with no solution, you can check this thread, no one found a solution. There is a temporary workaround until the React Native team fixes this bug as it seems to be taking too long, check it out here.
The autoCapitalize prop worked for me.
autoCapitalize="none"
I do not agree with the selected answer. The link provided in it worked for me.
secureTextEntry={Platform.OS === 'ios' ? false : true}
keyboardType={Platform.OS === 'ios' ? null : 'visible-password'}
autoCapitalize="characters"
https://github.com/facebook/react-native/issues/11068#issuecomment-586346549
I made this hack:
https://snack.expo.dev/#bzozoo/duplications-at-upper-or-lowercase-async-problem-solution
Unfortunately, it is quite a compromise solution.
Input is apparently slower due to the asynchronous function
I found a solution for this issue
add toLowercase() when you posting data
axios.post("api/login", { emailid: emailid.trim().toLowerCase()})
I'm having a serious problem with React Native on Android.
Let's say I have the following render method:
render() {
let stuff = this.state.showStuff ? <Text style={styles.stuff}>Stuff</Text> : null
return (
<View>
{ stuff }
</View>
)
}
Really simple. If I want to hide the "Stuff", I just call:
this.setState({ showStuff: false })
This works fine on iOS, but on Android, if styles.stuff define a backgroundColor, the component will be re-rendered without the "stuff" content, but with it's background!
Now I have no idea on how to remove elements from my component, since this weird behavior broke how I used to think react native works.
I found out that react-native-searchbar was causing the issue on non-related views. Removing that component solved this and other non-related issues on my project.
I have at the moment a component SplashScreen which I'm rendering first till my state is set. I would like somehow to find a way how to still show this component while my webview is loaded. I added the onLoadEnd to my webview and looks like I get my message back when its finished loading, the problem is that if I load first the splashscreen and wait for the state to be changed onLoadEnd actually will never be changed because the webview is not yet rendered. Is there a good method how to do this?
My solution was actually quite simple, the WebView component can have the param renderLoading which for me was not working, I figured out it was because also startInLoadingState needed to be defined.
So my WebView looks somehow like this:
<WebView
ref={MY_REF}
source={source}
renderLoading={this.renderLoading}
startInLoadingState
/>
This would be my approach:
constructor(props){
super(props);
this.state = { webviewLoaded: false };
}
_onLoadEnd() {
this.setState({ webviewLoaded: true });
}
render() {
return(
<View>
{(this.state.webviewLoaded) ? null : <SplashScreen />}
<WebView onLoadEnd={this._onLoadEnd.bind(this)} />
</View>
)
}
This way, the webview is rendered but it is placed behind the SplashScreen. So the webview starts loading while the SplashScreen is being displayed.
I had a similar problem and I managed to solve it temporarily with this:
loadEnd () {
this.setState({ webViewLoaded: true }):
}
render () {
const { webViewLoaded } = this.state;
return (<View>
{!webViewLoaded && <LoadingComponent /> } -- or spinner, whatever
<WebView
style={(webViewLoaded) ? styles.webView : styles.loading}
onLoadEnd={() => this.loadEnd.bind(this)} />
</View);
}
const styles = StyleSheet.create({
webView: { -- your styles ---},
loading: {
width: 0,
heigt: 0
}
});
not sure if exactly this helps you but you can try similar approach. I will probably change this to something more convenient. Not sure if there are possibilities to animate these changes because Im still pretty newbie in React Native.
edit: added hiding the spinner/loading element
I'm trying to trigger clicks on WebViews and want to open them for example in a new WebView to make a route flow. In iOS I can call the method onShouldStartLoadWithRequest and look at the event like this:
onShouldStartLoadWithRequest(e)
{
if(e.navigationType === "click")
{
}
}
On Android this function doesn't exists. Does someone know how to do something like this? Maybe you handle this in an other way but I really don't have a plan on this. Thanks for any advice
I solved this by routing the onNavigationStateChange function (which fires on Android), to my implementation of onShouldStartLoadingWithRequest:
onNavigationStateChange (req) {
if (Platform.OS !== 'ios') {
this.onShouldStartLoadWithRequest(req)
}
}
And:
onNavigationStateChange={this.onNavigationStateChange}
In this instance req contains the navigationType property. Remember to include Platform from react-native.