mirror of
https://github.com/Tencent/Hippy.git
synced 2026-10-22 00:45:15 +08:00
774 lines
25 KiB
Dart
774 lines
25 KiB
Dart
//
|
|
// Tencent is pleased to support the open source community by making
|
|
// Hippy available.
|
|
//
|
|
// Copyright (C) 2022 THL A29 Limited, a Tencent company.
|
|
// All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../common.dart';
|
|
import '../controller.dart';
|
|
import '../render.dart';
|
|
import '../style.dart';
|
|
import '../util.dart';
|
|
import '../viewmodel.dart';
|
|
import '../widget.dart';
|
|
|
|
class TextInputController extends BaseViewController<TextInputRenderViewModel> {
|
|
static const String kClassName = "TextInput";
|
|
static const String kTag = "TextInputController";
|
|
|
|
static const String kEventOnFocus = "focus";
|
|
static const String kEventOnBlur = "blur";
|
|
static const String kEventOnChangeText = "changetext";
|
|
static const String kEventOnKeyboardWillShow = "keyboardwillshow";
|
|
static const String kEventOnKeyboardWillHide = "keyboardwillhide";
|
|
static const String kEventOnEndEditing = "endediting";
|
|
static const String kEventOnSelectionChange = "selectionchange";
|
|
|
|
/// func
|
|
static const String kFuncClear = "clear";
|
|
static const String kFuncFocus = "focusTextInput";
|
|
static const String kFuncBlur = "blurTextInput";
|
|
static const String kFuncGetValue = "getValue";
|
|
static const String kFuncSetValue = "setValue";
|
|
|
|
// 注意这里由于js侧使用了错误拼写,这里暂时不能修改成正确的拼写,否则会导致无法成功调用
|
|
static const String kFuncDismiss = "dissmiss";
|
|
|
|
@override
|
|
TextInputRenderViewModel createRenderViewModel(RenderNode node, RenderContext context) {
|
|
return TextInputRenderViewModel(node.id, node.rootId, name, context);
|
|
}
|
|
|
|
@override
|
|
Widget createWidget(BuildContext context, TextInputRenderViewModel viewModel) {
|
|
return TextInputWidget(viewModel);
|
|
}
|
|
|
|
@override
|
|
Map<String, ControllerMethodProp> get extendRegisteredMethodProp => {
|
|
/// props
|
|
NodeProps.kFontSize: ControllerMethodProp(setFontSize, NodeProps.kDefaultFontSizeSp),
|
|
NodeProps.kDefaultValue: ControllerMethodProp(setDefaultValue, ""),
|
|
NodeProps.kValidator: ControllerMethodProp(setValidator, ""),
|
|
NodeProps.kEditable: ControllerMethodProp(setEditable, true),
|
|
NodeProps.kCaretColorReact: ControllerMethodProp(setCaretColor, Colors.transparent.value),
|
|
NodeProps.kCaretColorVue:
|
|
ControllerMethodProp(setCaretColorAlias, Colors.transparent.value),
|
|
NodeProps.kMultiline: ControllerMethodProp(multiLine, true),
|
|
NodeProps.kReturnKeyType: ControllerMethodProp(setReturnKeyType, ""),
|
|
NodeProps.kKeyboardType: ControllerMethodProp(setKeyboardType, ""),
|
|
NodeProps.kFontStyle: ControllerMethodProp(setFontStyle, "normal"),
|
|
NodeProps.kFontFamily: ControllerMethodProp(setFontFamily, "normal"),
|
|
NodeProps.kFontWeight: ControllerMethodProp(setFontWeight, "normal"),
|
|
NodeProps.kLineHeight: ControllerMethodProp(setLineHeight, 0.0),
|
|
NodeProps.kMaxLengthProp: ControllerMethodProp(maxLength, -1),
|
|
NodeProps.kOnSelectionChange: ControllerMethodProp(setOnSelectionChange, false),
|
|
NodeProps.kLetterSpacing: ControllerMethodProp(letterSpacing, -1.0),
|
|
NodeProps.kValueProp: ControllerMethodProp(value, ""),
|
|
NodeProps.kPlaceholder: ControllerMethodProp(placeHolder, ""),
|
|
NodeProps.kPlaceholderTextColorVue: ControllerMethodProp(setTextHitColorVue, 0xFF888888),
|
|
NodeProps.kPlaceholderTextColorReact:
|
|
ControllerMethodProp(setTextHitColorReact, 0xFF888888),
|
|
NodeProps.kNumberOfLines: ControllerMethodProp(setMaxLines, kMaxLineCount),
|
|
NodeProps.kUnderlineColor:
|
|
ControllerMethodProp(setUnderlineColor, Colors.transparent.value),
|
|
NodeProps.kColor: ControllerMethodProp(setColor, Colors.transparent.value),
|
|
NodeProps.kTextAlign: ControllerMethodProp(setTextAlign, "auto"),
|
|
NodeProps.kTextAlignVertical: ControllerMethodProp(setTextAlignVertical, "auto"),
|
|
NodeProps.kPaddingTop: ControllerMethodProp(setPaddingTop, 0.0),
|
|
NodeProps.kPaddingRight: ControllerMethodProp(setPaddingRight, 0.0),
|
|
NodeProps.kPaddingBottom: ControllerMethodProp(setPaddingBottom, 0.0),
|
|
NodeProps.kPaddingLeft: ControllerMethodProp(setPaddingLeft, 0.0),
|
|
// listen
|
|
NodeProps.kOnChangeText: ControllerMethodProp(setOnChangeText, true),
|
|
NodeProps.kOnEndEditing: ControllerMethodProp(setOnEndEditing, true),
|
|
NodeProps.kOnFocus: ControllerMethodProp(setOnFocus, true),
|
|
NodeProps.kOnBlur: ControllerMethodProp(setOnBlur, true),
|
|
NodeProps.kOnContentSizeChange: ControllerMethodProp(setOnContentSizeChange, true),
|
|
NodeProps.kOnKeyboardWillShow: ControllerMethodProp(setOnKeyboardWillShow, true),
|
|
NodeProps.kOnKeyboardWillHide: ControllerMethodProp(setOnKeyboardWillHide, true),
|
|
};
|
|
|
|
@override
|
|
String get name => kClassName;
|
|
|
|
@ControllerProps(NodeProps.kFontSize)
|
|
void setFontSize(TextInputRenderViewModel renderViewModel, double fontSize) {
|
|
renderViewModel.fontSize = fontSize;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kDefaultValue)
|
|
void setDefaultValue(TextInputRenderViewModel renderViewModel, String defaultValue) {
|
|
renderViewModel.setValue(defaultValue);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kValidator)
|
|
void setValidator(TextInputRenderViewModel renderViewModel, String strValidator) {
|
|
renderViewModel.dispatcher.validator = strValidator;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kEditable)
|
|
void setEditable(TextInputRenderViewModel renderViewModel, bool editable) {
|
|
renderViewModel.editable = editable;
|
|
}
|
|
|
|
// 设置输入光标颜色 RN 语法 caret-color
|
|
@ControllerProps(NodeProps.kCaretColorReact)
|
|
void setCaretColor(TextInputRenderViewModel renderViewModel, int cursorColor) {
|
|
renderViewModel.cursorColor = cursorColor;
|
|
}
|
|
|
|
// 设置输入光标颜色
|
|
//For Vue.vue的前端语法,会把caret-color转化成caretColor
|
|
@ControllerProps(NodeProps.kCaretColorVue)
|
|
void setCaretColorAlias(TextInputRenderViewModel renderViewModel, int cursorColor) {
|
|
renderViewModel.cursorColor = cursorColor;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kMultiline)
|
|
void multiLine(TextInputRenderViewModel renderViewModel, bool multiline) {
|
|
renderViewModel.setMultiLine(multiline);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kReturnKeyType)
|
|
void setReturnKeyType(TextInputRenderViewModel renderViewModel, String returnKeyType) {
|
|
renderViewModel.setTextInputType(returnKeyType);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kKeyboardType)
|
|
void setKeyboardType(TextInputRenderViewModel renderViewModel, String keyboardType) {
|
|
renderViewModel.setKeyboardType(keyboardType);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kFontStyle)
|
|
void setFontStyle(TextInputRenderViewModel renderViewModel, String fontStyleString) {
|
|
renderViewModel.setFontStyle(fontStyleString);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kFontWeight)
|
|
void setFontWeight(TextInputRenderViewModel renderViewModel, String fontWeightString) {
|
|
renderViewModel.setFontWeight(fontWeightString);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kLineHeight)
|
|
void setLineHeight(TextInputRenderViewModel renderViewModel, double lineHeight) {
|
|
renderViewModel.lineHeight = lineHeight;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kFontFamily)
|
|
void setFontFamily(TextInputRenderViewModel renderViewModel, String fontFamily) {
|
|
renderViewModel.fontFamily = fontFamily;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kMaxLengthProp)
|
|
void maxLength(TextInputRenderViewModel renderViewModel, int maxLength) {
|
|
renderViewModel.maxLength = maxLength;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnSelectionChange)
|
|
void setOnSelectionChange(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.selectionChangeEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kLetterSpacing)
|
|
void letterSpacing(TextInputRenderViewModel renderViewModel, double letterSpacing) {
|
|
renderViewModel.letterSpacing = letterSpacing;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kValueProp)
|
|
void value(TextInputRenderViewModel renderViewModel, String value) {
|
|
renderViewModel.setValue(value);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPlaceholder)
|
|
void placeHolder(TextInputRenderViewModel renderViewModel, String placeholder) {
|
|
renderViewModel.hint = placeholder;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPlaceholderTextColorVue)
|
|
void setTextHitColorVue(TextInputRenderViewModel renderViewModel, int color) {
|
|
renderViewModel.hintTextColor = color;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPlaceholderTextColorReact)
|
|
void setTextHitColorReact(TextInputRenderViewModel renderViewModel, int color) {
|
|
renderViewModel.hintTextColor = color;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kNumberOfLines)
|
|
void setMaxLines(TextInputRenderViewModel renderViewModel, int numberOfLine) {
|
|
renderViewModel.numberOfLine = numberOfLine;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kUnderlineColor)
|
|
void setUnderlineColor(TextInputRenderViewModel renderViewModel, int underlineColor) {
|
|
renderViewModel.underLineColor = underlineColor;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnFocus)
|
|
void setOnFocus(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.focusEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnBlur)
|
|
void setOnBlur(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.blurEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnChangeText)
|
|
void setOnChangeText(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.changeTextEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnContentSizeChange)
|
|
void setOnContentSizeChange(TextInputRenderViewModel renderViewModel, bool contentSizeChange) {
|
|
renderViewModel.dispatcher.contentSizeChangeEventEnable = contentSizeChange;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnKeyboardWillShow)
|
|
void setOnKeyboardWillShow(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.keyboardWillShowEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnKeyboardWillShow)
|
|
void setOnKeyboardWillHide(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.keyboardWillHideEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kOnEndEditing)
|
|
void setOnEndEditing(TextInputRenderViewModel renderViewModel, bool change) {
|
|
renderViewModel.dispatcher.endEditingEventEnable = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kColor)
|
|
void setColor(TextInputRenderViewModel renderViewModel, int change) {
|
|
renderViewModel.textColor = change;
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kTextAlign)
|
|
void setTextAlign(TextInputRenderViewModel renderViewModel, String textAlign) {
|
|
renderViewModel.setTextAlign(textAlign);
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kTextAlignVertical)
|
|
void setTextAlignVertical(TextInputRenderViewModel renderViewModel, String? textAlignVertical) {
|
|
if (textAlignVertical == null || "auto" == textAlignVertical) {
|
|
renderViewModel.textAlignVertical = null;
|
|
} else if ("top" == textAlignVertical) {
|
|
renderViewModel.textAlignVertical = TextAlignVertical.top;
|
|
} else if ("bottom" == textAlignVertical) {
|
|
renderViewModel.textAlignVertical = TextAlignVertical.bottom;
|
|
} else if ("center" == textAlignVertical) {
|
|
renderViewModel.textAlignVertical = TextAlignVertical.center;
|
|
}
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPaddingTop)
|
|
void setPaddingTop(TextInputRenderViewModel renderViewModel, Object? paddingTop) {
|
|
if (paddingTop is int) {
|
|
renderViewModel.paddingTop = paddingTop.toDouble();
|
|
} else if (paddingTop is double) {
|
|
renderViewModel.paddingTop = paddingTop;
|
|
} else {
|
|
renderViewModel.paddingTop = 0.0;
|
|
}
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPaddingRight)
|
|
void setPaddingRight(TextInputRenderViewModel renderViewModel, Object? paddingRight) {
|
|
if (paddingRight is int) {
|
|
renderViewModel.paddingRight = paddingRight.toDouble();
|
|
} else if (paddingRight is double) {
|
|
renderViewModel.paddingRight = paddingRight;
|
|
} else {
|
|
renderViewModel.paddingRight = 0.0;
|
|
}
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPaddingBottom)
|
|
void setPaddingBottom(TextInputRenderViewModel renderViewModel, Object? paddingBottom) {
|
|
if (paddingBottom is int) {
|
|
renderViewModel.paddingBottom = paddingBottom.toDouble();
|
|
} else if (paddingBottom is double) {
|
|
renderViewModel.paddingBottom = paddingBottom;
|
|
} else {
|
|
renderViewModel.paddingBottom = 0.0;
|
|
}
|
|
}
|
|
|
|
@ControllerProps(NodeProps.kPaddingLeft)
|
|
void setPaddingLeft(TextInputRenderViewModel renderViewModel, Object? paddingLeft) {
|
|
if (paddingLeft is int) {
|
|
renderViewModel.paddingLeft = paddingLeft.toDouble();
|
|
} else if (paddingLeft is double) {
|
|
renderViewModel.paddingLeft = paddingLeft;
|
|
} else {
|
|
renderViewModel.paddingLeft = 0.0;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void updateEvents(
|
|
TextInputRenderViewModel renderViewModel,
|
|
Set<EventHolder> holders,
|
|
) {
|
|
super.updateEvents(renderViewModel, holders);
|
|
if (holders.isNotEmpty) {
|
|
for (var holder in holders) {
|
|
switch (holder.eventName) {
|
|
case kEventOnFocus:
|
|
setOnFocus(renderViewModel, holder.isAdd);
|
|
break;
|
|
case kEventOnBlur:
|
|
setOnBlur(renderViewModel, holder.isAdd);
|
|
break;
|
|
case kEventOnChangeText:
|
|
setOnChangeText(renderViewModel, holder.isAdd);
|
|
break;
|
|
case kEventOnKeyboardWillShow:
|
|
setOnKeyboardWillShow(renderViewModel, holder.isAdd);
|
|
break;
|
|
case kEventOnKeyboardWillHide:
|
|
setOnKeyboardWillHide(renderViewModel, holder.isAdd);
|
|
break;
|
|
case kEventOnEndEditing:
|
|
setOnEndEditing(renderViewModel, holder.isAdd);
|
|
break;
|
|
case kEventOnSelectionChange:
|
|
setOnSelectionChange(renderViewModel, holder.isAdd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispatchFunction(TextInputRenderViewModel viewModel, String functionName, VoltronArray array,
|
|
{Promise? promise}) {
|
|
switch (functionName) {
|
|
case kFuncSetValue:
|
|
var value = array.getString(0);
|
|
if (value != null) {
|
|
int? pos = array.get<int>(1) ?? value.length;
|
|
LogUtils.i("text_input", "js set value: $value, $pos");
|
|
viewModel.dispatcher.jsSetValue(array.getString(0), pos);
|
|
}
|
|
break;
|
|
case kFuncClear:
|
|
viewModel.dispatcher.jsSetValue("", 0);
|
|
break;
|
|
case kFuncFocus:
|
|
viewModel.focus();
|
|
break;
|
|
case kFuncDismiss:
|
|
viewModel.dismiss();
|
|
break;
|
|
case kFuncBlur:
|
|
viewModel.blur();
|
|
break;
|
|
case kFuncGetValue:
|
|
if (promise != null) {
|
|
var resultMap = viewModel.dispatcher.jsGetValue();
|
|
promise.resolve(resultMap);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
class FocusNodeProxy {
|
|
FocusNode? node;
|
|
bool _cacheIsFocus = false;
|
|
VoidCallback? _focusChangeListener;
|
|
|
|
FocusNode get realNode {
|
|
return node ??= FocusNode();
|
|
}
|
|
|
|
void init() {
|
|
node = FocusNode();
|
|
_ensureListener();
|
|
_ensureFocus();
|
|
}
|
|
|
|
void addListener(VoidCallback callback) {
|
|
_focusChangeListener = callback;
|
|
_ensureListener();
|
|
}
|
|
|
|
void _ensureListener() {
|
|
var curListener = _focusChangeListener;
|
|
if (curListener != null) {
|
|
node?.addListener(curListener);
|
|
}
|
|
}
|
|
|
|
void _ensureFocus() {
|
|
if (_cacheIsFocus) {
|
|
focus();
|
|
}
|
|
}
|
|
|
|
void dispose() {
|
|
node = null;
|
|
}
|
|
|
|
void unfocus() {
|
|
_cacheIsFocus = false;
|
|
node?.unfocus();
|
|
}
|
|
|
|
bool get hasFocus => node?.hasFocus ?? _cacheIsFocus;
|
|
|
|
void focus() {
|
|
_cacheIsFocus = true;
|
|
node?.requestFocus();
|
|
}
|
|
}
|
|
|
|
class TextEditingControllerProxy {
|
|
TextEditingController? controller;
|
|
TextEditingValue? _cacheTextEditingValue;
|
|
VoidCallback? _textEditListener;
|
|
|
|
void init() {
|
|
controller = _newController;
|
|
_ensureListener();
|
|
}
|
|
|
|
void addListener(VoidCallback? callback) {
|
|
_textEditListener = callback;
|
|
_ensureListener();
|
|
}
|
|
|
|
void _ensureListener() {
|
|
var curListener = _textEditListener;
|
|
if (curListener != null) {
|
|
controller?.addListener(curListener);
|
|
}
|
|
}
|
|
|
|
TextEditingController get _newController => _cacheTextEditingValue != null
|
|
? TextEditingController.fromValue(_cacheTextEditingValue)
|
|
: TextEditingController.fromValue(
|
|
TextEditingValue(
|
|
text: "",
|
|
selection: TextSelection.fromPosition(
|
|
const TextPosition(offset: 0, affinity: TextAffinity.downstream),
|
|
),
|
|
),
|
|
);
|
|
|
|
TextEditingController get realController {
|
|
return controller ??= _newController;
|
|
}
|
|
|
|
set value(TextEditingValue value) {
|
|
_cacheTextEditingValue = value;
|
|
_ensureTextEditing();
|
|
}
|
|
|
|
TextEditingValue get value {
|
|
return _cacheTextEditingValue ??= TextEditingValue(
|
|
text: '',
|
|
selection: TextSelection.fromPosition(
|
|
const TextPosition(offset: 0, affinity: TextAffinity.downstream),
|
|
),
|
|
);
|
|
}
|
|
|
|
TextSelection get selection =>
|
|
controller?.selection ??
|
|
(_cacheTextEditingValue?.selection ??
|
|
TextSelection.fromPosition(
|
|
const TextPosition(offset: 0, affinity: TextAffinity.downstream),
|
|
));
|
|
|
|
String get text {
|
|
var v = controller?.value;
|
|
// 这里要考虑iOS原生中文输入法中存在候选词的情况,候选词不算做输入文本
|
|
if (v != null) {
|
|
if (v.isComposingRangeValid) {
|
|
return '${v.composing.textBefore(v.text)}${v.composing.textAfter(v.text)}';
|
|
} else {
|
|
return v.text;
|
|
}
|
|
}
|
|
return _cacheTextEditingValue?.text ?? '';
|
|
}
|
|
|
|
set text(String? text) {
|
|
value = value.copyWith(
|
|
text: text,
|
|
selection: const TextSelection.collapsed(offset: -1),
|
|
composing: TextRange.empty,
|
|
);
|
|
}
|
|
|
|
void _ensureTextEditing() {
|
|
var curVal = _cacheTextEditingValue;
|
|
if (curVal != null) {
|
|
controller?.value = curVal;
|
|
}
|
|
if (controller == null) {
|
|
_textEditListener?.call();
|
|
}
|
|
}
|
|
|
|
void dispose() {
|
|
controller = null;
|
|
}
|
|
|
|
void destroy() {
|
|
_cacheTextEditingValue = null;
|
|
}
|
|
}
|
|
|
|
class TextInputDispatcher {
|
|
TextEditingControllerProxy controller;
|
|
|
|
// 过滤输入文本的正则表达式
|
|
String validator = "";
|
|
|
|
// 事件相关
|
|
bool focusEventEnable = false;
|
|
bool blurEventEnable = false;
|
|
bool selectionChangeEventEnable = false;
|
|
bool changeTextEventEnable = false;
|
|
bool endEditingEventEnable = false;
|
|
bool contentSizeChangeEventEnable = false;
|
|
bool keyboardWillShowEventEnable = false;
|
|
bool keyboardWillHideEventEnable = false;
|
|
|
|
RenderContext context;
|
|
int rootId;
|
|
int id;
|
|
|
|
String _oldText = "";
|
|
bool _hasTextInput = false;
|
|
|
|
String _jsSetValue = "";
|
|
String _regexValidRepeat = "";
|
|
|
|
bool hasFocus = false;
|
|
|
|
TextInputDispatcher(this.context, this.rootId, this.id, this.controller);
|
|
|
|
void onSelectionChanged(int selStart, int selEnd) {
|
|
if (selectionChangeEventEnable) {
|
|
var selection = VoltronMap();
|
|
selection.push("start", selStart);
|
|
selection.push("end", selEnd);
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("selection", selection);
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnSelectionChange,
|
|
paramsMap,
|
|
);
|
|
}
|
|
}
|
|
|
|
void onFocusChange(bool focus) {
|
|
if (hasFocus != focus) {
|
|
hasFocus = focus;
|
|
if (focusEventEnable || blurEventEnable) {
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("text", text);
|
|
if (hasFocus) {
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnFocus,
|
|
paramsMap,
|
|
);
|
|
} else {
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnBlur,
|
|
paramsMap,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void onEndEdit() {
|
|
if (endEditingEventEnable) {
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("text", text);
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnEndEditing,
|
|
paramsMap,
|
|
);
|
|
}
|
|
}
|
|
|
|
void onChangeText(String changeText) {
|
|
var isJsSetValue = _isJsSetValue(changeText);
|
|
if (validator.isEmpty) {
|
|
//如果没有正则匹配
|
|
//如果文本输入过,判断是否两次相同
|
|
if (_hasTextInput && _oldText == changeText) {
|
|
return;
|
|
}
|
|
_oldText = changeText;
|
|
_jsSetValue = "";
|
|
_hasTextInput = true;
|
|
if (!isJsSetValue) {
|
|
//如果是前端设置下来的值,不再需要回调给前端.
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("text", changeText);
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnChangeText,
|
|
paramsMap,
|
|
);
|
|
LogUtils.d(
|
|
TextInputController.kTag,
|
|
"afterTextChanged 1 通知前端文本变化=$changeText",
|
|
);
|
|
}
|
|
} else {
|
|
//如果设置了正则表达式
|
|
try {
|
|
//如果当前的内容不匹配正则表达式
|
|
if (!RegExp(validator).hasMatch(changeText) && changeText != "") {
|
|
LogUtils.d(
|
|
TextInputController.kTag,
|
|
"afterTextChanged 不符合正则表达式,需要设置回去=$changeText",
|
|
);
|
|
//丢弃当前的内容,回退到上一次的值.上一次的值检查过,肯定是符合正则表达式的.
|
|
controller.value = TextEditingValue(
|
|
text: _oldText,
|
|
selection: TextSelection.collapsed(
|
|
offset: _oldText.length,
|
|
),
|
|
);
|
|
//上一步的setText,将触发新一轮的beforeTextChanged,onTextChanged,afterTextChanged
|
|
//为了避免前端收到两次内容同样的通知.记录一下正则匹配设置回去的值.
|
|
_regexValidRepeat = _oldText;
|
|
_hasTextInput = true;
|
|
} else {
|
|
//如果文本输入过,判断是否两次相同
|
|
if (_hasTextInput && changeText == _oldText) {
|
|
return;
|
|
}
|
|
_hasTextInput = true;
|
|
_oldText = changeText;
|
|
_jsSetValue = "";
|
|
if (!isJsSetValue //如果是前端设置的一定不通知
|
|
&&
|
|
(isEmpty(_regexValidRepeat) //如果没有,输入过无效的内容
|
|
||
|
|
_oldText != _regexValidRepeat)) {
|
|
//如果本次输入的内容是上一次重复的蓉蓉
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("text", changeText);
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnChangeText,
|
|
paramsMap,
|
|
);
|
|
LogUtils.d(
|
|
TextInputController.kTag,
|
|
"afterTextChanged 2 通知前端文本变化= $changeText",
|
|
);
|
|
_regexValidRepeat = "";
|
|
}
|
|
}
|
|
} catch (error) {
|
|
// 不知道外部的正则表达式,最好保护住
|
|
LogUtils.e(TextInputController.kTag, "change text error:$error");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool _isJsSetValue(String value) {
|
|
return !isEmpty(_jsSetValue) && value == _jsSetValue;
|
|
}
|
|
|
|
void jsSetValue(String? value, int pos) {
|
|
if (value == null) {
|
|
_jsSetValue = value ?? '';
|
|
controller.text = value;
|
|
} else {
|
|
_jsSetValue = value;
|
|
var offset = (pos < 0 || pos >= value.length) ? value.length : pos;
|
|
controller.value = TextEditingValue(
|
|
text: _jsSetValue,
|
|
selection: TextSelection.fromPosition(
|
|
TextPosition(
|
|
offset: offset,
|
|
affinity: TextAffinity.downstream,
|
|
),
|
|
),
|
|
);
|
|
// 这里设置时候也要通知到前端
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("text", value);
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnChangeText,
|
|
paramsMap,
|
|
);
|
|
}
|
|
}
|
|
|
|
VoltronMap jsGetValue() {
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push("text", text);
|
|
return paramsMap;
|
|
}
|
|
|
|
void onKeyboardWillShow(int height) {
|
|
if (keyboardWillShowEventEnable) {
|
|
var paramsMap = VoltronMap();
|
|
paramsMap.push<int>("keyboardHeight", height);
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnKeyboardWillShow,
|
|
paramsMap,
|
|
);
|
|
}
|
|
}
|
|
|
|
void onKeyboardWillHide() {
|
|
if (keyboardWillShowEventEnable) {
|
|
var paramsMap = VoltronMap();
|
|
context.renderBridgeManager.sendComponentEvent(
|
|
rootId,
|
|
id,
|
|
TextInputController.kEventOnKeyboardWillHide,
|
|
paramsMap,
|
|
);
|
|
}
|
|
}
|
|
|
|
String get text => controller.text;
|
|
}
|