重构
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// KBKeyboardInteractionHandler.m
|
||||
// CustomKeyboard
|
||||
//
|
||||
|
||||
#import "KBKeyboardInteractionHandler.h"
|
||||
#import "KBKeyButton.h"
|
||||
#import "KBKey.h"
|
||||
#import "KBKeyPreviewView.h"
|
||||
|
||||
static const NSTimeInterval kKBPreviewShowDuration = 0.08;
|
||||
static const NSTimeInterval kKBPreviewHideDuration = 0.06;
|
||||
|
||||
@interface KBKeyboardInteractionHandler ()
|
||||
@property (nonatomic, strong) KBKeyPreviewView *previewView;
|
||||
@end
|
||||
|
||||
@implementation KBKeyboardInteractionHandler
|
||||
|
||||
- (UIView *)resolveHitView:(UIView *)hitView
|
||||
point:(CGPoint)point
|
||||
container:(UIView *)container
|
||||
rowViews:(NSArray<UIView *> *)rowViews {
|
||||
if ([hitView isKindOfClass:[KBKeyButton class]]) {
|
||||
return hitView;
|
||||
}
|
||||
if ([self isHitInsideKeyRows:hitView rowViews:rowViews]) {
|
||||
KBKeyButton *btn = [self nearestKeyButtonForPoint:point
|
||||
container:container
|
||||
rowViews:rowViews];
|
||||
if (btn) { return btn; }
|
||||
}
|
||||
return hitView;
|
||||
}
|
||||
|
||||
- (NSArray<KBKeyButton *> *)collectKeyButtonsInView:(UIView *)view {
|
||||
if (!view) { return @[]; }
|
||||
NSMutableArray<KBKeyButton *> *buttons = [NSMutableArray array];
|
||||
[self collectKeyButtonsInView:view into:buttons];
|
||||
return buttons.copy;
|
||||
}
|
||||
|
||||
- (void)showPreviewForButton:(KBKeyButton *)button inContainer:(UIView *)container {
|
||||
if (!button || !container) { return; }
|
||||
KBKey *key = button.key;
|
||||
if (key.type != KBKeyTypeCharacter) return;
|
||||
|
||||
if (!self.previewView) {
|
||||
self.previewView = [[KBKeyPreviewView alloc] initWithFrame:CGRectZero];
|
||||
self.previewView.hidden = YES;
|
||||
[container addSubview:self.previewView];
|
||||
} else if (self.previewView.superview != container) {
|
||||
[container addSubview:self.previewView];
|
||||
}
|
||||
|
||||
[self.previewView configureWithKey:key icon:button.iconView.image];
|
||||
|
||||
// 计算预览视图位置:在按钮上方稍微偏上
|
||||
CGRect btnFrameInSelf = [button convertRect:button.bounds toView:container];
|
||||
CGFloat previewWidth = 42;
|
||||
CGFloat previewHeight = CGRectGetHeight(btnFrameInSelf) * 1.2;
|
||||
CGFloat centerX = CGRectGetMidX(btnFrameInSelf);
|
||||
CGFloat centerY = CGRectGetMinY(btnFrameInSelf) - previewHeight * 0.6;
|
||||
|
||||
self.previewView.frame = CGRectMake(0, 0, previewWidth, previewHeight);
|
||||
self.previewView.center = CGPointMake(centerX, centerY);
|
||||
self.previewView.alpha = 0.0;
|
||||
self.previewView.hidden = NO;
|
||||
|
||||
[UIView animateWithDuration:kKBPreviewShowDuration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut
|
||||
animations:^{
|
||||
self.previewView.alpha = 1.0;
|
||||
}
|
||||
completion:nil];
|
||||
}
|
||||
|
||||
- (void)hidePreview {
|
||||
if (!self.previewView || self.previewView.isHidden) return;
|
||||
[UIView animateWithDuration:kKBPreviewHideDuration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn
|
||||
animations:^{
|
||||
self.previewView.alpha = 0.0;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
self.previewView.hidden = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)bringPreviewToFrontIfNeededInContainer:(UIView *)container {
|
||||
if (!container) { return; }
|
||||
if (self.previewView && self.previewView.superview == container) {
|
||||
[container bringSubviewToFront:self.previewView];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (BOOL)isHitInsideKeyRows:(UIView *)hitView rowViews:(NSArray<UIView *> *)rowViews {
|
||||
if (!hitView) { return NO; }
|
||||
if ([rowViews containsObject:hitView]) { return YES; }
|
||||
for (UIView *row in rowViews) {
|
||||
if ([hitView isDescendantOfView:row]) { return YES; }
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (KBKeyButton *)nearestKeyButtonForPoint:(CGPoint)point
|
||||
container:(UIView *)container
|
||||
rowViews:(NSArray<UIView *> *)rowViews {
|
||||
if (!container) { return nil; }
|
||||
KBKeyButton *best = nil;
|
||||
CGFloat bestDistance = CGFLOAT_MAX;
|
||||
|
||||
UIView *targetRow = nil;
|
||||
for (UIView *row in rowViews) {
|
||||
CGRect rowFrame = [container convertRect:row.bounds fromView:row];
|
||||
if (CGRectContainsPoint(rowFrame, point)) {
|
||||
targetRow = row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSArray<UIView *> *candidateRows = targetRow ? @[targetRow] : rowViews;
|
||||
for (UIView *row in candidateRows) {
|
||||
NSArray<KBKeyButton *> *buttons = [self collectKeyButtonsInView:row];
|
||||
for (KBKeyButton *btn in buttons) {
|
||||
CGRect frame = [container convertRect:btn.frame fromView:btn.superview];
|
||||
CGFloat dx = point.x - CGRectGetMidX(frame);
|
||||
CGFloat dy = point.y - CGRectGetMidY(frame);
|
||||
CGFloat dist = (dx * dx) + (dy * dy);
|
||||
if (dist < bestDistance) {
|
||||
bestDistance = dist;
|
||||
best = btn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
- (void)collectKeyButtonsInView:(UIView *)view
|
||||
into:(NSMutableArray<KBKeyButton *> *)buttons {
|
||||
for (UIView *sub in view.subviews) {
|
||||
if ([sub isKindOfClass:[KBKeyButton class]]) {
|
||||
[buttons addObject:(KBKeyButton *)sub];
|
||||
continue;
|
||||
}
|
||||
if (sub.subviews.count > 0) {
|
||||
[self collectKeyButtonsInView:sub into:buttons];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user