feat:input add onSubmitEditing

This commit is contained in:
pengfei.zhou 2021-06-11 15:17:20 +08:00 committed by osborn
parent ff641bf983
commit 5263731dd7
12 changed files with 239 additions and 49 deletions

View File

@ -23,10 +23,12 @@ import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
@ -221,6 +223,28 @@ public class InputNode extends ViewNode<EditText> implements TextWatcher, View.O
} }
} }
break; break;
case "onSubmitEditing":
if (!prop.isString()) {
return;
}
final String functionId = prop.asString().value();
view.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
case EditorInfo.IME_ACTION_UNSPECIFIED:
case EditorInfo.IME_ACTION_NEXT:
case EditorInfo.IME_ACTION_DONE:
case EditorInfo.IME_ACTION_GO:
case EditorInfo.IME_ACTION_SEARCH:
case EditorInfo.IME_ACTION_SEND:
callJSResponse(functionId, v.getText().toString());
return true;
}
return false;
}
});
break;
default: default:
super.blend(view, name, prop); super.blend(view, name, prop);
break; break;

View File

@ -6,14 +6,12 @@ import {
layoutConfig, layoutConfig,
LayoutSpec, LayoutSpec,
Input, Input,
Gravity,
log,
Color, Color,
input, input,
text, text,
InputType,
} from "doric"; } from "doric";
import { title, colors } from "./utils"; import { preferenceView } from "./components/PreferenceView";
import { title } from "./utils";
function getInput(c: Partial<Input>) { function getInput(c: Partial<Input>) {
const inputView = input(c); const inputView = input(c);
@ -37,56 +35,64 @@ function getInput(c: Partial<Input>) {
inputView.onTextChange = (text) => { inputView.onTextChange = (text) => {
inputed.text = `Inputed:${text}`; inputed.text = `Inputed:${text}`;
}; };
return [inputView, isFocused, inputed]; inputView.onSubmitEditing = (text) => {
inputed.text = `Submited: ${text}`
};
return [
inputView,
isFocused,
inputed,
preferenceView().applyChild({
title: {
text: "Multiline"
},
switch: {
state: true,
onSwitch: (ret) => {
inputView.multiline = ret
}
}
}),
preferenceView().applyChild({
title: {
text: "Editable"
},
switch: {
state: true,
onSwitch: (ret) => {
inputView.editable = ret
}
}
}),
];
} }
@Entry @Entry
class InputDemo extends Panel { class InputDemo extends Panel {
build(root: Group) { build(root: Group) {
var [inputView, ...otherView] = getInput({ let inputView: Input
layoutConfig: {
widthSpec: LayoutSpec.FIT,
heightSpec: LayoutSpec.FIT,
},
hintText: "Please input something in one line",
border: {
width: 1,
color: Color.GRAY,
},
multiline: false,
textSize: 20,
maxLength: 20,
padding: { top: 10, bottom: 11 },
inputType: InputType.Decimal,
password: true,
});
scroller( scroller(
vlayout( vlayout(
[ [
title("Demo"), title("Demo"),
// ...getInput({ ...getInput({
// layoutConfig: { layoutConfig: {
// widthSpec: LayoutSpec.JUST, widthSpec: LayoutSpec.MOST,
// heightSpec: LayoutSpec.FIT, heightSpec: LayoutSpec.FIT,
// }, },
// width: 300, hintText: "Please input something",
// hintText: "Please input something", border: {
// border: { width: 1,
// width: 1, color: Color.GRAY,
// color: Color.GRAY, },
// }, }),
// textSize: 40,
// maxLength: 20,
// }),
inputView,
...otherView,
], ],
{ {
space: 10, space: 10,
layoutConfig: layoutConfig().most().configHeight(LayoutSpec.MOST), layoutConfig: layoutConfig().most().configHeight(LayoutSpec.MOST),
onClick: () => {
(inputView as Input).releaseFocus(context);
},
} }
), ),
{ {

View File

@ -28,6 +28,8 @@
typedef void (^onFocusChangeBlock)(BOOL focused, DoricInputNode *node); typedef void (^onFocusChangeBlock)(BOOL focused, DoricInputNode *node);
typedef void (^onSubmitEditingBlock)(NSString *text, DoricInputNode *node);
@implementation DoricInputView @implementation DoricInputView
- (instancetype)init { - (instancetype)init {
@ -71,7 +73,8 @@ - (CGSize)sizeThatFits:(CGSize)size {
@interface DoricInputNode () <UITextViewDelegate> @interface DoricInputNode () <UITextViewDelegate>
@property(nonatomic, copy) onTextChangeBlock onTextChange; @property(nonatomic, copy) onTextChangeBlock onTextChange;
@property(nonatomic, copy) onFocusChangeBlock onFocusShange; @property(nonatomic, copy) onFocusChangeBlock onFocusChange;
@property(nonatomic, copy) onSubmitEditingBlock onSubmitEditing;
@property(nonatomic, strong) NSNumber *maxLength; @property(nonatomic, strong) NSNumber *maxLength;
@end @end
@ -107,6 +110,9 @@ - (void)blendView:(DoricInputView *)view forPropName:(NSString *)name propValue:
BOOL value = [(NSNumber *) prop boolValue]; BOOL value = [(NSNumber *) prop boolValue];
if (!value) { if (!value) {
view.textContainer.maximumNumberOfLines = 1; view.textContainer.maximumNumberOfLines = 1;
if (view.text.length > 0) {
view.text = [view.text stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
}
} else { } else {
view.textContainer.maximumNumberOfLines = 0; view.textContainer.maximumNumberOfLines = 0;
} }
@ -124,11 +130,11 @@ - (void)blendView:(DoricInputView *)view forPropName:(NSString *)name propValue:
} }
} else if ([name isEqualToString:@"onFocusChange"]) { } else if ([name isEqualToString:@"onFocusChange"]) {
if ([prop isKindOfClass:[NSString class]]) { if ([prop isKindOfClass:[NSString class]]) {
self.onFocusShange = ^(BOOL focused, DoricInputNode *node) { self.onFocusChange = ^(BOOL focused, DoricInputNode *node) {
[node callJSResponse:prop, @(focused), nil]; [node callJSResponse:prop, @(focused), nil];
}; };
} else { } else {
self.onFocusShange = nil; self.onFocusChange = nil;
} }
} else if ([name isEqualToString:@"maxLength"]) { } else if ([name isEqualToString:@"maxLength"]) {
@ -161,6 +167,9 @@ - (void)blendView:(DoricInputView *)view forPropName:(NSString *)name propValue:
} else if ([name isEqualToString:@"editable"]) { } else if ([name isEqualToString:@"editable"]) {
view.editable = [(NSNumber *) prop boolValue]; view.editable = [(NSNumber *) prop boolValue];
} else if ([name isEqualToString:@"returnKeyType"]) { } else if ([name isEqualToString:@"returnKeyType"]) {
if (view.textContainer.maximumNumberOfLines == 1) {
return;
}
switch ([(NSNumber *) prop integerValue]) { switch ([(NSNumber *) prop integerValue]) {
case 1: case 1:
view.returnKeyType = UIReturnKeyDone; view.returnKeyType = UIReturnKeyDone;
@ -182,6 +191,14 @@ - (void)blendView:(DoricInputView *)view forPropName:(NSString *)name propValue:
view.returnKeyType = UIReturnKeyDefault; view.returnKeyType = UIReturnKeyDefault;
break; break;
} }
} else if ([name isEqualToString:@"onSubmitEditing"]) {
if ([prop isKindOfClass:[NSString class]]) {
self.onSubmitEditing = ^(NSString *text, DoricInputNode *node) {
[node callJSResponse:prop, text, nil];
};
} else {
self.onSubmitEditing = nil;
}
} else { } else {
[super blendView:view forPropName:name propValue:prop]; [super blendView:view forPropName:name propValue:prop];
} }
@ -237,15 +254,27 @@ - (void)releaseFocus {
#pragma mark - UITextViewDelegate #pragma mark - UITextViewDelegate
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { - (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
if (self.onFocusShange) { if (self.onFocusChange) {
self.onFocusShange(YES, self); self.onFocusChange(YES, self);
} }
return YES; return YES;
} }
- (BOOL)textViewShouldEndEditing:(UITextView *)textView { - (BOOL)textViewShouldEndEditing:(UITextView *)textView {
if (self.onFocusShange) { if (self.onFocusChange) {
self.onFocusShange(NO, self); self.onFocusChange(NO, self);
}
return YES;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text isEqualToString:@"\n"]) {
if (textView.textContainer.maximumNumberOfLines == 1) {
if (self.onSubmitEditing) {
self.onSubmitEditing(textView.text, self);
}
return NO;
}
} }
return YES; return YES;
} }

View File

@ -2767,6 +2767,15 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) { var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") { return Reflect.metadata(k, v); } if (typeof Reflect === "object" && typeof Reflect.metadata === "function") { return Reflect.metadata(k, v); }
}; };
exports.ReturnKeyType = void 0;
(function (ReturnKeyType) {
ReturnKeyType[ReturnKeyType["Default"] = 0] = "Default";
ReturnKeyType[ReturnKeyType["Done"] = 1] = "Done";
ReturnKeyType[ReturnKeyType["Search"] = 2] = "Search";
ReturnKeyType[ReturnKeyType["Next"] = 3] = "Next";
ReturnKeyType[ReturnKeyType["Go"] = 4] = "Go";
ReturnKeyType[ReturnKeyType["Send"] = 5] = "Send";
})(exports.ReturnKeyType || (exports.ReturnKeyType = {}));
var Input = /** @class */ (function (_super) { var Input = /** @class */ (function (_super) {
__extends$5(Input, _super); __extends$5(Input, _super);
function Input() { function Input() {
@ -2836,6 +2845,18 @@ var Input = /** @class */ (function (_super) {
Property, Property,
__metadata$3("design:type", Boolean) __metadata$3("design:type", Boolean)
], Input.prototype, "password", void 0); ], Input.prototype, "password", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Boolean)
], Input.prototype, "editable", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Number)
], Input.prototype, "returnKeyType", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Function)
], Input.prototype, "onSubmitEditing", void 0);
return Input; return Input;
}(View)); }(View));
exports.InputType = void 0; exports.InputType = void 0;

