Comparison of AttributedString false more often than true in TextInput, resulting in janky editing behavior

Summary:
Instead of comparing the entire AttributedString, compare just the strings and the TextAttributes of Fragments.

Concretely what I'm seeing is that the Frame of the associated parent ShadowViews are changing very frequently, making it impossible to actually modify the TextInput in some cases. However, we shouldn't forcibly reset the content of the TextInput if the frame of the parent is changing and not the actual child contents.

Changelog: [Internal] Fabric TextInput bug fix

Reviewed By: shergin

Differential Revision: D20319359

fbshipit-source-id: 2f51f521ad76fff9da6f6c8b5e795f03c33e496f
This commit is contained in:
Joshua Gross 2020-03-06 19:31:58 -08:00 коммит произвёл Facebook Github Bot
Родитель 074a2fab74
Коммит c18cc76e58
3 изменённых файлов: 31 добавлений и 3 удалений

Просмотреть файл

@ -98,6 +98,22 @@ bool AttributedString::isEmpty() const {
return fragments_.empty();
}
bool AttributedString::compareTextAttributesWithoutFrame(
const AttributedString &rhs) const {
if (fragments_.size() != rhs.fragments_.size()) {
return false;
}
for (unsigned i = 0; i < fragments_.size(); i++) {
if (fragments_[i].textAttributes != rhs.fragments_[i].textAttributes ||
fragments_[i].string != rhs.fragments_[i].string) {
return false;
}
}
return true;
}
bool AttributedString::operator==(const AttributedString &rhs) const {
return fragments_ == rhs.fragments_;
}

Просмотреть файл

@ -87,6 +87,11 @@ class AttributedString : public Sealable, public DebugStringConvertible {
*/
bool isEmpty() const;
/**
* Compares equality of TextAttributes of all Fragments on both sides.
*/
bool compareTextAttributesWithoutFrame(const AttributedString &rhs) const;
bool operator==(const AttributedString &rhs) const;
bool operator!=(const AttributedString &rhs) const;

Просмотреть файл

@ -94,10 +94,17 @@ AttributedString AndroidTextInputShadowNode::getMostRecentAttributedString()
auto reactTreeAttributedString = getAttributedString();
// Sometimes the treeAttributedString will only differ from the state
// not by inherent properties (string or prop attributes), but by the frame of
// the parent which has changed Thus, we can't directly compare the entire
// AttributedString
bool treeAttributedStringChanged =
!state.reactTreeAttributedString.compareTextAttributesWithoutFrame(
reactTreeAttributedString);
return (
state.reactTreeAttributedString == reactTreeAttributedString
? state.attributedString
: reactTreeAttributedString);
!treeAttributedStringChanged ? state.attributedString
: reactTreeAttributedString);
}
void AndroidTextInputShadowNode::updateStateIfNeeded() {