facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.2k stars 24.33k forks source link

Duplicated letters when autoCapitalize="characters" on android #11068

Closed joncrocks closed 1 year ago

joncrocks commented 7 years ago

Description

When trying to implement an upper case only input, adding autoCapitalize="characters" seems to work on Android by setting the keyboard to be upper case by default. One can hit the shift key and then type a lower case letter.

To ensure that we only let the user enter (and see) upper case letters, I thought that I might be able to handle it by ensuring that when we update the react state of the component we capture the text in upper case.

By using a toUpperCase on top of what is a pretty standard state update cycle (i.e. a very similar update method ala the examples at https://facebook.github.io/react-native/releases/next/docs/textinput.html ), this saves the input into the state, uppercased, ready for the next render cycle. (I'm not concerned about the dangers of toUpperCase at this point.)

Unfortunately, the behaviour is a bit strange when you start typing both upper and lowercase letters, where you start getting repeated letters, e.g. if I type AbC, I will end up with ABABC, AbcdE I get ABABCDABABCDE.

Reproduction

I created an example app here: https://rnplay.org/apps/t-gBOA Note that the behaviour seems fine on the iOS simulator, but is 'wrong' on the android simulator.

or see the component below:

import React, {Component} from "react";
import {View, TextInput} from "react-native";

export class UpperCaseTextEntry extends Component {

    constructor() {
        super();
        this.state = {
            text: ""
        }
    }

    upperCaseIt(text) {
        var textUpperCase = text.toUpperCase();

        this.setState({text: textUpperCase});
    }

    render() {
        var text = this.state.text;
        return (
            <View>
                <TextInput value={text} autoCapitalize="characters"
                           onChangeText={(text) => {this.upperCaseIt(text)}}
                />
            </View>
        )

    }
}

Solution

I suspect that there's something going awry with the syncing of state between the react state and the state of the underlying components, quite possibly some case-ignoring checks are being in some places, but not others.

Additional Information

I've also noted during that it's more than possible to fire multiple onChangeTexts before a render is triggered, which could lead to unexpected app behaviour. This could be expected unexpected behaviour though :-)

kenmasters commented 7 years ago

Are there any updates on these issue already? , I am also experiencing this.

magneticz commented 7 years ago

having same issue with lowercasing, every time a capital case character is entered, the text that is passed to onChangeText function contains exact duplicate of existing text plus last entered character. it happens only on android devices, on ios it works fine

rob-64 commented 7 years ago

Experiencing same with lowercase.

RN: 0.39.2 Phone: samsung galaxy S7

klaasman commented 7 years ago

Any news on this issue?

afilp commented 7 years ago

I have exactly the same problem and cannot release without a fix...

RN: 0.42.3 Phone: Galaxy s6 edge

Is anybody working on this? Thanks.

MSchmidt commented 7 years ago

Same issue.

RN: 0.44.3 Phone: Galaxy S8

Cannot reproduce this in emulator, so maybe something Samsung specific?

skabbes commented 7 years ago

Since the rnplay link is broken, I have recreated it on Expo Snack here:

https://snack.expo.io/S1ksBZsEW

Samsung Galaxy S8 is breaking for me.

andreiAndrade commented 7 years ago

When I disable the "Predictive Text" at "Language and Input > Samsung keyboard settings" the issue is solved, but how to solve that programmatically? :/

JumalDB commented 7 years ago

Same issue

RN: 0.44.0 Phone: Samsung Galaxy S7 Edge

Any fix?

sonikro commented 7 years ago

Same issue. Phone: Samsung Galaxy S7 / Moto Z2 Play Keyboards: Samsung Keyboard (with predict), Swiftkey Keyboard and Google Keyboard RN: react-native@0.47.1

renatoagds commented 7 years ago

Same issue here. Phone: OnePlus 5 Keyboard: Fleksy@8.4.6 RN: 0.46.2

ollyde commented 7 years ago

Same issue here. Android 7.0 emulator, google pixel hardware selected. RN: 0.46.2

vko-online commented 7 years ago

same for Samsung Galaxy @facebook ?

danparker276 commented 7 years ago

What's the work around? Just don't use autocapitalize and your own?

Pianist038801 commented 7 years ago

Experienced same issue. I thought that in Android onChangeText() is triggered multiple times or so. But after checking, it's not what I thought it would be. Totally no hint of solving the issues at this moment.

conor909 commented 7 years ago

Same issue here. It seems to be on any android devices with swipe / SwiftKey keyboards turned on. I think this issue should be escalated as these keyboards come pre-installed on a lot of devices.

williamoliveira commented 7 years ago

Same issue, I was getting paranoid cause I couldn't find the reason For me it doesn't even matter if you set autoCapitalize or not

Do anyone know a workaround?

"react-native": "^0.46.1", Xiaomi Redmi Note 4 Google Keyboard

ankitpopli1891 commented 7 years ago

I stumbled upon the same issue. Found out the autoCapitalize was not working due to fontFamily specified in style prop.

Seems like it was failing silently. Will update here, if I find anything else.

avynarchuk commented 7 years ago

Try to set autoCorrect to false and check if problem exist yet.

MSchmidt commented 7 years ago

It does. autoCorrect has nothing to do with it.

M1chaelTran commented 7 years ago

I have the same issue but found a workaround for my current needs.

The issue can't be re-produce via the simulator using your keyboard. However, if you use the onscreen keyboard, then you can see the text is duplicated.

