浏览代码

Merge pull request #58 from fzhangtj/text_edit

text field
/main
GitHub 6 年前
当前提交
fd26e5ca
共有 10 个文件被更改,包括 722 次插入136 次删除
  1. 129
      Runtime/material/input_decorator.cs
  2. 108
      Runtime/material/text_selection.cs
  3. 17
      Runtime/rendering/editable.cs
  4. 7
      Runtime/service/keyboard.cs
  5. 27
      Runtime/service/text_formatter.cs
  6. 38
      Runtime/widgets/editable_text.cs
  7. 444
      Runtime/material/text_field.cs
  8. 11
      Runtime/material/text_field.cs.meta
  9. 66
      Samples/UIWidgetSample/txt/TextFieldSample.cs
  10. 11
      Samples/UIWidgetSample/txt/TextFieldSample.cs.meta

129
Runtime/material/input_decorator.cs


}
class _InputBorderGap : ChangeNotifier {
class _InputBorderGap : ChangeNotifier, IEquatable<_InputBorderGap> {
float _start;
public float start {

}
}
public static bool operator ==(_InputBorderGap left, _InputBorderGap right) {
return left.Equals(right);
}
public bool Equals(_InputBorderGap other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
public static bool operator !=(_InputBorderGap left, _InputBorderGap other) {
return left.start != other.start || left.extent != other.extent;
return this.start == other.start && this.extent == other._extent;
public bool Equals(_InputBorderGap other) {
return this.start == other.start && this.extent == other.extent;
}
return (this.start.GetHashCode() * 397) ^ this.extent.GetHashCode();
return (this._start.GetHashCode() * 397) ^ this._extent.GetHashCode();
}
public static bool operator ==(_InputBorderGap left, _InputBorderGap right) {
return Equals(left, right);
}
public static bool operator !=(_InputBorderGap left, _InputBorderGap right) {
return !Equals(left, right);
}
}

container
}
class _Decoration {
class _Decoration : IEquatable<_Decoration> {
public _Decoration(
EdgeInsets contentPadding,
bool isCollapsed,

public readonly Widget counter;
public readonly Widget container;
public static bool operator ==(_Decoration left, _Decoration right) {
return left.Equals(right);
}
public bool Equals(_Decoration other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
public static bool operator !=(_Decoration left, _Decoration right) {
return !left.Equals(right);
return Equals(this.contentPadding, other.contentPadding) && this.isCollapsed == other.isCollapsed &&
this.floatingLabelHeight.Equals(other.floatingLabelHeight) &&
this.floatingLabelProgress.Equals(other.floatingLabelProgress) &&
Equals(this.border, other.border) && Equals(this.borderGap, other.borderGap) &&
Equals(this.icon, other.icon) && Equals(this.input, other.input) &&
Equals(this.label, other.label) && Equals(this.hint, other.hint) &&
Equals(this.prefix, other.prefix) && Equals(this.suffix, other.suffix) &&
Equals(this.prefixIcon, other.prefixIcon) && Equals(this.suffixIcon, other.suffixIcon) &&
Equals(this.helperError, other.helperError) && Equals(this.counter, other.counter) &&
Equals(this.container, other.container);
public bool Equals(_Decoration other) {
return this.contentPadding == other.contentPadding
&& this.floatingLabelHeight == other.floatingLabelHeight
&& this.floatingLabelProgress == other.floatingLabelProgress
&& this.border == other.border
&& this.borderGap == other.borderGap
&& this.icon == other.icon
&& this.input == other.input
&& this.label == other.label
&& this.hint == other.hint
&& this.prefix == other.prefix
&& this.suffix == other.suffix
&& this.prefixIcon == other.prefixIcon
&& this.suffixIcon == other.suffixIcon
&& this.helperError == other.helperError
&& this.counter == other.counter
&& this.container == other.container;
}
var hashCode = this.contentPadding.GetHashCode();
var hashCode = (this.contentPadding != null ? this.contentPadding.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.isCollapsed.GetHashCode();
hashCode = (hashCode * 397) ^ this.border.GetHashCode();
hashCode = (hashCode * 397) ^ this.borderGap.GetHashCode();
hashCode = (hashCode * 397) ^ this.icon.GetHashCode();
hashCode = (hashCode * 397) ^ this.input.GetHashCode();
hashCode = (hashCode * 397) ^ this.label.GetHashCode();
hashCode = (hashCode * 397) ^ this.hint.GetHashCode();
hashCode = (hashCode * 397) ^ this.prefix.GetHashCode();
hashCode = (hashCode * 397) ^ this.suffix.GetHashCode();
hashCode = (hashCode * 397) ^ this.prefixIcon.GetHashCode();
hashCode = (hashCode * 397) ^ this.suffixIcon.GetHashCode();
hashCode = (hashCode * 397) ^ this.helperError.GetHashCode();
hashCode = (hashCode * 397) ^ this.counter.GetHashCode();
hashCode = (hashCode * 397) ^ this.container.GetHashCode();
hashCode = (hashCode * 397) ^ (this.border != null ? this.border.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.borderGap != null ? this.borderGap.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.icon != null ? this.icon.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.input != null ? this.input.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.label != null ? this.label.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.hint != null ? this.hint.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.prefix != null ? this.prefix.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.suffix != null ? this.suffix.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.prefixIcon != null ? this.prefixIcon.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.suffixIcon != null ? this.suffixIcon.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.helperError != null ? this.helperError.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.counter != null ? this.counter.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.container != null ? this.container.GetHashCode() : 0);
public static bool operator ==(_Decoration left, _Decoration right) {
return Equals(left, right);
}
public static bool operator !=(_Decoration left, _Decoration right) {
return !Equals(left, right);
}
}
class _RenderDecorationLayout {

}
void _mountChild(Widget widget, _DecorationSlot slot) {
Element oldChild = this.slotToChild[slot];
Element oldChild = this.slotToChild.getOrDefault(slot);
Element newChild = this.updateChild(oldChild, widget, slot);
if (oldChild != null) {
this.slotToChild.Remove(slot);

}
void _updateChild(Widget widget, _DecorationSlot slot) {
Element oldChild = this.slotToChild[slot];
Element newChild = this.updateChild(oldChild, this.widget, slot);
Element oldChild = this.slotToChild.getOrDefault(slot);
Element newChild = this.updateChild(oldChild, widget, slot);
if (oldChild != null) {
this.childToSlot.Remove(oldChild);
this.slotToChild.Remove(slot);

return new _InputDecoratorState();
}
static RenderBox containerOf(BuildContext context) {
internal static RenderBox containerOf(BuildContext context) {
_RenderDecoration result =
(_RenderDecoration) context.ancestorRenderObjectOfType(new TypeMatcher<_RenderDecoration>());
return result?.container;

}
public static bool operator ==(InputDecoration left, InputDecoration right) {
return left.Equals(right);
return Equals(left, right);
return !left.Equals(right);
return !Equals(left, right);
}
public bool Equals(InputDecoration other) {

108
Runtime/material/text_selection.cs


using Rect = Unity.UIWidgets.ui.Rect;
using Transform = Unity.UIWidgets.widgets.Transform;
// todo using material components: FlatButton & Material ...
}
static class _TextSelectionUtils {
public _TextSelectionToolbar(Key key = null, Action handleCut = null,
Action handleCopy = null, Action handlePaste = null, Action handleSelectAll = null) : base(key: key) {
public _TextSelectionToolbar(Key key = null, VoidCallback handleCut = null,
VoidCallback handleCopy = null, VoidCallback handlePaste = null, VoidCallback handleSelectAll = null) : base(key: key) {
this.handleCut = handleCut;
this.handleCopy = handleCopy;
this.handlePaste = handlePaste;

public readonly Action handleCut;
public readonly Action handleCopy;
public readonly Action handlePaste;
public readonly Action handleSelectAll;
public readonly VoidCallback handleCut;
public readonly VoidCallback handleCopy;
public readonly VoidCallback handlePaste;
public readonly VoidCallback handleSelectAll;
MaterialLocalizations localizations = MaterialLocalizations.of(context);
items.Add(new _TempButton(onPressed: () => this.handleCut(), child: new Text("Cut")));
items.Add(new FlatButton(child: new Text(localizations.cutButtonLabel), onPressed: this.handleCut));
items.Add(new _TempButton(onPressed: () => this.handleCopy(), child: new Text("Copy")));
items.Add(new FlatButton(child: new Text(localizations.copyButtonLabel), onPressed: this.handleCopy));
items.Add(new _TempButton(onPressed: () => this.handlePaste(), child: new Text("Past")));
items.Add(new FlatButton(child: new Text(localizations.pasteButtonLabel), onPressed: this.handlePaste));
items.Add(new _TempButton(onPressed: () => this.handleSelectAll(), child: new Text("Select All")));
items.Add(new FlatButton(child: new Text(localizations.selectAllButtonLabel),
onPressed: this.handleSelectAll));
return new Container(
color: new Color(0xFFEFEFEF),
height: 44.0f, child: new Row(mainAxisSize: MainAxisSize.min, children: items));
return new Material(
elevation: 1.0f,
child: new Container(
color: new Color(0xFFEFEFEF),
height: 44.0f, child: new Row(mainAxisSize: MainAxisSize.min, children: items))
);
}
}

float x = globalPosition.dx - childSize.width / 2.0f;
float y = globalPosition.dy - childSize.height;
if (x < _TextSelectionUtils._kToolbarScreenPadding) {
x = _TextSelectionUtils._kToolbarScreenPadding;
if (x < MaterialUtils._kToolbarScreenPadding) {
x = MaterialUtils._kToolbarScreenPadding;
else if (x + childSize.width > this.screenSize.width - _TextSelectionUtils._kToolbarScreenPadding) {
x = this.screenSize.width - childSize.width - _TextSelectionUtils._kToolbarScreenPadding;
else if (x + childSize.width > this.screenSize.width - MaterialUtils._kToolbarScreenPadding) {
x = this.screenSize.width - childSize.width - MaterialUtils._kToolbarScreenPadding;
if (y < _TextSelectionUtils._kToolbarScreenPadding) {
y = _TextSelectionUtils._kToolbarScreenPadding;
if (y < MaterialUtils._kToolbarScreenPadding) {
y = MaterialUtils._kToolbarScreenPadding;
else if (y + childSize.height > this.screenSize.height - _TextSelectionUtils._kToolbarScreenPadding) {
y = this.screenSize.height - childSize.height - _TextSelectionUtils._kToolbarScreenPadding;
else if (y + childSize.height > this.screenSize.height - MaterialUtils._kToolbarScreenPadding) {
y = this.screenSize.height - childSize.height - MaterialUtils._kToolbarScreenPadding;
}
return new Offset(x, y);

class _MaterialTextSelectionControls : TextSelectionControls {
public override Size handleSize {
get {
return new Size(_TextSelectionUtils._kHandleSize,
_TextSelectionUtils._kHandleSize);
return new Size(MaterialUtils._kHandleSize,
MaterialUtils._kHandleSize);
}
}

child: new _TextSelectionToolbar(
handleCut: this.canCut(selectionDelegate)
? () => this.handleCut(selectionDelegate)
: (Action) null,
: (VoidCallback) null,
: (Action) null,
: (VoidCallback) null,
: (Action) null,
: (VoidCallback) null,
: (Action) null
: (VoidCallback) null
)
)
);

Widget handle = new Padding(
padding: EdgeInsets.only(right: 26.0f, bottom: 26.0f),
child: new SizedBox(
width: 20,
height: 20,
width: MaterialUtils._kHandleSize,
height: MaterialUtils._kHandleSize,
color: new Color(0xFFFF0000)
color: Theme.of(context).textSelectionHandleColor
)
)
)

}
return null;
}
}
public class _TempButton : StatelessWidget {
public _TempButton(
Key key = null,
GestureTapCallback onPressed = null,
EdgeInsets padding = null,
Color backgroundColor = null,
Widget child = null
) : base(key: key) {
this.onPressed = onPressed;
this.padding = padding ?? EdgeInsets.all(8.0f);
this.backgroundColor = backgroundColor ?? new Color(0);
this.child = child;
}
public readonly GestureTapCallback onPressed;
public readonly EdgeInsets padding;
public readonly Widget child;
public readonly Color backgroundColor;
public override Widget build(BuildContext context) {
return new GestureDetector(
onTap: this.onPressed,
child: new Container(
padding: this.padding,
color: this.backgroundColor,
child: this.child
)
);
}
}
}

17
Runtime/rendering/editable.cs


public static readonly char obscuringCharacter = '•';
static readonly float _kCaretGap = 1.0f;
static readonly float _kCaretHeightOffset = 2.0f;
static readonly float _kCaretWidth = 1.0f;
TextPainter _textPainter;
Color _cursorColor;

bool? hasFocus = null, int? maxLines = 1, Color selectionColor = null,
TextSelection selection = null, bool obscureText = false, SelectionChangedHandler onSelectionChanged = null,
CaretChangedHandler onCaretChanged = null, bool ignorePointer = false,
float cursorWidth = 1.0f,
Radius cursorRadius = null,
bool enableInteractiveSelection = true,
TextSelectionDelegate textSelectionDelegate = null) {
D.assert(textSelectionDelegate != null);
this._textPainter = new TextPainter(text: text, textAlign: textAlign, textDirection: textDirection,

this._selection = selection;
this._obscureText = obscureText;
this._offset = offset;
this._cursorWidth = cursorWidth;
this._cursorRadius = cursorRadius;
this._enableInteractiveSelection = enableInteractiveSelection;
this.ignorePointer = ignorePointer;
this.onCaretChanged = onCaretChanged;
this.onSelectionChanged = onSelectionChanged;

public Rect getLocalRectForCaret(TextPosition caretPosition) {
this._layoutText(this.constraints.maxWidth);
var caretOffset = this._textPainter.getOffsetForCaret(caretPosition, this._caretPrototype);
return Rect.fromLTWH(0.0f, 0.0f, _kCaretWidth, this.preferredLineHeight)
return Rect.fromLTWH(0.0f, 0.0f, this.cursorWidth, this.preferredLineHeight)
.shift(caretOffset + this._paintOffset);
}

}
}
void handleTapDown(TapDownDetails details) {
public void handleTapDown(TapDownDetails details) {
this._lastTapDownPosition = details.globalPosition + - this._paintOffset;
if (!Application.isMobilePlatform) {
this.selectPosition(SelectionChangedCause.tap);

return;
}
var caretMargin = _kCaretGap + _kCaretWidth;
var caretMargin = _kCaretGap + this.cursorWidth;
var avialableWidth = Mathf.Max(0.0f, constraintWidth - caretMargin);
var maxWidth = this._isMultiline ? avialableWidth : float.PositiveInfinity;
this._textPainter.layout(minWidth: avialableWidth, maxWidth: maxWidth);

protected override void performLayout() {
this._layoutText(this.constraints.maxWidth);
this._caretPrototype = Rect.fromLTWH(0.0f, _kCaretHeightOffset, _kCaretWidth,
this._caretPrototype = Rect.fromLTWH(0.0f, _kCaretHeightOffset, this.cursorWidth,
this.preferredLineHeight - 2.0f * _kCaretHeightOffset);
this._selectionRects = null;

var contentSize = new Size(textPainterSize.width + _kCaretGap + _kCaretWidth,
var contentSize = new Size(textPainterSize.width + _kCaretGap + this.cursorWidth,
textPainterSize.height);
var _maxScrollExtent = this._getMaxScrollExtend(contentSize);
this._hasVisualOverflow = _maxScrollExtent > 0.0;

7
Runtime/service/keyboard.cs


}
abstract class AbstractUIWidgetsKeyboardDelegate : KeyboardDelegate {
UIWidgetsMessageManager.instance.AddChannelMessageDelegate("TextInput", this._handleMethodCall);
UIWidgetsMessageManager.instance.
AddChannelMessageDelegate("TextInput", this._handleMethodCall);
UIWidgetsMessageManager.instance.RemoveChannelMessageDelegate("TextInput", this._handleMethodCall);
UIWidgetsMessageManager.instance.
RemoveChannelMessageDelegate("TextInput", this._handleMethodCall);
}
public abstract void show();

27
Runtime/service/text_formatter.cs


(substring) => this.blacklistedPattern.Replace(substring, this.replacementString));
}
}
public class LengthLimitingTextInputFormatter : TextInputFormatter {
public LengthLimitingTextInputFormatter(int? maxLength) {
D.assert(maxLength == null || maxLength > 0);
this.maxLength = maxLength;
}
public readonly int? maxLength;
public override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
if (this.maxLength != null && newValue.text.Length > this.maxLength) {
TextSelection newSelection = newValue.selection.copyWith(
baseOffset: Math.Min(newValue.selection.start, this.maxLength.Value),
extentOffset: Math.Min(newValue.selection.end, this.maxLength.Value)
);
string truncated = newValue.text.Substring(0, this.maxLength.Value);
return new TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty
);
}
return newValue;
}
}
static class Util {
internal static TextEditingValue _selectionAwareTextManipulation(TextEditingValue value,

38
Runtime/widgets/editable_text.cs


public delegate void SelectionChangedCallback(TextSelection selection, SelectionChangedCause cause);
public class TextEditingController : ValueNotifier<TextEditingValue> {
public TextEditingController(string text) : base(text == null
public TextEditingController(string text = null) : base(text == null
? TextEditingValue.empty
: new TextEditingValue(text)) {
}

public TextEditingController fromValue(TextEditingValue value) {
public static TextEditingController fromValue(TextEditingValue value) {
return new TextEditingController(value);
}

ValueChanged<string> onSubmitted = null, SelectionChangedCallback onSelectionChanged = null,
List<TextInputFormatter> inputFormatters = null, bool rendererIgnoresPointer = false,
EdgeInsets scrollPadding = null, bool unityTouchKeyboard = false,
Key key = null) : base(key) {
Key key = null, float? cursorWidth = 2.0f, Radius cursorRadius = null, Brightness? keyboardAppearance = Brightness.light,
bool enableInteractiveSelection = true
) : base(key) {
D.assert(controller != null);
D.assert(focusNode != null);
D.assert(style != null);

else {
this.inputFormatters = inputFormatters;
}
this.cursorWidth = cursorWidth;
this.cursorRadius = cursorRadius;
this.keyboardAppearance = keyboardAppearance;
this.enableInteractiveSelection = enableInteractiveSelection;
public readonly float? cursorWidth;
public readonly Radius cursorRadius;
public readonly Brightness? keyboardAppearance;
public readonly bool enableInteractiveSelection;
public override State createState() {
return new EditableTextState();
}

? TextInputAction.newline
: TextInputAction.done),
textCapitalization: this.widget.textCapitalization,
keyboardAppearance: this.widget.keyboardAppearance??Brightness.light,
unityTouchKeyboard: this.widget.unityTouchKeyboard
));

onSelectionChanged: this._handleSelectionChanged,
onCaretChanged: this._handleCaretChanged,
rendererIgnoresPointer: this.widget.rendererIgnoresPointer,
cursorWidth: this.widget.cursorWidth,
cursorRadius: this.widget.cursorRadius,
enableInteractiveSelection: this.widget.enableInteractiveSelection,
textSelectionDelegate: this
)
)

public readonly SelectionChangedHandler onSelectionChanged;
public readonly CaretChangedHandler onCaretChanged;
public readonly bool rendererIgnoresPointer;
public readonly float? cursorWidth;
public readonly Radius cursorRadius;
public readonly bool enableInteractiveSelection;
public readonly TextSelectionDelegate textSelectionDelegate;

TextDirection? textDirection = null, bool obscureText = false, TextAlign textAlign = TextAlign.left,
bool autocorrect = false, ViewportOffset offset = null, SelectionChangedHandler onSelectionChanged = null,
CaretChangedHandler onCaretChanged = null, bool rendererIgnoresPointer = false,
Key key = null, TextSelectionDelegate textSelectionDelegate = null) : base(key) {
Key key = null, TextSelectionDelegate textSelectionDelegate = null, float? cursorWidth = null,
Radius cursorRadius = null, bool enableInteractiveSelection = true) : base(key) {
this.textSpan = textSpan;
this.value = value;
this.cursorColor = cursorColor;

this.onCaretChanged = onCaretChanged;
this.rendererIgnoresPointer = rendererIgnoresPointer;
this.textSelectionDelegate = textSelectionDelegate;
this.cursorWidth = cursorWidth;
this.cursorRadius = cursorRadius;
this.enableInteractiveSelection = enableInteractiveSelection;
}
public override RenderObject createRenderObject(BuildContext context) {

onSelectionChanged: this.onSelectionChanged,
onCaretChanged: this.onCaretChanged,
ignorePointer: this.rendererIgnoresPointer,
cursorWidth: this.cursorWidth??1.0f,
cursorRadius: this.cursorRadius,
enableInteractiveSelection: this.enableInteractiveSelection,
textSelectionDelegate: this.textSelectionDelegate
);
}

edit.ignorePointer = this.rendererIgnoresPointer;
edit.obscureText = this.obscureText;
edit.textSelectionDelegate = this.textSelectionDelegate;
edit.cursorWidth = this.cursorWidth ?? 1.0f;
edit.cursorRadius = this.cursorRadius;
edit.enableInteractiveSelection = this.enableInteractiveSelection;
}
}
}

444
Runtime/material/text_field.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.service;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.material {
public class TextField : StatefulWidget {
public TextField(Key key = null, TextEditingController controller = null, FocusNode focusNode = null,
InputDecoration decoration = null, bool noDecoration = false, TextInputType keyboardType = null,
TextInputAction? textInputAction = null,
TextCapitalization textCapitalization = TextCapitalization.none, TextStyle style = null,
TextAlign textAlign = TextAlign.left, TextDirection textDirection = TextDirection.ltr,
bool autofocus = false, bool obscureText = false, bool autocorrect = false, int? maxLines = 1,
int? maxLength = null, bool maxLengthEnforced = true, ValueChanged<string> onChanged = null,
VoidCallback onEditingComplete = null,
ValueChanged<string> onSubmitted = null, List<TextInputFormatter> inputFormatters = null,
bool? enabled = null, float? cursorWidth = 2.0f, Radius cursorRadius = null, Color cursorColor = null,
Brightness? keyboardAppearance = null, EdgeInsets scrollPadding = null,
bool enableInteractiveSelection = true,
GestureTapCallback onTap = null
) : base(key: key) {
D.assert(maxLines == null || maxLines > 0);
D.assert(maxLength == null || maxLength > 0);
this.controller = controller;
this.focusNode = focusNode;
this.decoration = noDecoration ? null : (decoration ?? new InputDecoration());
this.textInputAction = textInputAction;
this.textCapitalization = textCapitalization;
this.style = style;
this.textAlign = textAlign;
this.textDirection = textDirection;
this.autofocus = autofocus;
this.obscureText = obscureText;
this.autocorrect = autocorrect;
this.maxLines = maxLines;
this.maxLength = maxLength;
this.maxLengthEnforced = maxLengthEnforced;
this.onChanged = onChanged;
this.onEditingComplete = onEditingComplete;
this.onSubmitted = onSubmitted;
this.inputFormatters = inputFormatters;
this.enabled = enabled;
this.cursorWidth = cursorWidth;
this.cursorColor = cursorColor;
this.cursorRadius = cursorRadius;
this.onSubmitted = onSubmitted;
this.keyboardAppearance = keyboardAppearance;
this.enableInteractiveSelection = enableInteractiveSelection;
this.onTap = onTap;
this.keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline);
this.scrollPadding = scrollPadding ?? EdgeInsets.all(20.0f);
}
public readonly TextEditingController controller;
public readonly FocusNode focusNode;
public readonly InputDecoration decoration;
public readonly TextInputType keyboardType;
public readonly TextInputAction? textInputAction;
public readonly TextCapitalization textCapitalization;
public readonly TextStyle style;
public readonly TextAlign textAlign;
public readonly TextDirection textDirection;
public readonly bool autofocus;
public readonly bool obscureText;
public readonly bool autocorrect;
public readonly int? maxLines;
public const long noMaxLength = 9007199254740992; // math.pow(2, 53);
public readonly int? maxLength;
public readonly bool maxLengthEnforced;
public readonly ValueChanged<string> onChanged;
public readonly VoidCallback onEditingComplete;
public readonly ValueChanged<String> onSubmitted;
public readonly List<TextInputFormatter> inputFormatters;
public readonly bool? enabled;
public readonly float? cursorWidth;
public readonly Radius cursorRadius;
public readonly Color cursorColor;
public readonly Brightness? keyboardAppearance;
public readonly EdgeInsets scrollPadding;
public readonly bool enableInteractiveSelection;
public readonly GestureTapCallback onTap;
public override State createState() {
return new _TextFieldState();
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(
new DiagnosticsProperty<TextEditingController>("controller", this.controller, defaultValue: null));
properties.add(new DiagnosticsProperty<FocusNode>("focusNode", this.focusNode, defaultValue: null));
properties.add(new DiagnosticsProperty<bool?>("enabled", this.enabled, defaultValue: null));
properties.add(new DiagnosticsProperty<InputDecoration>("decoration", this.decoration));
properties.add(new DiagnosticsProperty<TextInputType>("keyboardType", this.keyboardType,
defaultValue: TextInputType.text));
properties.add(new DiagnosticsProperty<TextStyle>("style", this.style, defaultValue: null));
properties.add(new DiagnosticsProperty<bool>("autofocus", this.autofocus, defaultValue: false));
properties.add(new DiagnosticsProperty<bool>("obscureText", this.obscureText, defaultValue: false));
properties.add(new DiagnosticsProperty<bool>("autocorrect", this.autocorrect, defaultValue: false));
properties.add(new IntProperty("maxLines", this.maxLines, defaultValue: 1));
properties.add(new IntProperty("maxLength", this.maxLength, defaultValue: null));
properties.add(new FlagProperty("maxLengthEnforced", value: this.maxLengthEnforced,
ifTrue: "max length enforced"));
properties.add(new DiagnosticsProperty<GestureTapCallback>("onTap", this.onTap, defaultValue: null));
}
}
class _TextFieldState : AutomaticKeepAliveClientMixin<TextField> {
readonly GlobalKey<EditableTextState> _editableTextKey = new LabeledGlobalKey<EditableTextState>();
HashSet<InteractiveInkFeature> _splashes;
InteractiveInkFeature _currentSplash;
TextEditingController _controller;
TextEditingController _effectiveController {
get { return this.widget.controller ?? this._controller; }
}
FocusNode _focusNode;
FocusNode _effectiveFocusNode {
get {
if (this.widget.focusNode != null) {
return this.widget.focusNode;
}
if (this._focusNode != null) {
return this._focusNode;
}
this._focusNode = new FocusNode();
return this._focusNode;
}
}
bool needsCounter {
get {
return this.widget.maxLength != null
&& this.widget.decoration != null
&& this.widget.decoration.counterText == null;
}
}
InputDecoration _getEffectiveDecoration() {
MaterialLocalizations localizations = MaterialLocalizations.of(this.context);
InputDecoration effectiveDecoration = (this.widget.decoration ?? new InputDecoration())
.applyDefaults(Theme.of(this.context).inputDecorationTheme)
.copyWith(
enabled: this.widget.enabled
);
if (!this.needsCounter) {
return effectiveDecoration;
}
int currentLength = this._effectiveController.value.text.Length;
string counterText = $"{currentLength}";
if (this.widget.maxLength != TextField.noMaxLength) {
counterText += $"/{this.widget.maxLength}";
}
// Handle length exceeds maxLength
if (this._effectiveController.value.text.Length > this.widget.maxLength) {
ThemeData themeData = Theme.of(this.context);
return effectiveDecoration.copyWith(
errorText: effectiveDecoration.errorText ?? "",
counterStyle: effectiveDecoration.errorStyle
?? themeData.textTheme.caption.copyWith(color: themeData.errorColor),
counterText: counterText
);
}
return effectiveDecoration.copyWith(
counterText: counterText
);
}
public override void initState() {
base.initState();
if (this.widget.controller == null) {
this._controller = new TextEditingController();
}
}
public override void didUpdateWidget(StatefulWidget oldWidget) {
base.didUpdateWidget(oldWidget);
if (this.widget.controller == null && ((TextField) oldWidget).controller != null) {
this._controller = TextEditingController.fromValue(((TextField) oldWidget).controller.value);
}
else if (this.widget.controller != null && ((TextField) oldWidget).controller == null) {
this._controller = null;
}
bool isEnabled = this.widget.enabled ?? this.widget.decoration?.enabled ?? true;
bool wasEnabled = ((TextField) oldWidget).enabled ?? ((TextField) oldWidget).decoration?.enabled ?? true;
if (wasEnabled && !isEnabled) {
this._effectiveFocusNode.unfocus();
}
}
public override void dispose() {
this._focusNode?.dispose();
base.dispose();
}
void _requestKeyboard() {
this._editableTextKey.currentState?.requestKeyboard();
}
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) {
if (cause == SelectionChangedCause.longPress) {
// Feedback.forLongPress(context); todo add feedback
}
}
InteractiveInkFeature _createInkFeature(TapDownDetails details) {
MaterialInkController inkController = Material.of(this.context);
BuildContext editableContext = this._editableTextKey.currentContext;
RenderBox referenceBox =
(RenderBox) (InputDecorator.containerOf(editableContext) ?? editableContext.findRenderObject());
Offset position = referenceBox.globalToLocal(details.globalPosition);
Color color = Theme.of(this.context).splashColor;
InteractiveInkFeature splash = null;
void handleRemoved() {
if (this._splashes != null) {
D.assert(this._splashes.Contains(splash));
this._splashes.Remove(splash);
if (this._currentSplash == splash) this._currentSplash = null;
this.updateKeepAlive();
} // else we're probably in deactivate()
}
splash = Theme.of(this.context).splashFactory.create(
controller: inkController,
referenceBox: referenceBox,
position: position,
color: color,
containedInkWell: true,
borderRadius: BorderRadius.zero,
onRemoved: handleRemoved
);
return splash;
}
RenderEditable _renderEditable {
get {
return this._editableTextKey.currentState.renderEditable;
}
}
void _handleTapDown(TapDownDetails details) {
this._renderEditable.handleTapDown(details);
this._startSplash(details);
}
void _handleTap() {
if (this.widget.enableInteractiveSelection) {
this._renderEditable.handleTap();
}
this._requestKeyboard();
this._confirmCurrentSplash();
if (this.widget.onTap != null) {
this.widget.onTap();
}
}
void _handleTapCancel() {
this._cancelCurrentSplash();
}
void _handleLongPress() {
if (this.widget.enableInteractiveSelection) {
this._renderEditable.handleLongPress();
}
this._confirmCurrentSplash();
}
void _startSplash(TapDownDetails details) {
if (this._effectiveFocusNode.hasFocus) {
return;
}
InteractiveInkFeature splash = this._createInkFeature(details);
this._splashes = this._splashes ?? new HashSet<InteractiveInkFeature>();
this._splashes.Add(splash);
this._currentSplash = splash;
this.updateKeepAlive();
}
void _confirmCurrentSplash() {
this._currentSplash?.confirm();
this._currentSplash = null;
}
void _cancelCurrentSplash() {
this._currentSplash?.cancel();
}
protected override bool wantKeepAlive {
get { return this._splashes != null && this._splashes.isNotEmpty(); }
}
public override void deactivate() {
if (this._splashes != null) {
HashSet<InteractiveInkFeature> splashes = this._splashes;
this._splashes = null;
foreach (InteractiveInkFeature splash in splashes) {
splash.dispose();
}
this._currentSplash = null;
}
D.assert(this._currentSplash == null);
base.deactivate();
}
public override Widget build(BuildContext context) {
base.build(context); // See AutomaticKeepAliveClientMixin.
D.assert(MaterialD.debugCheckHasMaterial(context));
D.assert(WidgetsD.debugCheckHasDirectionality(context));
ThemeData themeData = Theme.of(context);
TextStyle style = this.widget.style ?? themeData.textTheme.subhead;
Brightness keyboardAppearance = this.widget.keyboardAppearance ?? themeData.primaryColorBrightness;
TextEditingController controller = this._effectiveController;
FocusNode focusNode = this._effectiveFocusNode;
List<TextInputFormatter> formatters = this.widget.inputFormatters ?? new List<TextInputFormatter>();
if (this.widget.maxLength != null && this.widget.maxLengthEnforced) {
formatters.Add(new LengthLimitingTextInputFormatter(this.widget.maxLength));
}
Widget child = new RepaintBoundary(
child: new EditableText(
key: this._editableTextKey,
controller: controller,
focusNode: focusNode,
keyboardType: this.widget.keyboardType,
textInputAction: this.widget.textInputAction,
textCapitalization: this.widget.textCapitalization,
style: style,
textAlign: this.widget.textAlign,
textDirection: this.widget.textDirection,
autofocus: this.widget.autofocus,
obscureText: this.widget.obscureText,
autocorrect: this.widget.autocorrect,
maxLines: this.widget.maxLines,
selectionColor: themeData.textSelectionColor,
selectionControls: this.widget.enableInteractiveSelection
? MaterialUtils.materialTextSelectionControls
: null,
onChanged: this.widget.onChanged,
onEditingComplete: this.widget.onEditingComplete,
onSubmitted: this.widget.onSubmitted,
onSelectionChanged: this._handleSelectionChanged,
inputFormatters: formatters,
rendererIgnoresPointer: true,
cursorWidth: this.widget.cursorWidth,
cursorRadius: this.widget.cursorRadius,
cursorColor: this.widget.cursorColor ?? Theme.of(context).cursorColor,
scrollPadding: this.widget.scrollPadding,
keyboardAppearance: keyboardAppearance,
enableInteractiveSelection: this.widget.enableInteractiveSelection
)
);
if (this.widget.decoration != null) {
child = new AnimatedBuilder(
animation: ListenableUtils.merge(new List<Listenable> {focusNode, controller}),
builder:
(_context, _child) => {
return new InputDecorator(
decoration: this._getEffectiveDecoration(),
baseStyle: this.widget.style,
textAlign: this.widget.textAlign,
isFocused: focusNode.hasFocus,
isEmpty: controller.value.text.isEmpty(),
child: _child
);
},
child: child
);
}
return new IgnorePointer(
ignoring: !(this.widget.enabled ?? this.widget.decoration?.enabled ?? true),
child: new GestureDetector(
behavior: HitTestBehavior.translucent,
onTapDown: this._handleTapDown,
onTap: this._handleTap,
onTapCancel: this._handleTapCancel,
onLongPress: this._handleLongPress,
child: child
)
);
}
}
}

11
Runtime/material/text_field.cs.meta


fileFormatVersion: 2
guid: d5a3808be9f564644bca2cd611869d5b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

66
Samples/UIWidgetSample/txt/TextFieldSample.cs


using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using DialogUtils = Unity.UIWidgets.material.DialogUtils;
namespace UIWidgetsSample {
public class TextFieldSample : UIWidgetsSamplePanel {
protected override void Awake() {
base.Awake();
FontManager.instance.addFont(Resources.Load<Font>(path: "MaterialIcons-Regular"), "Material Icons");
}
protected override Widget createWidget() {
return new MaterialApp(
title: "Text Fields",
home: new MyCustomForm()
);
}
}
class MyCustomForm : StatefulWidget {
public override State createState() {
return new _MyCustomFormState();
}
}
class _MyCustomFormState : State<MyCustomForm> {
readonly TextEditingController myController = new TextEditingController();
public override void dispose() {
this.myController.dispose();
base.dispose();
}
public override Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Retrieve Text Input")
),
body: new Padding(
padding: EdgeInsets.all(16.0f),
child: new TextField(controller: this.myController)
),
floatingActionButton: new FloatingActionButton(
// When the user presses the button, show an alert dialog with the
// text the user has typed into our text field.
onPressed: () => {
DialogUtils.showDialog(
context: context,
builder: (_context) => {
return new AlertDialog(
// Retrieve the text the user has typed in using our
// TextEditingController
content: new Text(this.myController.text)
);
});
},
tooltip: "Show me the value",
child: new Icon(Icons.search)
)
);
}
}
}

11
Samples/UIWidgetSample/txt/TextFieldSample.cs.meta


fileFormatVersion: 2
guid: 85b678a668e064f5c90ee8a9f7c13f35
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存