处理键盘长按删除 撤销出现的bug
This commit is contained in:
@@ -363,30 +363,33 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
|||||||
|
|
||||||
// MARK: - KBKeyBoardMainViewDelegate
|
// MARK: - KBKeyBoardMainViewDelegate
|
||||||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapKey:(KBKey *)key {
|
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapKey:(KBKey *)key {
|
||||||
if (key.type != KBKeyTypeShift && key.type != KBKeyTypeModeChange) {
|
|
||||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
|
||||||
}
|
|
||||||
switch (key.type) {
|
switch (key.type) {
|
||||||
case KBKeyTypeCharacter: {
|
case KBKeyTypeCharacter: {
|
||||||
|
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||||
NSString *text = key.output ?: key.title ?: @"";
|
NSString *text = key.output ?: key.title ?: @"";
|
||||||
[self.textDocumentProxy insertText:text];
|
[self.textDocumentProxy insertText:text];
|
||||||
[self kb_updateCurrentWordWithInsertedText:text];
|
[self kb_updateCurrentWordWithInsertedText:text];
|
||||||
} break;
|
} break;
|
||||||
case KBKeyTypeBackspace:
|
case KBKeyTypeBackspace:
|
||||||
|
[[KBBackspaceUndoManager shared] recordDeletionSnapshotBefore:self.textDocumentProxy.documentContextBeforeInput
|
||||||
|
after:self.textDocumentProxy.documentContextAfterInput];
|
||||||
[self.textDocumentProxy deleteBackward];
|
[self.textDocumentProxy deleteBackward];
|
||||||
[self kb_scheduleContextRefreshResetSuppression:NO];
|
[self kb_scheduleContextRefreshResetSuppression:NO];
|
||||||
break;
|
break;
|
||||||
case KBKeyTypeSpace:
|
case KBKeyTypeSpace:
|
||||||
|
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||||
[self.textDocumentProxy insertText:@" "];
|
[self.textDocumentProxy insertText:@" "];
|
||||||
[self kb_clearCurrentWord];
|
[self kb_clearCurrentWord];
|
||||||
break;
|
break;
|
||||||
case KBKeyTypeReturn:
|
case KBKeyTypeReturn:
|
||||||
|
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||||
[self.textDocumentProxy insertText:@"\n"];
|
[self.textDocumentProxy insertText:@"\n"];
|
||||||
[self kb_clearCurrentWord];
|
[self kb_clearCurrentWord];
|
||||||
break;
|
break;
|
||||||
case KBKeyTypeGlobe:
|
case KBKeyTypeGlobe:
|
||||||
[self advanceToNextInputMode]; break;
|
[self advanceToNextInputMode]; break;
|
||||||
case KBKeyTypeCustom:
|
case KBKeyTypeCustom:
|
||||||
|
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||||
// 点击自定义键切换到功能面板
|
// 点击自定义键切换到功能面板
|
||||||
[self showFunctionPanel:YES];
|
[self showFunctionPanel:YES];
|
||||||
[self kb_clearCurrentWord];
|
[self kb_clearCurrentWord];
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
|||||||
@property (nonatomic, assign) CGPoint backspaceLastTouchPointInSelf;
|
@property (nonatomic, assign) CGPoint backspaceLastTouchPointInSelf;
|
||||||
@property (nonatomic, assign) NSUInteger backspaceClearToken;
|
@property (nonatomic, assign) NSUInteger backspaceClearToken;
|
||||||
@property (nonatomic, strong) UILabel *backspaceClearLabel;
|
@property (nonatomic, strong) UILabel *backspaceClearLabel;
|
||||||
|
@property (nonatomic, copy) NSString *pendingClearBefore;
|
||||||
|
@property (nonatomic, copy) NSString *pendingClearAfter;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation KBBackspaceLongPressHandler
|
@implementation KBBackspaceLongPressHandler
|
||||||
@@ -73,6 +75,8 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
|||||||
self.backspaceHasLastTouchPoint = NO;
|
self.backspaceHasLastTouchPoint = NO;
|
||||||
self.backspaceHoldToken += 1;
|
self.backspaceHoldToken += 1;
|
||||||
[self kb_hideBackspaceClearLabel];
|
[self kb_hideBackspaceClearLabel];
|
||||||
|
self.pendingClearBefore = nil;
|
||||||
|
self.pendingClearAfter = nil;
|
||||||
|
|
||||||
if (!button) { return; }
|
if (!button) { return; }
|
||||||
|
|
||||||
@@ -99,7 +103,10 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
|||||||
}
|
}
|
||||||
switch (gr.state) {
|
switch (gr.state) {
|
||||||
case UIGestureRecognizerStateBegan: {
|
case UIGestureRecognizerStateBegan: {
|
||||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
[self kb_captureDeletionSnapshotIfNeeded];
|
||||||
|
if (self.showClearLabelEnabled) {
|
||||||
|
[self kb_capturePendingClearSnapshotIfNeeded];
|
||||||
|
}
|
||||||
self.backspaceHoldToken += 1;
|
self.backspaceHoldToken += 1;
|
||||||
NSUInteger token = self.backspaceHoldToken;
|
NSUInteger token = self.backspaceHoldToken;
|
||||||
self.backspaceHoldActive = YES;
|
self.backspaceHoldActive = YES;
|
||||||
@@ -310,6 +317,9 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
|||||||
[self kb_hideBackspaceClearLabel];
|
[self kb_hideBackspaceClearLabel];
|
||||||
if (shouldClear) {
|
if (shouldClear) {
|
||||||
[self kb_clearAllInput];
|
[self kb_clearAllInput];
|
||||||
|
} else {
|
||||||
|
self.pendingClearBefore = nil;
|
||||||
|
self.pendingClearAfter = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,9 +431,12 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
|||||||
UIResponder *start = (UIResponder *)([self kb_hostView] ?: self.backspaceButton);
|
UIResponder *start = (UIResponder *)([self kb_hostView] ?: self.backspaceButton);
|
||||||
UIInputViewController *ivc = KBFindInputViewController(start);
|
UIInputViewController *ivc = KBFindInputViewController(start);
|
||||||
if (ivc) {
|
if (ivc) {
|
||||||
NSString *before = ivc.textDocumentProxy.documentContextBeforeInput ?: @"";
|
NSString *before = self.pendingClearBefore ?: (ivc.textDocumentProxy.documentContextBeforeInput ?: @"");
|
||||||
[[KBBackspaceUndoManager shared] recordClearWithContext:before];
|
NSString *after = self.pendingClearAfter ?: (ivc.textDocumentProxy.documentContextAfterInput ?: @"");
|
||||||
|
[[KBBackspaceUndoManager shared] recordClearWithContextBefore:before after:after];
|
||||||
}
|
}
|
||||||
|
self.pendingClearBefore = nil;
|
||||||
|
self.pendingClearAfter = nil;
|
||||||
self.backspaceClearToken += 1;
|
self.backspaceClearToken += 1;
|
||||||
NSUInteger token = self.backspaceClearToken;
|
NSUInteger token = self.backspaceClearToken;
|
||||||
[self kb_clearAllInputStepForToken:token guard:0 emptyRounds:0];
|
[self kb_clearAllInputStepForToken:token guard:0 emptyRounds:0];
|
||||||
@@ -489,4 +502,25 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
|||||||
return self.backspaceButton.superview;
|
return self.backspaceButton.superview;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)kb_captureDeletionSnapshotIfNeeded {
|
||||||
|
if ([KBBackspaceUndoManager shared].hasUndo) { return; }
|
||||||
|
UIResponder *start = (UIResponder *)([self kb_hostView] ?: self.backspaceButton);
|
||||||
|
UIInputViewController *ivc = KBFindInputViewController(start);
|
||||||
|
if (!ivc) { return; }
|
||||||
|
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||||
|
[[KBBackspaceUndoManager shared] recordDeletionSnapshotBefore:proxy.documentContextBeforeInput
|
||||||
|
after:proxy.documentContextAfterInput];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)kb_capturePendingClearSnapshotIfNeeded {
|
||||||
|
if ([KBBackspaceUndoManager shared].hasUndo) { return; }
|
||||||
|
if (self.pendingClearBefore.length > 0 || self.pendingClearAfter.length > 0) { return; }
|
||||||
|
UIResponder *start = (UIResponder *)([self kb_hostView] ?: self.backspaceButton);
|
||||||
|
UIInputViewController *ivc = KBFindInputViewController(start);
|
||||||
|
if (!ivc) { return; }
|
||||||
|
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||||
|
self.pendingClearBefore = proxy.documentContextBeforeInput ?: @"";
|
||||||
|
self.pendingClearAfter = proxy.documentContextAfterInput ?: @"";
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -15,13 +15,16 @@ extern NSNotificationName const KBBackspaceUndoStateDidChangeNotification;
|
|||||||
|
|
||||||
+ (instancetype)shared;
|
+ (instancetype)shared;
|
||||||
|
|
||||||
/// 记录一次“立刻清空”删除的内容(基于 documentContextBeforeInput)
|
/// 记录一次删除前的快照(不改变撤销按钮显示)。
|
||||||
- (void)recordClearWithContext:(NSString *)context;
|
- (void)recordDeletionSnapshotBefore:(NSString *)before after:(NSString *)after;
|
||||||
|
|
||||||
|
/// 记录一次“立刻清空”删除的内容(基于 documentContextBeforeInput/AfterInput)。
|
||||||
|
- (void)recordClearWithContextBefore:(NSString *)before after:(NSString *)after;
|
||||||
|
|
||||||
/// 在指定 responder 处执行撤销(向光标处插回删除的内容)
|
/// 在指定 responder 处执行撤销(向光标处插回删除的内容)
|
||||||
- (void)performUndoFromResponder:(UIResponder *)responder;
|
- (void)performUndoFromResponder:(UIResponder *)responder;
|
||||||
|
|
||||||
/// 非清空行为触发时,清理撤销状态
|
/// 非删除行为触发时,清理撤销状态
|
||||||
- (void)registerNonClearAction;
|
- (void)registerNonClearAction;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
NSNotificationName const KBBackspaceUndoStateDidChangeNotification = @"KBBackspaceUndoStateDidChangeNotification";
|
NSNotificationName const KBBackspaceUndoStateDidChangeNotification = @"KBBackspaceUndoStateDidChangeNotification";
|
||||||
|
|
||||||
@interface KBBackspaceUndoManager ()
|
@interface KBBackspaceUndoManager ()
|
||||||
@property (nonatomic, strong) NSMutableArray<NSString *> *segments; // deletion order (last -> first)
|
@property (nonatomic, copy) NSString *undoText;
|
||||||
@property (nonatomic, assign) BOOL lastActionWasClear;
|
@property (nonatomic, assign) NSInteger undoAfterLength;
|
||||||
@property (nonatomic, assign) BOOL hasUndo;
|
@property (nonatomic, assign) BOOL hasUndo;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -27,42 +27,57 @@ NSNotificationName const KBBackspaceUndoStateDidChangeNotification = @"KBBackspa
|
|||||||
|
|
||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_segments = [NSMutableArray array];
|
_undoText = @"";
|
||||||
|
_undoAfterLength = 0;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)recordClearWithContext:(NSString *)context {
|
- (void)recordDeletionSnapshotBefore:(NSString *)before after:(NSString *)after {
|
||||||
if (context.length == 0) { return; }
|
if (self.undoText.length > 0) { return; }
|
||||||
NSString *segment = [self kb_segmentForClearFromContext:context];
|
NSString *safeBefore = before ?: @"";
|
||||||
if (segment.length == 0) { return; }
|
NSString *safeAfter = after ?: @"";
|
||||||
|
NSString *full = [safeBefore stringByAppendingString:safeAfter];
|
||||||
|
if (full.length == 0) { return; }
|
||||||
|
self.undoText = full;
|
||||||
|
self.undoAfterLength = (NSInteger)safeAfter.length;
|
||||||
|
}
|
||||||
|
|
||||||
if (!self.lastActionWasClear) {
|
- (void)recordClearWithContextBefore:(NSString *)before after:(NSString *)after {
|
||||||
[self.segments removeAllObjects];
|
if (self.undoText.length == 0) {
|
||||||
|
NSString *safeBefore = before ?: @"";
|
||||||
|
NSString *safeAfter = after ?: @"";
|
||||||
|
NSString *full = [safeBefore stringByAppendingString:safeAfter];
|
||||||
|
if (full.length > 0) {
|
||||||
|
self.undoText = full;
|
||||||
|
self.undoAfterLength = (NSInteger)safeAfter.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[self.segments addObject:segment];
|
if (self.undoText.length == 0) { return; }
|
||||||
self.lastActionWasClear = YES;
|
|
||||||
[self kb_updateHasUndo:YES];
|
[self kb_updateHasUndo:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performUndoFromResponder:(UIResponder *)responder {
|
- (void)performUndoFromResponder:(UIResponder *)responder {
|
||||||
if (self.segments.count == 0) { return; }
|
if (self.undoText.length == 0) { return; }
|
||||||
UIInputViewController *ivc = KBFindInputViewController(responder);
|
UIInputViewController *ivc = KBFindInputViewController(responder);
|
||||||
if (!ivc) { return; }
|
if (!ivc) { return; }
|
||||||
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||||
NSString *text = [self kb_buildUndoText];
|
[self kb_clearAllTextForProxy:proxy];
|
||||||
if (text.length == 0) { return; }
|
[proxy insertText:self.undoText];
|
||||||
[proxy insertText:text];
|
if (self.undoAfterLength > 0 &&
|
||||||
|
[proxy respondsToSelector:@selector(adjustTextPositionByCharacterOffset:)]) {
|
||||||
|
[proxy adjustTextPositionByCharacterOffset:-self.undoAfterLength];
|
||||||
|
}
|
||||||
|
|
||||||
[self.segments removeAllObjects];
|
self.undoText = @"";
|
||||||
self.lastActionWasClear = NO;
|
self.undoAfterLength = 0;
|
||||||
[self kb_updateHasUndo:NO];
|
[self kb_updateHasUndo:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)registerNonClearAction {
|
- (void)registerNonClearAction {
|
||||||
self.lastActionWasClear = NO;
|
if (self.undoText.length == 0) { return; }
|
||||||
if (self.segments.count == 0) { return; }
|
self.undoText = @"";
|
||||||
[self.segments removeAllObjects];
|
self.undoAfterLength = 0;
|
||||||
[self kb_updateHasUndo:NO];
|
[self kb_updateHasUndo:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,97 +89,34 @@ NSNotificationName const KBBackspaceUndoStateDidChangeNotification = @"KBBackspa
|
|||||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBBackspaceUndoStateDidChangeNotification object:self];
|
[[NSNotificationCenter defaultCenter] postNotificationName:KBBackspaceUndoStateDidChangeNotification object:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)kb_segmentForClearFromContext:(NSString *)context {
|
static const NSInteger kKBUndoClearMaxRounds = 200;
|
||||||
NSInteger length = context.length;
|
|
||||||
if (length == 0) { return @""; }
|
|
||||||
|
|
||||||
static NSCharacterSet *sentenceBoundarySet = nil;
|
- (void)kb_clearAllTextForProxy:(id<UITextDocumentProxy>)proxy {
|
||||||
static NSCharacterSet *whitespaceSet = nil;
|
if (!proxy) { return; }
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
sentenceBoundarySet = [NSCharacterSet characterSetWithCharactersInString:@".!?;。!?;…\n"];
|
|
||||||
whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
||||||
});
|
|
||||||
|
|
||||||
NSInteger end = length;
|
if ([proxy respondsToSelector:@selector(adjustTextPositionByCharacterOffset:)]) {
|
||||||
while (end > 0) {
|
NSInteger guard = 0;
|
||||||
unichar ch = [context characterAtIndex:end - 1];
|
NSString *contextAfter = proxy.documentContextAfterInput ?: @"";
|
||||||
if ([whitespaceSet characterIsMember:ch]) {
|
while (contextAfter.length > 0 && guard < kKBUndoClearMaxRounds) {
|
||||||
end -= 1;
|
NSInteger offset = (NSInteger)contextAfter.length;
|
||||||
} else {
|
[proxy adjustTextPositionByCharacterOffset:offset];
|
||||||
break;
|
for (NSUInteger i = 0; i < contextAfter.length; i++) {
|
||||||
}
|
[proxy deleteBackward];
|
||||||
}
|
}
|
||||||
NSInteger searchEnd = end;
|
guard += 1;
|
||||||
while (searchEnd > 0) {
|
contextAfter = proxy.documentContextAfterInput ?: @"";
|
||||||
unichar ch = [context characterAtIndex:searchEnd - 1];
|
|
||||||
if ([sentenceBoundarySet characterIsMember:ch]) {
|
|
||||||
searchEnd -= 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NSInteger boundaryIndex = NSNotFound;
|
NSInteger guard = 0;
|
||||||
for (NSInteger i = searchEnd - 1; i >= 0; i--) {
|
NSString *contextBefore = proxy.documentContextBeforeInput ?: @"";
|
||||||
unichar ch = [context characterAtIndex:i];
|
while (contextBefore.length > 0 && guard < kKBUndoClearMaxRounds) {
|
||||||
if ([sentenceBoundarySet characterIsMember:ch]) {
|
for (NSUInteger i = 0; i < contextBefore.length; i++) {
|
||||||
boundaryIndex = i;
|
[proxy deleteBackward];
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
guard += 1;
|
||||||
|
contextBefore = proxy.documentContextBeforeInput ?: @"";
|
||||||
}
|
}
|
||||||
|
|
||||||
NSInteger start = (boundaryIndex == NSNotFound) ? 0 : (boundaryIndex + 1);
|
|
||||||
if (start >= length) { return @""; }
|
|
||||||
return [context substringFromIndex:start];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)kb_buildUndoText {
|
|
||||||
if (self.segments.count == 0) { return @""; }
|
|
||||||
NSArray<NSString *> *ordered = [[self.segments reverseObjectEnumerator] allObjects];
|
|
||||||
NSMutableString *result = [NSMutableString string];
|
|
||||||
for (NSInteger i = 0; i < ordered.count; i++) {
|
|
||||||
NSString *segment = ordered[i] ?: @"";
|
|
||||||
if (segment.length == 0) { continue; }
|
|
||||||
if (i < ordered.count - 1) {
|
|
||||||
segment = [self kb_replaceTrailingBoundaryWithComma:segment];
|
|
||||||
}
|
|
||||||
[result appendString:segment];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)kb_replaceTrailingBoundaryWithComma:(NSString *)segment {
|
|
||||||
if (segment.length == 0) { return segment; }
|
|
||||||
|
|
||||||
static NSCharacterSet *boundarySet = nil;
|
|
||||||
static NSCharacterSet *englishBoundarySet = nil;
|
|
||||||
static NSCharacterSet *whitespaceSet = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
boundarySet = [NSCharacterSet characterSetWithCharactersInString:@".!?;。!?;…\n"];
|
|
||||||
englishBoundarySet = [NSCharacterSet characterSetWithCharactersInString:@".!?;"];
|
|
||||||
whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
||||||
});
|
|
||||||
|
|
||||||
NSInteger idx = segment.length - 1;
|
|
||||||
while (idx >= 0) {
|
|
||||||
unichar ch = [segment characterAtIndex:idx];
|
|
||||||
if ([whitespaceSet characterIsMember:ch]) {
|
|
||||||
idx -= 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (![boundarySet characterIsMember:ch]) {
|
|
||||||
return segment;
|
|
||||||
}
|
|
||||||
NSString *comma = [englishBoundarySet characterIsMember:ch] ? @"," : @",";
|
|
||||||
NSMutableString *mutable = [segment mutableCopy];
|
|
||||||
NSRange r = NSMakeRange(idx, 1);
|
|
||||||
[mutable replaceCharactersInRange:r withString:comma];
|
|
||||||
return mutable;
|
|
||||||
}
|
|
||||||
|
|
||||||
return segment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -770,18 +770,21 @@ static void KBULDarwinCallback(CFNotificationCenterRef center, void *observer, C
|
|||||||
- (void)kb_fullAccessChanged {
|
- (void)kb_fullAccessChanged {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{ [self kb_refreshPasteboardMonitor]; });
|
dispatch_async(dispatch_get_main_queue(), ^{ [self kb_refreshPasteboardMonitor]; });
|
||||||
}
|
}
|
||||||
- (void)onTapDelete {
|
|
||||||
|
- (void)onTapDelete {
|
||||||
NSLog(@"点击:删除");
|
NSLog(@"点击:删除");
|
||||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
|
||||||
UIInputViewController *ivc = KBFindInputViewController(self);
|
UIInputViewController *ivc = KBFindInputViewController(self);
|
||||||
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||||
|
[[KBBackspaceUndoManager shared] recordDeletionSnapshotBefore:proxy.documentContextBeforeInput
|
||||||
|
after:proxy.documentContextAfterInput];
|
||||||
[proxy deleteBackward];
|
[proxy deleteBackward];
|
||||||
}
|
}
|
||||||
- (void)onTapClear {
|
- (void)onTapClear {
|
||||||
NSLog(@"点击:清空");
|
NSLog(@"点击:清空");
|
||||||
[self.backspaceHandler performClearAction];
|
[self.backspaceHandler performClearAction];
|
||||||
}
|
}
|
||||||
- (void)onTapSend {
|
|
||||||
|
- (void)onTapSend {
|
||||||
NSLog(@"点击:发送");
|
NSLog(@"点击:发送");
|
||||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||||
// 发送:插入换行。大多数聊天类 App 会把回车视为“发送”
|
// 发送:插入换行。大多数聊天类 App 会把回车视为“发送”
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#import "KBSuggestionBarView.h"
|
#import "KBSuggestionBarView.h"
|
||||||
#import "Masonry.h"
|
#import "Masonry.h"
|
||||||
#import "KBSkinManager.h"
|
#import "KBSkinManager.h"
|
||||||
|
#import "KBBackspaceUndoManager.h"
|
||||||
|
|
||||||
@interface KBKeyBoardMainView ()<KBToolBarDelegate, KBKeyboardViewDelegate, KBEmojiPanelViewDelegate, KBSuggestionBarViewDelegate>
|
@interface KBKeyBoardMainView ()<KBToolBarDelegate, KBKeyboardViewDelegate, KBEmojiPanelViewDelegate, KBSuggestionBarViewDelegate>
|
||||||
@property (nonatomic, strong) KBToolBar *topBar;
|
@property (nonatomic, strong) KBToolBar *topBar;
|
||||||
@@ -87,10 +88,18 @@
|
|||||||
make.top.equalTo(self.topBar.mas_bottom).offset(barSpacing);
|
make.top.equalTo(self.topBar.mas_bottom).offset(barSpacing);
|
||||||
}];
|
}];
|
||||||
// 功能面板切换交由外部控制器处理;此处不直接创建/管理
|
// 功能面板切换交由外部控制器处理;此处不直接创建/管理
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(kb_undoStateChanged)
|
||||||
|
name:KBBackspaceUndoStateDidChangeNotification
|
||||||
|
object:nil];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setEmojiPanelVisible:(BOOL)visible animated:(BOOL)animated {
|
- (void)setEmojiPanelVisible:(BOOL)visible animated:(BOOL)animated {
|
||||||
if (self.emojiPanelVisible == visible) return;
|
if (self.emojiPanelVisible == visible) return;
|
||||||
self.emojiPanelVisible = visible;
|
self.emojiPanelVisible = visible;
|
||||||
@@ -108,7 +117,7 @@
|
|||||||
self.emojiView.alpha = visible ? 1.0 : 0.0;
|
self.emojiView.alpha = visible ? 1.0 : 0.0;
|
||||||
self.keyboardView.alpha = visible ? 0.0 : 1.0;
|
self.keyboardView.alpha = visible ? 0.0 : 1.0;
|
||||||
self.topBar.alpha = visible ? 0.0 : 1.0;
|
self.topBar.alpha = visible ? 0.0 : 1.0;
|
||||||
self.suggestionBar.alpha = visible ? 0.0 : (self.suggestionBarHasItems ? 1.0 : 0.0);
|
self.suggestionBar.alpha = visible ? 0.0 : ([self kb_shouldShowSuggestions] ? 1.0 : 0.0);
|
||||||
};
|
};
|
||||||
void (^completion)(BOOL) = ^(BOOL finished) {
|
void (^completion)(BOOL) = ^(BOOL finished) {
|
||||||
self.emojiView.hidden = !visible;
|
self.emojiView.hidden = !visible;
|
||||||
@@ -117,7 +126,7 @@
|
|||||||
if (visible) {
|
if (visible) {
|
||||||
self.suggestionBar.hidden = YES;
|
self.suggestionBar.hidden = YES;
|
||||||
} else {
|
} else {
|
||||||
self.suggestionBar.hidden = !self.suggestionBarHasItems;
|
self.suggestionBar.hidden = ![self kb_shouldShowSuggestions];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -258,14 +267,7 @@
|
|||||||
- (void)kb_setSuggestions:(NSArray<NSString *> *)suggestions {
|
- (void)kb_setSuggestions:(NSArray<NSString *> *)suggestions {
|
||||||
self.suggestionBarHasItems = (suggestions.count > 0);
|
self.suggestionBarHasItems = (suggestions.count > 0);
|
||||||
[self.suggestionBar updateSuggestions:suggestions];
|
[self.suggestionBar updateSuggestions:suggestions];
|
||||||
|
[self kb_applySuggestionVisibility];
|
||||||
if (self.emojiPanelVisible) {
|
|
||||||
self.suggestionBar.hidden = YES;
|
|
||||||
self.suggestionBar.alpha = 0.0;
|
|
||||||
} else {
|
|
||||||
self.suggestionBar.hidden = !self.suggestionBarHasItems;
|
|
||||||
self.suggestionBar.alpha = self.suggestionBarHasItems ? 1.0 : 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - KBSuggestionBarViewDelegate
|
#pragma mark - KBSuggestionBarViewDelegate
|
||||||
@@ -276,4 +278,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)kb_undoStateChanged {
|
||||||
|
[self kb_applySuggestionVisibility];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)kb_shouldShowSuggestions {
|
||||||
|
if (self.emojiPanelVisible) { return NO; }
|
||||||
|
if (![KBBackspaceUndoManager shared].hasUndo && self.suggestionBarHasItems) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)kb_applySuggestionVisibility {
|
||||||
|
BOOL shouldShow = [self kb_shouldShowSuggestions];
|
||||||
|
self.suggestionBar.hidden = !shouldShow;
|
||||||
|
self.suggestionBar.alpha = shouldShow ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user