View File

@ -2135,6 +2135,15 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) { var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
exports.ReturnKeyType = void 0;
(function (ReturnKeyType) {
ReturnKeyType[ReturnKeyType["Default"] = 0] = "Default";
ReturnKeyType[ReturnKeyType["Done"] = 1] = "Done";
ReturnKeyType[ReturnKeyType["Search"] = 2] = "Search";
ReturnKeyType[ReturnKeyType["Next"] = 3] = "Next";
ReturnKeyType[ReturnKeyType["Go"] = 4] = "Go";
ReturnKeyType[ReturnKeyType["Send"] = 5] = "Send";
})(exports.ReturnKeyType || (exports.ReturnKeyType = {}));
class Input extends View { class Input extends View {
getText(context) { getText(context) {
return this.nativeChannel(context, 'getText')(); return this.nativeChannel(context, 'getText')();
@ -2200,6 +2209,18 @@ __decorate$3([
Property, Property,
__metadata$3("design:type", Boolean) __metadata$3("design:type", Boolean)
], Input.prototype, "password", void 0); ], Input.prototype, "password", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Boolean)
], Input.prototype, "editable", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Number)
], Input.prototype, "returnKeyType", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Function)
], Input.prototype, "onSubmitEditing", void 0);
exports.InputType = void 0; exports.InputType = void 0;
(function (InputType) { (function (InputType) {
InputType[InputType["Default"] = 0] = "Default"; InputType[InputType["Default"] = 0] = "Default";

View File

@ -3656,6 +3656,15 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) { var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
exports.ReturnKeyType = void 0;
(function (ReturnKeyType) {
ReturnKeyType[ReturnKeyType["Default"] = 0] = "Default";
ReturnKeyType[ReturnKeyType["Done"] = 1] = "Done";
ReturnKeyType[ReturnKeyType["Search"] = 2] = "Search";
ReturnKeyType[ReturnKeyType["Next"] = 3] = "Next";
ReturnKeyType[ReturnKeyType["Go"] = 4] = "Go";
ReturnKeyType[ReturnKeyType["Send"] = 5] = "Send";
})(exports.ReturnKeyType || (exports.ReturnKeyType = {}));
class Input extends View { class Input extends View {
getText(context) { getText(context) {
return this.nativeChannel(context, 'getText')(); return this.nativeChannel(context, 'getText')();
@ -3721,6 +3730,18 @@ __decorate$3([
Property, Property,
__metadata$3("design:type", Boolean) __metadata$3("design:type", Boolean)
], Input.prototype, "password", void 0); ], Input.prototype, "password", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Boolean)
], Input.prototype, "editable", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Number)
], Input.prototype, "returnKeyType", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Function)
], Input.prototype, "onSubmitEditing", void 0);
exports.InputType = void 0; exports.InputType = void 0;
(function (InputType) { (function (InputType) {
InputType[InputType["Default"] = 0] = "Default"; InputType[InputType["Default"] = 0] = "Default";

11
doric-js/index.d.ts vendored
View File

@ -760,6 +760,14 @@ declare module 'doric/lib/src/widget/input' {
import { Color } from "doric/lib/src/util/color"; import { Color } from "doric/lib/src/util/color";
import { Gravity } from "doric/lib/src/util/gravity"; import { Gravity } from "doric/lib/src/util/gravity";
import { BridgeContext } from "doric/lib/src/runtime/global"; import { BridgeContext } from "doric/lib/src/runtime/global";
export enum ReturnKeyType {
Default = 0,
Done = 1,
Search = 2,
Next = 3,
Go = 4,
Send = 5
}
export class Input extends View { export class Input extends View {
text?: string; text?: string;
textColor?: Color; textColor?: Color;
@ -773,6 +781,9 @@ declare module 'doric/lib/src/widget/input' {
onFocusChange?: (focused: boolean) => void; onFocusChange?: (focused: boolean) => void;
maxLength?: number; maxLength?: number;
password?: boolean; password?: boolean;
editable?: boolean;
returnKeyType?: ReturnKeyType;
onSubmitEditing?: (text: string) => void;
getText(context: BridgeContext): Promise<string>; getText(context: BridgeContext): Promise<string>;
setSelection(context: BridgeContext, start: number, end?: number): Promise<string>; setSelection(context: BridgeContext, start: number, end?: number): Promise<string>;
requestFocus(context: BridgeContext): Promise<any>; requestFocus(context: BridgeContext): Promise<any>;

View File

@ -2,6 +2,14 @@ import { View } from "../ui/view";
import { Color } from "../util/color"; import { Color } from "../util/color";
import { Gravity } from "../util/gravity"; import { Gravity } from "../util/gravity";
import { BridgeContext } from "../runtime/global"; import { BridgeContext } from "../runtime/global";
export declare enum ReturnKeyType {
Default = 0,
Done = 1,
Search = 2,
Next = 3,
Go = 4,
Send = 5
}
export declare class Input extends View { export declare class Input extends View {
text?: string; text?: string;
textColor?: Color; textColor?: Color;
@ -15,6 +23,9 @@ export declare class Input extends View {
onFocusChange?: (focused: boolean) => void; onFocusChange?: (focused: boolean) => void;
maxLength?: number; maxLength?: number;
password?: boolean; password?: boolean;
editable?: boolean;
returnKeyType?: ReturnKeyType;
onSubmitEditing?: (text: string) => void;
getText(context: BridgeContext): Promise<string>; getText(context: BridgeContext): Promise<string>;
setSelection(context: BridgeContext, start: number, end?: number): Promise<string>; setSelection(context: BridgeContext, start: number, end?: number): Promise<string>;
requestFocus(context: BridgeContext): Promise<any>; requestFocus(context: BridgeContext): Promise<any>;

View File

@ -26,6 +26,15 @@ import { View, Property, InconsistProperty } from "../ui/view";
import { Color } from "../util/color"; import { Color } from "../util/color";
import { Gravity } from "../util/gravity"; import { Gravity } from "../util/gravity";
import { layoutConfig } from "../util/index.util"; import { layoutConfig } from "../util/index.util";
export var ReturnKeyType;
(function (ReturnKeyType) {
ReturnKeyType[ReturnKeyType["Default"] = 0] = "Default";
ReturnKeyType[ReturnKeyType["Done"] = 1] = "Done";
ReturnKeyType[ReturnKeyType["Search"] = 2] = "Search";
ReturnKeyType[ReturnKeyType["Next"] = 3] = "Next";
ReturnKeyType[ReturnKeyType["Go"] = 4] = "Go";
ReturnKeyType[ReturnKeyType["Send"] = 5] = "Send";
})(ReturnKeyType || (ReturnKeyType = {}));
export class Input extends View { export class Input extends View {
getText(context) { getText(context) {
return this.nativeChannel(context, 'getText')(); return this.nativeChannel(context, 'getText')();
@ -91,6 +100,18 @@ __decorate([
Property, Property,
__metadata("design:type", Boolean) __metadata("design:type", Boolean)
], Input.prototype, "password", void 0); ], Input.prototype, "password", void 0);
__decorate([
Property,
__metadata("design:type", Boolean)
], Input.prototype, "editable", void 0);
__decorate([
Property,
__metadata("design:type", Number)
], Input.prototype, "returnKeyType", void 0);
__decorate([
Property,
__metadata("design:type", Function)
], Input.prototype, "onSubmitEditing", void 0);
export var InputType; export var InputType;
(function (InputType) { (function (InputType) {
InputType[InputType["Default"] = 0] = "Default"; InputType[InputType["Default"] = 0] = "Default";

View File

@ -72,6 +72,10 @@ export class Input extends View {
@Property @Property
returnKeyType?: ReturnKeyType returnKeyType?: ReturnKeyType
@Property
onSubmitEditing?: (text: string) => void
getText(context: BridgeContext) { getText(context: BridgeContext) {
return this.nativeChannel(context, 'getText')() as Promise<string> return this.nativeChannel(context, 'getText')() as Promise<string>
} }

View File

@ -3710,6 +3710,15 @@ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators,
var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) { var __metadata$3 = (undefined && undefined.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
exports.ReturnKeyType = void 0;
(function (ReturnKeyType) {
ReturnKeyType[ReturnKeyType["Default"] = 0] = "Default";
ReturnKeyType[ReturnKeyType["Done"] = 1] = "Done";
ReturnKeyType[ReturnKeyType["Search"] = 2] = "Search";
ReturnKeyType[ReturnKeyType["Next"] = 3] = "Next";
ReturnKeyType[ReturnKeyType["Go"] = 4] = "Go";
ReturnKeyType[ReturnKeyType["Send"] = 5] = "Send";
})(exports.ReturnKeyType || (exports.ReturnKeyType = {}));
class Input extends View { class Input extends View {
getText(context) { getText(context) {
return this.nativeChannel(context, 'getText')(); return this.nativeChannel(context, 'getText')();
@ -3775,6 +3784,18 @@ __decorate$3([
Property, Property,
__metadata$3("design:type", Boolean) __metadata$3("design:type", Boolean)
], Input.prototype, "password", void 0); ], Input.prototype, "password", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Boolean)
], Input.prototype, "editable", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Number)
], Input.prototype, "returnKeyType", void 0);
__decorate$3([
Property,
__metadata$3("design:type", Function)
], Input.prototype, "onSubmitEditing", void 0);
exports.InputType = void 0; exports.InputType = void 0;
(function (InputType) { (function (InputType) {
InputType[InputType["Default"] = 0] = "Default"; InputType[InputType["Default"] = 0] = "Default";

File diff suppressed because one or more lines are too long