键盘添加撤销操作
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#import "KBHostAppLauncher.h"
|
||||
#import "KBKeyboardSubscriptionView.h"
|
||||
#import "KBKeyboardSubscriptionProduct.h"
|
||||
#import "KBBackspaceUndoManager.h"
|
||||
|
||||
// 提前声明一个类别,使编译器在 static 回调中识别 kb_consumePendingShopSkin 方法。
|
||||
@interface KeyboardViewController (KBSkinShopBridge)
|
||||
@@ -249,6 +250,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
|
||||
// MARK: - KBKeyBoardMainViewDelegate
|
||||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didTapKey:(KBKey *)key {
|
||||
if (key.type != KBKeyTypeShift && key.type != KBKeyTypeModeChange) {
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
}
|
||||
switch (key.type) {
|
||||
case KBKeyTypeCharacter:
|
||||
[self.textDocumentProxy insertText:key.output ?: key.title ?: @""]; break;
|
||||
@@ -285,9 +289,14 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
|
||||
|
||||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didSelectEmoji:(NSString *)emoji {
|
||||
if (emoji.length == 0) { return; }
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
[self.textDocumentProxy insertText:emoji];
|
||||
}
|
||||
|
||||
- (void)keyBoardMainViewDidTapUndo:(KBKeyBoardMainView *)keyBoardMainView {
|
||||
[[KBBackspaceUndoManager shared] performUndoFromResponder:self.view];
|
||||
}
|
||||
|
||||
- (void)keyBoardMainViewDidTapEmojiSearch:(KBKeyBoardMainView *)keyBoardMainView {
|
||||
[KBHUD showInfo:KBLocalized(@"Search coming soon")];
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#import "KBBackspaceLongPressHandler.h"
|
||||
#import "KBResponderUtils.h"
|
||||
#import "KBSkinManager.h"
|
||||
#import "KBBackspaceUndoManager.h"
|
||||
|
||||
static const NSTimeInterval kKBBackspaceLongPressMinDuration = 0.35;
|
||||
static const NSTimeInterval kKBBackspaceRepeatInterval = 0.06;
|
||||
@@ -96,6 +97,7 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
||||
}
|
||||
switch (gr.state) {
|
||||
case UIGestureRecognizerStateBegan: {
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
self.backspaceHoldToken += 1;
|
||||
NSUInteger token = self.backspaceHoldToken;
|
||||
self.backspaceHoldActive = YES;
|
||||
@@ -406,6 +408,12 @@ typedef NS_ENUM(NSInteger, KBBackspaceChunkClass) {
|
||||
#pragma mark - Clear
|
||||
|
||||
- (void)kb_clearAllInput {
|
||||
UIResponder *start = (UIResponder *)([self kb_hostView] ?: self.backspaceButton);
|
||||
UIInputViewController *ivc = KBFindInputViewController(start);
|
||||
if (ivc) {
|
||||
NSString *before = ivc.textDocumentProxy.documentContextBeforeInput ?: @"";
|
||||
[[KBBackspaceUndoManager shared] recordClearWithContext:before];
|
||||
}
|
||||
self.backspaceClearToken += 1;
|
||||
NSUInteger token = self.backspaceClearToken;
|
||||
[self kb_clearAllInputStepForToken:token guard:0 emptyRounds:0];
|
||||
|
||||
29
CustomKeyboard/Utils/KBBackspaceUndoManager.h
Normal file
29
CustomKeyboard/Utils/KBBackspaceUndoManager.h
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// KBBackspaceUndoManager.h
|
||||
// CustomKeyboard
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSNotificationName const KBBackspaceUndoStateDidChangeNotification;
|
||||
|
||||
@interface KBBackspaceUndoManager : NSObject
|
||||
|
||||
@property (nonatomic, readonly) BOOL hasUndo;
|
||||
|
||||
+ (instancetype)shared;
|
||||
|
||||
/// 记录一次“立刻清空”删除的内容(基于 documentContextBeforeInput)
|
||||
- (void)recordClearWithContext:(NSString *)context;
|
||||
|
||||
/// 在指定 responder 处执行撤销(向光标处插回删除的内容)
|
||||
- (void)performUndoFromResponder:(UIResponder *)responder;
|
||||
|
||||
/// 非清空行为触发时,清理撤销状态
|
||||
- (void)registerNonClearAction;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
170
CustomKeyboard/Utils/KBBackspaceUndoManager.m
Normal file
170
CustomKeyboard/Utils/KBBackspaceUndoManager.m
Normal file
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// KBBackspaceUndoManager.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
|
||||
#import "KBBackspaceUndoManager.h"
|
||||
#import "KBResponderUtils.h"
|
||||
|
||||
NSNotificationName const KBBackspaceUndoStateDidChangeNotification = @"KBBackspaceUndoStateDidChangeNotification";
|
||||
|
||||
@interface KBBackspaceUndoManager ()
|
||||
@property (nonatomic, strong) NSMutableArray<NSString *> *segments; // deletion order (last -> first)
|
||||
@property (nonatomic, assign) BOOL lastActionWasClear;
|
||||
@property (nonatomic, assign) BOOL hasUndo;
|
||||
@end
|
||||
|
||||
@implementation KBBackspaceUndoManager
|
||||
|
||||
+ (instancetype)shared {
|
||||
static KBBackspaceUndoManager *mgr = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
mgr = [[KBBackspaceUndoManager alloc] init];
|
||||
});
|
||||
return mgr;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_segments = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)recordClearWithContext:(NSString *)context {
|
||||
if (context.length == 0) { return; }
|
||||
NSString *segment = [self kb_segmentForClearFromContext:context];
|
||||
if (segment.length == 0) { return; }
|
||||
|
||||
if (!self.lastActionWasClear) {
|
||||
[self.segments removeAllObjects];
|
||||
}
|
||||
[self.segments addObject:segment];
|
||||
self.lastActionWasClear = YES;
|
||||
[self kb_updateHasUndo:YES];
|
||||
}
|
||||
|
||||
- (void)performUndoFromResponder:(UIResponder *)responder {
|
||||
if (self.segments.count == 0) { return; }
|
||||
UIInputViewController *ivc = KBFindInputViewController(responder);
|
||||
if (!ivc) { return; }
|
||||
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||
NSString *text = [self kb_buildUndoText];
|
||||
if (text.length == 0) { return; }
|
||||
[proxy insertText:text];
|
||||
|
||||
[self.segments removeAllObjects];
|
||||
self.lastActionWasClear = NO;
|
||||
[self kb_updateHasUndo:NO];
|
||||
}
|
||||
|
||||
- (void)registerNonClearAction {
|
||||
self.lastActionWasClear = NO;
|
||||
if (self.segments.count == 0) { return; }
|
||||
[self.segments removeAllObjects];
|
||||
[self kb_updateHasUndo:NO];
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)kb_updateHasUndo:(BOOL)hasUndo {
|
||||
if (self.hasUndo == hasUndo) { return; }
|
||||
self.hasUndo = hasUndo;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBBackspaceUndoStateDidChangeNotification object:self];
|
||||
}
|
||||
|
||||
- (NSString *)kb_segmentForClearFromContext:(NSString *)context {
|
||||
NSInteger length = context.length;
|
||||
if (length == 0) { return @""; }
|
||||
|
||||
static NSCharacterSet *sentenceBoundarySet = nil;
|
||||
static NSCharacterSet *whitespaceSet = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sentenceBoundarySet = [NSCharacterSet characterSetWithCharactersInString:@".!?;。!?;…\n"];
|
||||
whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
});
|
||||
|
||||
NSInteger end = length;
|
||||
while (end > 0) {
|
||||
unichar ch = [context characterAtIndex:end - 1];
|
||||
if ([whitespaceSet characterIsMember:ch]) {
|
||||
end -= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSInteger searchEnd = end;
|
||||
while (searchEnd > 0) {
|
||||
unichar ch = [context characterAtIndex:searchEnd - 1];
|
||||
if ([sentenceBoundarySet characterIsMember:ch]) {
|
||||
searchEnd -= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSInteger boundaryIndex = NSNotFound;
|
||||
for (NSInteger i = searchEnd - 1; i >= 0; i--) {
|
||||
unichar ch = [context characterAtIndex:i];
|
||||
if ([sentenceBoundarySet characterIsMember:ch]) {
|
||||
boundaryIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@@ -26,6 +26,7 @@
|
||||
#import <MJExtension/MJExtension.h>
|
||||
#import "KBBizCode.h"
|
||||
#import "KBBackspaceLongPressHandler.h"
|
||||
#import "KBBackspaceUndoManager.h"
|
||||
|
||||
@interface KBFunctionView () <KBFunctionBarViewDelegate, KBStreamOverlayViewDelegate, KBFunctionTagListViewDelegate>
|
||||
// UI
|
||||
@@ -769,6 +770,7 @@ static void KBULDarwinCallback(CFNotificationCenterRef center, void *observer, C
|
||||
}
|
||||
- (void)onTapDelete {
|
||||
NSLog(@"点击:删除");
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
UIInputViewController *ivc = KBFindInputViewController(self);
|
||||
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||
[proxy deleteBackward];
|
||||
@@ -779,6 +781,7 @@ static void KBULDarwinCallback(CFNotificationCenterRef center, void *observer, C
|
||||
}
|
||||
- (void)onTapSend {
|
||||
NSLog(@"点击:发送");
|
||||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||||
// 发送:插入换行。大多数聊天类 App 会把回车视为“发送”
|
||||
UIInputViewController *ivc = KBFindInputViewController(self);
|
||||
id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
|
||||
|
||||
@@ -23,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 点击了右侧设置按钮
|
||||
- (void)keyBoardMainViewDidTapSettings:(KBKeyBoardMainView *)keyBoardMainView;
|
||||
/// 点击了撤销删除按钮
|
||||
- (void)keyBoardMainViewDidTapUndo:(KBKeyBoardMainView *)keyBoardMainView;
|
||||
|
||||
/// emoji 视图里选择了一个表情
|
||||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView didSelectEmoji:(NSString *)emoji;
|
||||
|
||||
@@ -115,6 +115,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)toolBarDidTapUndo:(KBToolBar *)toolBar {
|
||||
if ([self.delegate respondsToSelector:@selector(keyBoardMainViewDidTapUndo:)]) {
|
||||
[self.delegate keyBoardMainViewDidTapUndo:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - KBKeyboardViewDelegate
|
||||
|
||||
- (void)keyboardView:(KBKeyboardView *)keyboard didTapKey:(KBKey *)key {
|
||||
|
||||
@@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)toolBar:(KBToolBar *)toolBar didTapActionAtIndex:(NSInteger)index;
|
||||
/// 右侧设置按钮点击
|
||||
- (void)toolBarDidTapSettings:(KBToolBar *)toolBar;
|
||||
/// 右侧撤销删除按钮点击
|
||||
- (void)toolBarDidTapUndo:(KBToolBar *)toolBar;
|
||||
@end
|
||||
|
||||
/// 顶部工具栏:左侧 4 个按钮,右侧 1 个设置按钮。
|
||||
@@ -30,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 暴露按钮以便外部定制(只读;首次访问时懒加载创建)
|
||||
@property (nonatomic, strong, readonly) NSArray<UIButton *> *leftButtons;
|
||||
@property (nonatomic, strong, readonly) UIButton *settingsButton;
|
||||
@property (nonatomic, strong, readonly) UIButton *undoButton;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -7,12 +7,16 @@
|
||||
|
||||
#import "KBToolBar.h"
|
||||
#import "KBResponderUtils.h" // 查找 UIInputViewController,用于系统切换输入法
|
||||
#import "KBBackspaceUndoManager.h"
|
||||
|
||||
@interface KBToolBar ()
|
||||
@property (nonatomic, strong) UIView *leftContainer;
|
||||
@property (nonatomic, strong) NSArray<UIButton *> *leftButtonsInternal;
|
||||
//@property (nonatomic, strong) UIButton *settingsButtonInternal;
|
||||
@property (nonatomic, strong) UIButton *globeButtonInternal; // 可选:系统“切换输入法”键
|
||||
@property (nonatomic, strong) UIButton *undoButtonInternal; // 右侧撤销删除
|
||||
@property (nonatomic, assign) BOOL kbNeedsInputModeSwitchKey;
|
||||
@property (nonatomic, assign) BOOL kbUndoVisible;
|
||||
@end
|
||||
|
||||
@implementation KBToolBar
|
||||
@@ -22,10 +26,18 @@
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
_leftButtonTitles = @[KBLocalized(@"Recharge Now")]; // 默认标题
|
||||
[self setupUI];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(kb_undoStateChanged)
|
||||
name:KBBackspaceUndoStateDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
@@ -33,6 +45,10 @@
|
||||
return self.leftButtonsInternal;
|
||||
}
|
||||
|
||||
- (UIButton *)undoButton {
|
||||
return self.undoButtonInternal;
|
||||
}
|
||||
|
||||
//- (UIButton *)settingsButton {
|
||||
// return self.settingsButtonInternal;
|
||||
//}
|
||||
@@ -53,6 +69,7 @@
|
||||
[self addSubview:self.leftContainer];
|
||||
// [self addSubview:self.settingsButtonInternal];
|
||||
[self addSubview:self.globeButtonInternal];
|
||||
[self addSubview:self.undoButtonInternal];
|
||||
|
||||
// 右侧设置按钮
|
||||
// [self.settingsButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -68,14 +85,15 @@
|
||||
make.width.height.mas_equalTo(32);
|
||||
}];
|
||||
|
||||
// 左侧容器占用剩余空间
|
||||
[self.leftContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.globeButtonInternal.mas_right).offset(8);
|
||||
make.right.equalTo(self).offset(-12);
|
||||
// 右侧撤销按钮
|
||||
[self.undoButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.mas_right).offset(-12);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.height.mas_equalTo(32);
|
||||
}];
|
||||
|
||||
[self kb_updateLeftContainerConstraints];
|
||||
|
||||
// 在左侧容器中创建按钮(数量 = 标题数量)
|
||||
NSMutableArray<UIButton *> *buttons = [NSMutableArray arrayWithCapacity:_leftButtonTitles.count];
|
||||
UIView *previous = nil;
|
||||
@@ -110,6 +128,7 @@
|
||||
|
||||
// 初始刷新地球键的可见性与事件绑定
|
||||
[self kb_refreshGlobeVisibility];
|
||||
[self kb_updateUndoVisibilityAnimated:NO];
|
||||
}
|
||||
|
||||
- (UIButton *)buildActionButtonAtIndex:(NSInteger)idx {
|
||||
@@ -147,6 +166,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onUndo {
|
||||
if ([self.delegate respondsToSelector:@selector(toolBarDidTapUndo:)]) {
|
||||
[self.delegate toolBarDidTapUndo:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
|
||||
- (UIView *)leftContainer {
|
||||
@@ -182,6 +207,23 @@
|
||||
return _globeButtonInternal;
|
||||
}
|
||||
|
||||
- (UIButton *)undoButtonInternal {
|
||||
if (!_undoButtonInternal) {
|
||||
_undoButtonInternal = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
_undoButtonInternal.layer.cornerRadius = 16;
|
||||
_undoButtonInternal.layer.masksToBounds = YES;
|
||||
_undoButtonInternal.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
|
||||
_undoButtonInternal.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
|
||||
[_undoButtonInternal setTitle:@"撤销删除" forState:UIControlStateNormal];
|
||||
[_undoButtonInternal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||
_undoButtonInternal.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 10);
|
||||
_undoButtonInternal.hidden = YES;
|
||||
_undoButtonInternal.alpha = 0.0;
|
||||
[_undoButtonInternal addTarget:self action:@selector(onUndo) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _undoButtonInternal;
|
||||
}
|
||||
|
||||
#pragma mark - Globe (Input Mode Switch)
|
||||
|
||||
// 根据宿主是否已提供系统切换键,决定是否显示地球按钮;并绑定系统事件。
|
||||
@@ -193,18 +235,9 @@
|
||||
}
|
||||
|
||||
self.globeButtonInternal.hidden = !needSwitchKey;
|
||||
self.kbNeedsInputModeSwitchKey = needSwitchKey;
|
||||
|
||||
// 重新调整 leftContainer 的左约束:若不需要地球键,则贴左边距 12
|
||||
[self.leftContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (needSwitchKey) {
|
||||
make.left.equalTo(self.globeButtonInternal.mas_right).offset(8);
|
||||
} else {
|
||||
make.left.equalTo(self.mas_left).offset(12);
|
||||
}
|
||||
make.right.equalTo(self).offset(-12);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.height.mas_equalTo(32);
|
||||
}];
|
||||
[self kb_updateLeftContainerConstraints];
|
||||
|
||||
// 绑定系统提供的输入法切换处理(点按切换、长按弹出列表)
|
||||
// 仅在需要时绑定,避免多余的事件转发
|
||||
@@ -220,6 +253,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)kb_updateLeftContainerConstraints {
|
||||
[self.leftContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.kbNeedsInputModeSwitchKey) {
|
||||
make.left.equalTo(self.globeButtonInternal.mas_right).offset(8);
|
||||
} else {
|
||||
make.left.equalTo(self.mas_left).offset(12);
|
||||
}
|
||||
if (self.kbUndoVisible) {
|
||||
make.right.equalTo(self.undoButtonInternal.mas_left).offset(-8);
|
||||
} else {
|
||||
make.right.equalTo(self).offset(-12);
|
||||
}
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.height.mas_equalTo(32);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)kb_undoStateChanged {
|
||||
[self kb_updateUndoVisibilityAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)kb_updateUndoVisibilityAnimated:(BOOL)animated {
|
||||
BOOL visible = [KBBackspaceUndoManager shared].hasUndo;
|
||||
if (self.kbUndoVisible == visible) { return; }
|
||||
self.kbUndoVisible = visible;
|
||||
self.undoButtonInternal.hidden = NO;
|
||||
|
||||
[self kb_updateLeftContainerConstraints];
|
||||
void (^changes)(void) = ^{
|
||||
self.undoButtonInternal.alpha = visible ? 1.0 : 0.0;
|
||||
[self layoutIfNeeded];
|
||||
};
|
||||
void (^finish)(BOOL) = ^(BOOL finished) {
|
||||
self.undoButtonInternal.hidden = !visible;
|
||||
};
|
||||
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.18
|
||||
delay:0
|
||||
options:UIViewAnimationOptionCurveEaseInOut
|
||||
animations:changes
|
||||
completion:finish];
|
||||
} else {
|
||||
changes();
|
||||
finish(YES);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didMoveToWindow {
|
||||
[super didMoveToWindow];
|
||||
[self kb_refreshGlobeVisibility];
|
||||
|
||||
Reference in New Issue
Block a user