未验证 提交 9ab6550b 编写于 作者: C chunhtai 提交者: GitHub

Introduce read only text field semantics (#9281)

上级 a263abfb
...@@ -576,6 +576,11 @@ class SemanticsObject { ...@@ -576,6 +576,11 @@ class SemanticsObject {
/// Whether this object represents an editable text field. /// Whether this object represents an editable text field.
bool get isTextField => hasFlag(ui.SemanticsFlag.isTextField); bool get isTextField => hasFlag(ui.SemanticsFlag.isTextField);
/// Whether this object is read only.
///
/// Only applicable when [isTextField] is true.
bool get isReadOnly => hasFlag(ui.SemanticsFlag.isReadOnly);
/// Whether this object represents an image with no tappable functionality. /// Whether this object represents an image with no tappable functionality.
bool get isVisualOnly => bool get isVisualOnly =>
hasFlag(ui.SemanticsFlag.isImage) && hasFlag(ui.SemanticsFlag.isImage) &&
......
...@@ -298,6 +298,7 @@ class SemanticsFlag { ...@@ -298,6 +298,7 @@ class SemanticsFlag {
static const int _kIsToggledIndex = 1 << 17; static const int _kIsToggledIndex = 1 << 17;
static const int _kHasImplicitScrollingIndex = 1 << 18; static const int _kHasImplicitScrollingIndex = 1 << 18;
static const int _kIsMultilineIndex = 1 << 19; static const int _kIsMultilineIndex = 1 << 19;
static const int _kIsReadOnlyIndex = 1 << 20;
const SemanticsFlag._(this.index); const SemanticsFlag._(this.index);
...@@ -354,6 +355,12 @@ class SemanticsFlag { ...@@ -354,6 +355,12 @@ class SemanticsFlag {
static const SemanticsFlag isTextField = static const SemanticsFlag isTextField =
const SemanticsFlag._(_kIsTextFieldIndex); const SemanticsFlag._(_kIsTextFieldIndex);
/// Whether the semantic node is read only.
///
/// Only applicable when [isTextField] is true.
static const SemanticsFlag isReadOnly =
const SemanticsFlag._(_kIsReadOnlyIndex);
/// Whether the semantic node currently holds the user's focus. /// Whether the semantic node currently holds the user's focus.
/// ///
/// The focused element is usually the current receiver of keyboard inputs. /// The focused element is usually the current receiver of keyboard inputs.
...@@ -539,6 +546,7 @@ class SemanticsFlag { ...@@ -539,6 +546,7 @@ class SemanticsFlag {
_kIsToggledIndex: isToggled, _kIsToggledIndex: isToggled,
_kHasImplicitScrollingIndex: hasImplicitScrolling, _kHasImplicitScrollingIndex: hasImplicitScrolling,
_kIsMultilineIndex: isMultiline, _kIsMultilineIndex: isMultiline,
_kIsReadOnlyIndex: isReadOnly,
}; };
@override @override
...@@ -584,6 +592,8 @@ class SemanticsFlag { ...@@ -584,6 +592,8 @@ class SemanticsFlag {
return 'SemanticsFlag.hasImplicitScrolling'; return 'SemanticsFlag.hasImplicitScrolling';
case _kIsMultilineIndex: case _kIsMultilineIndex:
return 'SemanticsFlag.isMultiline'; return 'SemanticsFlag.isMultiline';
case _kIsReadOnlyIndex:
return 'SemanticsFlag.isReadOnly';
} }
return null; return null;
} }
......
...@@ -288,6 +288,7 @@ class SemanticsFlag { ...@@ -288,6 +288,7 @@ class SemanticsFlag {
static const int _kHasToggledStateIndex = 1 << 16; static const int _kHasToggledStateIndex = 1 << 16;
static const int _kIsToggledIndex = 1 << 17; static const int _kIsToggledIndex = 1 << 17;
static const int _kHasImplicitScrollingIndex = 1 << 18; static const int _kHasImplicitScrollingIndex = 1 << 18;
static const int _kIsReadOnlyIndex = 1 << 20;
const SemanticsFlag._(this.index); const SemanticsFlag._(this.index);
...@@ -341,6 +342,11 @@ class SemanticsFlag { ...@@ -341,6 +342,11 @@ class SemanticsFlag {
/// affordances. /// affordances.
static const SemanticsFlag isTextField = SemanticsFlag._(_kIsTextFieldIndex); static const SemanticsFlag isTextField = SemanticsFlag._(_kIsTextFieldIndex);
/// Whether the semantic node is read only.
///
/// Only applicable when [isTextField] is true.
static const SemanticsFlag isReadOnly = SemanticsFlag._(_kIsReadOnlyIndex);
/// Whether the semantic node currently holds the user's focus. /// Whether the semantic node currently holds the user's focus.
/// ///
/// The focused element is usually the current receiver of keyboard inputs. /// The focused element is usually the current receiver of keyboard inputs.
...@@ -506,6 +512,7 @@ class SemanticsFlag { ...@@ -506,6 +512,7 @@ class SemanticsFlag {
_kHasToggledStateIndex: hasToggledState, _kHasToggledStateIndex: hasToggledState,
_kIsToggledIndex: isToggled, _kIsToggledIndex: isToggled,
_kHasImplicitScrollingIndex: hasImplicitScrolling, _kHasImplicitScrollingIndex: hasImplicitScrolling,
_kIsReadOnlyIndex: isReadOnly,
}; };
@override @override
...@@ -549,6 +556,8 @@ class SemanticsFlag { ...@@ -549,6 +556,8 @@ class SemanticsFlag {
return 'SemanticsFlag.isToggled'; return 'SemanticsFlag.isToggled';
case _kHasImplicitScrollingIndex: case _kHasImplicitScrollingIndex:
return 'SemanticsFlag.hasImplicitScrolling'; return 'SemanticsFlag.hasImplicitScrolling';
case _kIsReadOnlyIndex:
return 'SemanticsFlag.isReadOnly';
} }
return null; return null;
} }
......
...@@ -69,6 +69,7 @@ enum class SemanticsFlags : int32_t { ...@@ -69,6 +69,7 @@ enum class SemanticsFlags : int32_t {
kHasToggledState = 1 << 16, kHasToggledState = 1 << 16,
kIsToggled = 1 << 17, kIsToggled = 1 << 17,
kHasImplicitScrolling = 1 << 18, kHasImplicitScrolling = 1 << 18,
kIsReadOnly = 1 << 20,
}; };
const int kScrollableSemanticsFlags = const int kScrollableSemanticsFlags =
......
...@@ -529,9 +529,11 @@ public class AccessibilityBridge extends AccessibilityNodeProvider { ...@@ -529,9 +529,11 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
if (semanticsNode.hasFlag(Flag.IS_TEXT_FIELD)) { if (semanticsNode.hasFlag(Flag.IS_TEXT_FIELD)) {
result.setPassword(semanticsNode.hasFlag(Flag.IS_OBSCURED)); result.setPassword(semanticsNode.hasFlag(Flag.IS_OBSCURED));
result.setClassName("android.widget.EditText"); if (!semanticsNode.hasFlag(Flag.IS_READ_ONLY)) {
result.setClassName("android.widget.EditText");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
result.setEditable(true); result.setEditable(!semanticsNode.hasFlag(Flag.IS_READ_ONLY));
if (semanticsNode.textSelectionBase != -1 && semanticsNode.textSelectionExtent != -1) { if (semanticsNode.textSelectionBase != -1 && semanticsNode.textSelectionExtent != -1) {
result.setTextSelection(semanticsNode.textSelectionBase, semanticsNode.textSelectionExtent); result.setTextSelection(semanticsNode.textSelectionBase, semanticsNode.textSelectionExtent);
} }
...@@ -1611,7 +1613,8 @@ public class AccessibilityBridge extends AccessibilityNodeProvider { ...@@ -1611,7 +1613,8 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
IS_LIVE_REGION(1 << 15), IS_LIVE_REGION(1 << 15),
HAS_TOGGLED_STATE(1 << 16), HAS_TOGGLED_STATE(1 << 16),
IS_TOGGLED(1 << 17), IS_TOGGLED(1 << 17),
HAS_IMPLICIT_SCROLLING(1 << 18); HAS_IMPLICIT_SCROLLING(1 << 18),
IS_READ_ONLY(1 << 20);
final int value; final int value;
......
...@@ -713,7 +713,8 @@ SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid, ...@@ -713,7 +713,8 @@ SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid,
if (!object) { if (!object) {
// New node case: simply create a new SemanticsObject. // New node case: simply create a new SemanticsObject.
flutter::SemanticsNode node = updates[uid]; flutter::SemanticsNode node = updates[uid];
if (node.HasFlag(flutter::SemanticsFlags::kIsTextField)) { if (node.HasFlag(flutter::SemanticsFlags::kIsTextField) &&
!node.HasFlag(flutter::SemanticsFlags::kIsReadOnly)) {
// Text fields are backed by objects that implement UITextInput. // Text fields are backed by objects that implement UITextInput.
object = [[[TextInputSemanticsObject alloc] initWithBridge:GetWeakPtr() uid:uid] autorelease]; object = [[[TextInputSemanticsObject alloc] initWithBridge:GetWeakPtr() uid:uid] autorelease];
} else { } else {
...@@ -729,13 +730,16 @@ SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid, ...@@ -729,13 +730,16 @@ SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid,
flutter::SemanticsNode node = nodeEntry->second; flutter::SemanticsNode node = nodeEntry->second;
BOOL isTextField = node.HasFlag(flutter::SemanticsFlags::kIsTextField); BOOL isTextField = node.HasFlag(flutter::SemanticsFlags::kIsTextField);
BOOL wasTextField = object.node.HasFlag(flutter::SemanticsFlags::kIsTextField); BOOL wasTextField = object.node.HasFlag(flutter::SemanticsFlags::kIsTextField);
if (wasTextField != isTextField) { BOOL isReadOnly = node.HasFlag(flutter::SemanticsFlags::kIsReadOnly);
BOOL wasReadOnly = object.node.HasFlag(flutter::SemanticsFlags::kIsReadOnly);
if (wasTextField != isTextField || isReadOnly != wasReadOnly) {
// The node changed its type from text field to something else, or vice versa. In this // The node changed its type from text field to something else, or vice versa. In this
// case, we cannot reuse the existing SemanticsObject implementation. Instead, we replace // case, we cannot reuse the existing SemanticsObject implementation. Instead, we replace
// it with a new instance. // it with a new instance.
NSUInteger positionInChildlist = [object.parent.children indexOfObject:object]; NSUInteger positionInChildlist = [object.parent.children indexOfObject:object];
SemanticsObject* parent = object.parent;
[objects_ removeObjectForKey:@(node.id)]; [objects_ removeObjectForKey:@(node.id)];
if (isTextField) { if (isTextField && !isReadOnly) {
// Text fields are backed by objects that implement UITextInput. // Text fields are backed by objects that implement UITextInput.
object = [[[TextInputSemanticsObject alloc] initWithBridge:GetWeakPtr() object = [[[TextInputSemanticsObject alloc] initWithBridge:GetWeakPtr()
uid:uid] autorelease]; uid:uid] autorelease];
...@@ -743,6 +747,7 @@ SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid, ...@@ -743,6 +747,7 @@ SemanticsObject* AccessibilityBridge::GetOrCreateObject(int32_t uid,
object = [[[FlutterSemanticsObject alloc] initWithBridge:GetWeakPtr() object = [[[FlutterSemanticsObject alloc] initWithBridge:GetWeakPtr()
uid:uid] autorelease]; uid:uid] autorelease];
} }
object.parent = parent;
[object.parent.children replaceObjectAtIndex:positionInChildlist withObject:object]; [object.parent.children replaceObjectAtIndex:positionInChildlist withObject:object];
objects_.get()[@(node.id)] = object; objects_.get()[@(node.id)] = object;
} }
......
...@@ -153,6 +153,10 @@ typedef enum { ...@@ -153,6 +153,10 @@ typedef enum {
// |PageView| widget does not have implicit scrolling, so that users don't // |PageView| widget does not have implicit scrolling, so that users don't
// navigate to the next page when reaching the end of the current one. // navigate to the next page when reaching the end of the current one.
kFlutterSemanticsFlagHasImplicitScrolling = 1 << 18, kFlutterSemanticsFlagHasImplicitScrolling = 1 << 18,
// Whether the semantic node is read only.
//
// Only applicable when kFlutterSemanticsFlagIsTextField flag is on.
kFlutterSemanticsFlagIsReadOnly = 1 << 20,
} FlutterSemanticsFlag; } FlutterSemanticsFlag;
typedef enum { typedef enum {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册