For my case, since the user can't use a 'keyboard' except for the on-screen keyboard provided. In adding, it only became an issue when I use the text.toUpperCase() Thus, setting the text state in lower case and autoCapitalize="characters" seems to work fine for my case. Of course, if you do not want the user to ever be able to enter lowercase, then this is an issue.

PS: I specified a fontFamily in style and autoCapitalize still work as expected

john1jan commented 7 years ago

I am facing the same issue..

john1jan commented 7 years ago

Any update on this issue . I just tried to use toUpperCase on my textinput. Its dupllicates the characters.

john1jan commented 7 years ago

ezgif com-optimize

tastafur commented 6 years ago

Has anyone found a solution for this bug?, I have the same problem in all samsung that have the predictive language activated

MedinaGitHub commented 6 years ago

the problem is toUpperCase() , i use <TextInput autoCapitalize='characters' ...

MSchmidt commented 6 years ago

@MedinaGitHub of course the problem is the use of toUpperCase(). We use this to enforce uppercase and this causes this bug on Samsung devices.

williamoliveira commented 6 years ago

Not only Samsung

BrunoJAzevedo commented 6 years ago

Not only Samsung devices and I have the same behaviour with toLowerCase()

kasterlod commented 6 years ago

try this: https://github.com/nikolaiwarner/react-native-text-input-reset

jasperkuperus commented 6 years ago

Exact same issue as shown by @john1jan.

React Native: 0.51.0 Android device: OnePlus 3

nickngn commented 6 years ago

@kasterlod Did you success with that solution?

kasterlod commented 6 years ago

@lucinick Yes. In newer version of react-native its fixes so you don't need to use [react-native-text-input-reset] any more

jasperkuperus commented 6 years ago

@kasterlod Is it already fixed? In which React Native version did they fix this?

nickngn commented 6 years ago

@kasterlod Thank for your reply, but my react-native version is 0.44.0 and I wonder that can [react-native-text-input-reset] help me?

nickngn commented 6 years ago

I upgraded my react-native to the latest version 0.55.4 but the issue still isn't solved, any advice?

alliecurry commented 6 years ago

Still seeing this issue with React Native 0.56.0 :(

MeisiLA commented 6 years ago

Issue is not fixed in the newest version. At least for me.

RN: 0.57.1 Samsung J5 with Android 7 Samsung Keyboard

hoangvuanhdevelopervn commented 6 years ago

Duplicate message on android when typing in Vietnamese keyboard, just on android, iOS work fine.

ben-chanathip commented 6 years ago

Has problem in Google keyboard with feature suggestion, just on android, iOS work fine.

iagormoraes commented 6 years ago

This problem still happen with capitalized letters in any situation.

f6m6 commented 5 years ago

😔 This issue is 2 years old, and is affecting our app

lorenc-tomasz commented 5 years ago

The same on 0.57.4

ultrabert commented 5 years ago

Appears to be working on a Samsung S7 (React Native 0.57.4) with (suggested by nathvarun):

<TextInput> ... secureTextEntry={true} keyboardType="visible-password" </TextInput>

joshg111 commented 5 years ago

autoCorrect set to false fixed the issue for me..

iagormoraes commented 5 years ago

Just to remember that testing it on emulators will not show the real problem, I tested on my real device and the problem occurs.

jasperkuperus commented 5 years ago

This issue still happens om 0.57.7... Exactly as shown by @john1jan

mauricioscotton commented 5 years ago

Just to remember that testing it on emulators will not show the real problem, I tested on my real device and the problem occurs.

For me It still happens on both. =(

I've managed to find the bug and in runtime trick it to make it work...

Apparently, when we setText natively, we have two different text informations. (AGAIN, THIS BUG ONLY HAPPENS WHEN YOU USE UPPERCASE OF LOWERCASE)

So, I've end up on inner android classes and I've noticed that the dupe of characters happens on this line: image

The reason why it happens is that we have two different texts. Let's say that we've added "a" and then after onTextChange JavaScript event, we changed it to "A"... On the native side, even though we see "A", somehow "a" still there. When this line is executed: image

We still are going to be able to see it on the visual element displaying the correct char.(line after) image

Now, after this, we should have two versions of the text, therefore, the next char will be duped as we remained with "a" inside the native component and "A" on the visual part.... Here is the proof that we remained with "a" instead of "A" inside of the native component somehow: image

Now, on: BaseInputConnection.java@843, it will try to replace the text "A" for "ab": image

Logically, replacing "A"@Position:1, by "ab", we will end up with: "Aab"....

(Variables at the moment:) image image image

AAAnddd, voila: image (Our text is now "Aab")

After all of that, our text.toUpperCase(), will be fired on JavaScript side, and the method receiver on native side is: maybeSetText@ReactEdittext.java:359 image Then if we inspect getText(), this instance will be with our correct text, but somehow, it will break when changing by default Android classes... image

AND, IF WE execute this line every time on the Evaluate screen right after getText().replace.... image

The bug disappears: image

mauricioscotton commented 5 years ago

Also, to reproduce it, just drop a TextInput like this:

<TextInput ref={(el) => this.input = el} onChangeText={(val) => { this.input.setNativeProps({text: val.toUpperCase()}); }}/>

and on ReactEditText.java@381, change:

getText().replace(0, length(), spannableStringBuilder);

for:

setText(spannableStringBuilder);
mauricioscotton commented 5 years ago

@hramos, Have a look mate! =D

Removed original quoting...