mirror of
https://github.com/Tencent/Hippy.git
synced 2026-10-24 02:04:23 +08:00
87e2b66a8f
refactor(ios): add clang-format configuration and apply
427 lines
12 KiB
Objective-C
427 lines
12 KiB
Objective-C
/*!
|
|
* iOS SDK
|
|
*
|
|
* Tencent is pleased to support the open source community by making
|
|
* Hippy available.
|
|
*
|
|
* Copyright (C) 2019 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 "HippyTextField.h"
|
|
|
|
#import "HippyConvert.h"
|
|
#import "HippyUtils.h"
|
|
#import "HippyTextSelection.h"
|
|
#import "UIView+Hippy.h"
|
|
|
|
@implementation HippyUITextField {
|
|
BOOL _jsRequestingFirstResponder;
|
|
}
|
|
|
|
- (void)setKeyboardType:(UIKeyboardType)keyboardType {
|
|
NSString *tempPwdStr = self.text;
|
|
self.text = @"";
|
|
if (keyboardType == UIKeyboardTypeTwitter) {
|
|
self.secureTextEntry = true;
|
|
} else {
|
|
self.secureTextEntry = false;
|
|
[super setKeyboardType:keyboardType];
|
|
}
|
|
self.text = tempPwdStr;
|
|
}
|
|
|
|
- (void)setEditable:(BOOL)editable {
|
|
_editable = editable;
|
|
[self setEnabled:editable];
|
|
}
|
|
|
|
- (void)paste:(id)sender {
|
|
_textWasPasted = YES;
|
|
[super paste:sender];
|
|
}
|
|
|
|
- (void)hippyWillMakeFirstResponder {
|
|
_jsRequestingFirstResponder = YES;
|
|
}
|
|
|
|
- (BOOL)canBecomeFirstResponder {
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)becomeFirstResponder {
|
|
if (_responderDelegate && [_responderDelegate respondsToSelector:@selector(textview_becomeFirstResponder)]) {
|
|
[_responderDelegate textview_becomeFirstResponder];
|
|
}
|
|
|
|
return [super becomeFirstResponder];
|
|
}
|
|
|
|
- (BOOL)resignFirstResponder {
|
|
if (_responderDelegate && [_responderDelegate respondsToSelector:@selector(textview_resignFirstResponder)]) {
|
|
[_responderDelegate textview_resignFirstResponder];
|
|
}
|
|
return [super resignFirstResponder];
|
|
}
|
|
|
|
- (void)textview_becomeFirstResponder {
|
|
if (_onFocus) {
|
|
_onFocus(@{});
|
|
}
|
|
}
|
|
|
|
- (void)textview_resignFirstResponder {
|
|
if (_onBlur) {
|
|
_onBlur(@{});
|
|
}
|
|
}
|
|
|
|
- (void)hippyDidMakeFirstResponder {
|
|
_jsRequestingFirstResponder = YES;
|
|
}
|
|
|
|
- (void)didMoveToWindow {
|
|
if (_jsRequestingFirstResponder) {
|
|
[self becomeFirstResponder];
|
|
[self hippyDidMakeFirstResponder];
|
|
}
|
|
}
|
|
|
|
- (void)dealloc {
|
|
_responderDelegate = nil;
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
|
|
@end
|
|
|
|
@interface HippyTextField () <HippyUITextFieldResponseDelegate>
|
|
@end
|
|
|
|
@implementation HippyTextField {
|
|
UITextRange *_previousSelectionRange;
|
|
HippyUITextField *_textView;
|
|
}
|
|
|
|
- (void)keyboardWillShow:(NSNotification *)aNotification {
|
|
[super keyboardWillShow:aNotification];
|
|
NSDictionary *userInfo = [aNotification userInfo];
|
|
NSValue *aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
|
|
CGRect keyboardRect = [aValue CGRectValue];
|
|
CGFloat keyboardHeight = keyboardRect.size.height;
|
|
if (_textView.isFirstResponder && _onKeyboardWillShow) {
|
|
_onKeyboardWillShow(@{ @"keyboardHeight": @(keyboardHeight) });
|
|
}
|
|
}
|
|
|
|
- (instancetype)init {
|
|
if ((self = [super initWithFrame:CGRectZero])) {
|
|
[self setContentInset:UIEdgeInsetsZero];
|
|
_textView = [[HippyUITextField alloc] initWithFrame:CGRectZero];
|
|
_textView.responderDelegate = self;
|
|
_textView.backgroundColor = [UIColor clearColor];
|
|
_textView.textColor = [UIColor blackColor];
|
|
_textView.delegate = self;
|
|
[_textView addObserver:self forKeyPath:@"selectedTextRange" options:0 context:nil];
|
|
[_textView addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
|
|
[_textView addTarget:self action:@selector(textFieldBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
|
|
[_textView addTarget:self action:@selector(textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
|
|
[self addSubview:_textView];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[_textView removeObserver:self forKeyPath:@"selectedTextRange"];
|
|
}
|
|
|
|
HIPPY_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
|
|
HIPPY_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
|
|
|
// This method is overridden for `onKeyPress`. The manager
|
|
// will not send a keyPress for text that was pasted.
|
|
- (void)paste:(id)sender {
|
|
_textWasPasted = YES;
|
|
[_textView paste:sender];
|
|
}
|
|
|
|
- (CGRect)textRectForBounds:(CGRect)bounds {
|
|
CGRect rect = [_textView textRectForBounds:bounds];
|
|
return UIEdgeInsetsInsetRect(rect, self.contentInset);
|
|
}
|
|
|
|
- (CGRect)editingRectForBounds:(CGRect)bounds {
|
|
return [_textView textRectForBounds:bounds];
|
|
}
|
|
|
|
- (void)setAutoCorrect:(BOOL)autoCorrect {
|
|
_textView.autocorrectionType = (autoCorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo);
|
|
}
|
|
|
|
- (BOOL)autoCorrect {
|
|
return _textView.autocorrectionType == UITextAutocorrectionTypeYes;
|
|
}
|
|
|
|
- (void)textFieldDidChange {
|
|
UITextRange *selectedRange = [_textView markedTextRange];
|
|
NSString *newText = [_textView textInRange:selectedRange];
|
|
/**获取中文输入法下高亮部分并直接返回不做_onChangeText */
|
|
if (newText.length > 0) {
|
|
return;
|
|
}
|
|
// selectedTextRange observer isn't triggered when you type even though the
|
|
// cursor position moves, so we send event again here.
|
|
|
|
if (!self.hippyTag || !_onChangeText) {
|
|
return;
|
|
}
|
|
|
|
NSInteger theMaxLength = self.maxLength.integerValue;
|
|
if (theMaxLength == 0) {
|
|
theMaxLength = INT_MAX;
|
|
}
|
|
UITextField *textField = _textView;
|
|
NSString *toBeString = textField.text;
|
|
NSString *lang = [textField.textInputMode primaryLanguage];
|
|
if ([lang isEqualToString:@"zh-Hans"]) // 简体中文输入
|
|
{
|
|
NSString *toBeString = textField.text;
|
|
|
|
UITextRange *selectedRange = [textField markedTextRange];
|
|
UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
|
|
|
|
if (!position) {
|
|
if (toBeString.length > theMaxLength) {
|
|
NSRange rangeIndex = [toBeString rangeOfComposedCharacterSequenceAtIndex:theMaxLength];
|
|
if (rangeIndex.length == 1) {
|
|
textField.text = [toBeString substringToIndex:theMaxLength];
|
|
} else {
|
|
NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, theMaxLength)];
|
|
textField.text = [toBeString substringWithRange:rangeRange];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (toBeString.length > theMaxLength) {
|
|
NSRange rangeIndex = [toBeString rangeOfComposedCharacterSequenceAtIndex:theMaxLength];
|
|
if (rangeIndex.length == 1) {
|
|
textField.text = [toBeString substringToIndex:theMaxLength];
|
|
} else {
|
|
NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, theMaxLength)];
|
|
textField.text = [toBeString substringWithRange:rangeRange];
|
|
}
|
|
}
|
|
}
|
|
|
|
_onChangeText(@{
|
|
@"text": _textView.text,
|
|
});
|
|
|
|
[self sendSelectionEvent];
|
|
}
|
|
|
|
- (void)textFieldSubmitEditing {
|
|
}
|
|
|
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
|
if (_onEndEditing) {
|
|
_onEndEditing(@{
|
|
@"text": textField.text,
|
|
});
|
|
}
|
|
if (_onKeyPress) {
|
|
_onKeyPress(@{
|
|
@"key": @"enter",
|
|
});
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
#pragma mark - Notification Method
|
|
|
|
- (void)textFieldBeginEditing {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[self sendSelectionEvent];
|
|
});
|
|
}
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
ofObject:(__unused HippyTextField *)textField
|
|
change:(__unused NSDictionary *)change
|
|
context:(__unused void *)context {
|
|
if ([keyPath isEqualToString:@"selectedTextRange"]) {
|
|
[self sendSelectionEvent];
|
|
}
|
|
}
|
|
|
|
// defaultValue
|
|
- (void)setDefaultValue:(NSString *)defaultValue {
|
|
if (defaultValue && 0 == [self text].length) {
|
|
[_textView setText:defaultValue];
|
|
}
|
|
_defaultValue = defaultValue;
|
|
}
|
|
|
|
// focus/blur
|
|
- (void)focus {
|
|
[_textView becomeFirstResponder];
|
|
}
|
|
|
|
- (void)blur {
|
|
[_textView resignFirstResponder];
|
|
}
|
|
|
|
- (BOOL)becomeFirstResponder {
|
|
return [_textView becomeFirstResponder];
|
|
}
|
|
|
|
- (void)textview_becomeFirstResponder {
|
|
if (_onFocus) {
|
|
_onFocus(@{});
|
|
}
|
|
}
|
|
|
|
- (void)textview_resignFirstResponder {
|
|
if (_onBlur) {
|
|
_onBlur(@{});
|
|
}
|
|
}
|
|
|
|
- (BOOL)resignFirstResponder {
|
|
[super resignFirstResponder];
|
|
return [_textView resignFirstResponder];
|
|
}
|
|
|
|
- (void)updateFrames {
|
|
_textView.frame = self.bounds;
|
|
}
|
|
|
|
- (void)layoutSubviews {
|
|
[super layoutSubviews];
|
|
|
|
// Start sending content size updates only after the view has been laid out
|
|
// otherwise we send multiple events with bad dimensions on initial render.
|
|
// _viewDidCompleteInitialLayout = YES;
|
|
|
|
[self updateFrames];
|
|
}
|
|
|
|
- (void)setContentInset:(UIEdgeInsets)contentInset {
|
|
[super setContentInset:contentInset];
|
|
[self updateFrames];
|
|
}
|
|
|
|
- (void)setPlaceholder:(NSString *)placeholder {
|
|
_placeholder = placeholder;
|
|
[self updatePlaceholder];
|
|
}
|
|
|
|
- (void)setPlaceholderTextColor:(UIColor *)placeholderTextColor {
|
|
_placeholderTextColor = placeholderTextColor;
|
|
[self updatePlaceholder];
|
|
}
|
|
|
|
- (void)updatePlaceholder {
|
|
_textView.placeholder = _placeholder;
|
|
if (_placeholderTextColor && _placeholder) {
|
|
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:_placeholder
|
|
attributes:@{ NSForegroundColorAttributeName: _placeholderTextColor }];
|
|
_textView.attributedPlaceholder = attributedString;
|
|
}
|
|
}
|
|
|
|
- (void)setText:(NSString *)text {
|
|
double version = UIDevice.currentDevice.systemVersion.doubleValue;
|
|
if (version >= 10.0 && version < 12.0) {
|
|
text = [text stringByReplacingOccurrencesOfString:@"జ్ఞా" withString:@" "];
|
|
}
|
|
|
|
_textView.text = text;
|
|
_text = text;
|
|
}
|
|
|
|
- (void)setFontSize:(NSNumber *)fontSize {
|
|
_fontSize = fontSize;
|
|
if ([fontSize floatValue] > 0) {
|
|
[_textView setFont:[UIFont systemFontOfSize:[fontSize floatValue]]];
|
|
}
|
|
}
|
|
|
|
- (void)setValue:(NSString *)value {
|
|
[_textView setText:value];
|
|
}
|
|
|
|
- (NSString *)value {
|
|
return _textView.text;
|
|
}
|
|
|
|
- (void)setFont:(UIFont *)font {
|
|
_textView.font = font;
|
|
}
|
|
|
|
- (void)setTextColor:(UIColor *)textColor {
|
|
_textView.textColor = textColor;
|
|
}
|
|
|
|
- (UIColor *)textColor {
|
|
return _textView.textColor;
|
|
}
|
|
|
|
- (UIFont *)font {
|
|
return _textView.font;
|
|
}
|
|
|
|
- (void)sendSelectionEvent {
|
|
if (_onSelectionChange && _textView.selectedTextRange != _previousSelectionRange
|
|
&& ![_textView.selectedTextRange isEqual:_previousSelectionRange]) {
|
|
_previousSelectionRange = _textView.selectedTextRange;
|
|
|
|
UITextRange *selection = _textView.selectedTextRange;
|
|
NSInteger start = [_textView offsetFromPosition:[_textView beginningOfDocument] toPosition:selection.start];
|
|
NSInteger end = [_textView offsetFromPosition:[_textView beginningOfDocument] toPosition:selection.end];
|
|
_onSelectionChange(@{
|
|
@"selection": @ {
|
|
@"start": @(start),
|
|
@"end": @(end),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
- (void)clearText {
|
|
[_textView setText:@""];
|
|
}
|
|
|
|
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
|
|
if (_onKeyPress) {
|
|
NSString *resultKey = string;
|
|
if ([string isEqualToString:@" "]) {
|
|
resultKey = @"space";
|
|
} else if ([string isEqualToString:@""]) {
|
|
resultKey = @"backspace";
|
|
} else if ([string isEqualToString:@"\n"]) {
|
|
resultKey = @"enter"; //理论上这里没有enter,不过加一个总没错
|
|
}
|
|
_onKeyPress(@{ @"key": resultKey });
|
|
}
|
|
NSString *toBeString = [textField.text stringByReplacingCharactersInRange:range withString:string];
|
|
if (textField.isSecureTextEntry) {
|
|
textField.text = toBeString;
|
|
return NO;
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
@end
|