From 7b02207537d35bfa1714bf8beafc921f717d100a Mon Sep 17 00:00:00 2001
From: 单军华
Date: Wed, 11 Jul 2018 10:47:42 +0800
Subject: [PATCH] 首次上传
---
screendisplay/Pods/YYText/YYText/Component/YYTextKeyboardManager.m | 521 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 521 insertions(+), 0 deletions(-)
diff --git a/screendisplay/Pods/YYText/YYText/Component/YYTextKeyboardManager.m b/screendisplay/Pods/YYText/YYText/Component/YYTextKeyboardManager.m
new file mode 100755
index 0000000..43467bb
--- /dev/null
+++ b/screendisplay/Pods/YYText/YYText/Component/YYTextKeyboardManager.m
@@ -0,0 +1,521 @@
+//
+// YYTextKeyboardManager.m
+// YYText <https://github.com/ibireme/YYText>
+//
+// Created by ibireme on 15/6/3.
+// Copyright (c) 2015 ibireme.
+//
+// This source code is licensed under the MIT-style license found in the
+// LICENSE file in the root directory of this source tree.
+//
+
+#import "YYTextKeyboardManager.h"
+#import "YYTextUtilities.h"
+#import <objc/runtime.h>
+
+
+static int _YYTextKeyboardViewFrameObserverKey;
+
+/// Observer for view's frame/bounds/center/transform
+@interface _YYTextKeyboardViewFrameObserver : NSObject
+@property (nonatomic, copy) void (^notifyBlock)(UIView *keyboard);
+- (void)addToKeyboardView:(UIView *)keyboardView;
++ (instancetype)observerForView:(UIView *)keyboardView;
+@end
+
+
+@implementation _YYTextKeyboardViewFrameObserver {
+ __unsafe_unretained UIView *_keyboardView;
+}
+- (void)addToKeyboardView:(UIView *)keyboardView {
+ if (_keyboardView == keyboardView) return;
+ if (_keyboardView) {
+ [self removeFrameObserver];
+ objc_setAssociatedObject(_keyboardView, &_YYTextKeyboardViewFrameObserverKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ }
+ _keyboardView = keyboardView;
+ if (keyboardView) {
+ [self addFrameObserver];
+ }
+ objc_setAssociatedObject(keyboardView, &_YYTextKeyboardViewFrameObserverKey, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (void)removeFrameObserver {
+ [_keyboardView removeObserver:self forKeyPath:@"frame"];
+ [_keyboardView removeObserver:self forKeyPath:@"center"];
+ [_keyboardView removeObserver:self forKeyPath:@"bounds"];
+ [_keyboardView removeObserver:self forKeyPath:@"transform"];
+ _keyboardView = nil;
+}
+
+- (void)addFrameObserver {
+ if (!_keyboardView) return;
+ [_keyboardView addObserver:self forKeyPath:@"frame" options:kNilOptions context:NULL];
+ [_keyboardView addObserver:self forKeyPath:@"center" options:kNilOptions context:NULL];
+ [_keyboardView addObserver:self forKeyPath:@"bounds" options:kNilOptions context:NULL];
+ [_keyboardView addObserver:self forKeyPath:@"transform" options:kNilOptions context:NULL];
+}
+
+- (void)dealloc {
+ [self removeFrameObserver];
+}
+
++ (instancetype)observerForView:(UIView *)keyboardView {
+ if (!keyboardView) return nil;
+ return objc_getAssociatedObject(keyboardView, &_YYTextKeyboardViewFrameObserverKey);
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+
+ BOOL isPrior = [[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue];
+ if (isPrior) return;
+
+ NSKeyValueChange changeKind = [[change objectForKey:NSKeyValueChangeKindKey] integerValue];
+ if (changeKind != NSKeyValueChangeSetting) return;
+
+ id newVal = [change objectForKey:NSKeyValueChangeNewKey];
+ if (newVal == [NSNull null]) newVal = nil;
+
+ if (_notifyBlock) {
+ _notifyBlock(_keyboardView);
+ }
+}
+
+@end
+
+
+
+@implementation YYTextKeyboardManager {
+ NSHashTable *_observers;
+
+ CGRect _fromFrame;
+ BOOL _fromVisible;
+ UIInterfaceOrientation _fromOrientation;
+
+ CGRect _notificationFromFrame;
+ CGRect _notificationToFrame;
+ NSTimeInterval _notificationDuration;
+ UIViewAnimationCurve _notificationCurve;
+ BOOL _hasNotification;
+
+ CGRect _observedToFrame;
+ BOOL _hasObservedChange;
+
+ BOOL _lastIsNotification;
+}
+
+- (instancetype)init {
+ @throw [NSException exceptionWithName:@"YYTextKeyboardManager init error" reason:@"Use 'defaultManager' to get instance." userInfo:nil];
+ return [super init];
+}
+
+- (instancetype)_init {
+ self = [super init];
+ _observers = [[NSHashTable alloc] initWithOptions:NSPointerFunctionsWeakMemory|NSPointerFunctionsObjectPointerPersonality capacity:0];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(_keyboardFrameWillChangeNotification:)
+ name:UIKeyboardWillChangeFrameNotification
+ object:nil];
+ // for iPad (iOS 9)
+ if ([UIDevice currentDevice].systemVersion.floatValue >= 9) {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(_keyboardFrameDidChangeNotification:)
+ name:UIKeyboardDidChangeFrameNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)_initFrameObserver {
+ UIView *keyboardView = self.keyboardView;
+ if (!keyboardView) return;
+ __weak typeof(self) _self = self;
+ _YYTextKeyboardViewFrameObserver *observer = [_YYTextKeyboardViewFrameObserver observerForView:keyboardView];
+ if (!observer) {
+ observer = [_YYTextKeyboardViewFrameObserver new];
+ observer.notifyBlock = ^(UIView *keyboard) {
+ [_self _keyboardFrameChanged:keyboard];
+ };
+ [observer addToKeyboardView:keyboardView];
+ }
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
++ (instancetype)defaultManager {
+ static YYTextKeyboardManager *mgr = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ if (!YYTextIsAppExtension()) {
+ mgr = [[self alloc] _init];
+ }
+ });
+ return mgr;
+}
+
++ (void)load {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [self defaultManager];
+ });
+}
+
+- (void)addObserver:(id<YYTextKeyboardObserver>)observer {
+ if (!observer) return;
+ [_observers addObject:observer];
+}
+
+- (void)removeObserver:(id<YYTextKeyboardObserver>)observer {
+ if (!observer) return;
+ [_observers removeObject:observer];
+}
+
+- (UIWindow *)keyboardWindow {
+ UIApplication *app = YYTextSharedApplication();
+ if (!app) return nil;
+
+ UIWindow *window = nil;
+ for (window in app.windows) {
+ if ([self _getKeyboardViewFromWindow:window]) return window;
+ }
+ window = app.keyWindow;
+ if ([self _getKeyboardViewFromWindow:window]) return window;
+
+ NSMutableArray *kbWindows = nil;
+ for (window in app.windows) {
+ NSString *windowName = NSStringFromClass(window.class);
+ if ([self _systemVersion] < 9) {
+ // UITextEffectsWindow
+ if (windowName.length == 19 &&
+ [windowName hasPrefix:@"UI"] &&
+ [windowName hasSuffix:@"TextEffectsWindow"]) {
+ if (!kbWindows) kbWindows = [NSMutableArray new];
+ [kbWindows addObject:window];
+ }
+ } else {
+ // UIRemoteKeyboardWindow
+ if (windowName.length == 22 &&
+ [windowName hasPrefix:@"UI"] &&
+ [windowName hasSuffix:@"RemoteKeyboardWindow"]) {
+ if (!kbWindows) kbWindows = [NSMutableArray new];
+ [kbWindows addObject:window];
+ }
+ }
+ }
+
+ if (kbWindows.count == 1) {
+ return kbWindows.firstObject;
+ }
+ return nil;
+}
+
+- (UIView *)keyboardView {
+ UIApplication *app = YYTextSharedApplication();
+ if (!app) return nil;
+
+ UIWindow *window = nil;
+ UIView *view = nil;
+ for (window in app.windows) {
+ view = [self _getKeyboardViewFromWindow:window];
+ if (view) return view;
+ }
+ window = app.keyWindow;
+ view = [self _getKeyboardViewFromWindow:window];
+ if (view) return view;
+ return nil;
+}
+
+- (BOOL)isKeyboardVisible {
+ UIWindow *window = self.keyboardWindow;
+ if (!window) return NO;
+ UIView *view = self.keyboardView;
+ if (!view) return NO;
+ CGRect rect = CGRectIntersection(window.bounds, view.frame);
+ if (CGRectIsNull(rect)) return NO;
+ if (CGRectIsInfinite(rect)) return NO;
+ return rect.size.width > 0 && rect.size.height > 0;
+}
+
+- (CGRect)keyboardFrame {
+ UIView *keyboard = [self keyboardView];
+ if (!keyboard) return CGRectNull;
+
+ CGRect frame = CGRectNull;
+ UIWindow *window = keyboard.window;
+ if (window) {
+ frame = [window convertRect:keyboard.frame toWindow:nil];
+ } else {
+ frame = keyboard.frame;
+ }
+ return frame;
+}
+
+#pragma mark - private
+
+- (double)_systemVersion {
+ static double v;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ v = [UIDevice currentDevice].systemVersion.doubleValue;
+ });
+ return v;
+}
+
+- (UIView *)_getKeyboardViewFromWindow:(UIWindow *)window {
+ /*
+ iOS 6/7:
+ UITextEffectsWindow
+ UIPeripheralHostView << keyboard
+
+ iOS 8:
+ UITextEffectsWindow
+ UIInputSetContainerView
+ UIInputSetHostView << keyboard
+
+ iOS 9:
+ UIRemoteKeyboardWindow
+ UIInputSetContainerView
+ UIInputSetHostView << keyboard
+ */
+ if (!window) return nil;
+
+ // Get the window
+ NSString *windowName = NSStringFromClass(window.class);
+ if ([self _systemVersion] < 9) {
+ // UITextEffectsWindow
+ if (windowName.length != 19) return nil;
+ if (![windowName hasPrefix:@"UI"]) return nil;
+ if (![windowName hasSuffix:@"TextEffectsWindow"]) return nil;
+ } else {
+ // UIRemoteKeyboardWindow
+ if (windowName.length != 22) return nil;
+ if (![windowName hasPrefix:@"UI"]) return nil;
+ if (![windowName hasSuffix:@"RemoteKeyboardWindow"]) return nil;
+ }
+
+ // Get the view
+ if ([self _systemVersion] < 8) {
+ // UIPeripheralHostView
+ for (UIView *view in window.subviews) {
+ NSString *viewName = NSStringFromClass(view.class);
+ if (viewName.length != 20) continue;
+ if (![viewName hasPrefix:@"UI"]) continue;
+ if (![viewName hasSuffix:@"PeripheralHostView"]) continue;
+ return view;
+ }
+ } else {
+ // UIInputSetContainerView
+ for (UIView *view in window.subviews) {
+ NSString *viewName = NSStringFromClass(view.class);
+ if (viewName.length != 23) continue;
+ if (![viewName hasPrefix:@"UI"]) continue;
+ if (![viewName hasSuffix:@"InputSetContainerView"]) continue;
+ // UIInputSetHostView
+ for (UIView *subView in view.subviews) {
+ NSString *subViewName = NSStringFromClass(subView.class);
+ if (subViewName.length != 18) continue;
+ if (![subViewName hasPrefix:@"UI"]) continue;
+ if (![subViewName hasSuffix:@"InputSetHostView"]) continue;
+ return subView;
+ }
+ }
+ }
+
+ return nil;
+}
+
+- (void)_keyboardFrameWillChangeNotification:(NSNotification *)notif {
+ if (![notif.name isEqualToString:UIKeyboardWillChangeFrameNotification]) return;
+ NSDictionary *info = notif.userInfo;
+ if (!info) return;
+
+ [self _initFrameObserver];
+
+ NSValue *beforeValue = info[UIKeyboardFrameBeginUserInfoKey];
+ NSValue *afterValue = info[UIKeyboardFrameEndUserInfoKey];
+ NSNumber *curveNumber = info[UIKeyboardAnimationCurveUserInfoKey];
+ NSNumber *durationNumber = info[UIKeyboardAnimationDurationUserInfoKey];
+
+ CGRect before = beforeValue.CGRectValue;
+ CGRect after = afterValue.CGRectValue;
+ UIViewAnimationCurve curve = curveNumber.integerValue;
+ NSTimeInterval duration = durationNumber.doubleValue;
+
+ // ignore zero end frame
+ if (after.size.width <= 0 && after.size.height <= 0) return;
+
+ _notificationFromFrame = before;
+ _notificationToFrame = after;
+ _notificationCurve = curve;
+ _notificationDuration = duration;
+ _hasNotification = YES;
+ _lastIsNotification = YES;
+
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_notifyAllObservers) object:nil];
+ if (duration == 0) {
+ [self performSelector:@selector(_notifyAllObservers) withObject:nil afterDelay:0 inModes:@[NSRunLoopCommonModes]];
+ } else {
+ [self _notifyAllObservers];
+ }
+}
+
+- (void)_keyboardFrameDidChangeNotification:(NSNotification *)notif {
+ if (![notif.name isEqualToString:UIKeyboardDidChangeFrameNotification]) return;
+ NSDictionary *info = notif.userInfo;
+ if (!info) return;
+
+ [self _initFrameObserver];
+
+ NSValue *afterValue = info[UIKeyboardFrameEndUserInfoKey];
+ CGRect after = afterValue.CGRectValue;
+
+ // ignore zero end frame
+ if (after.size.width <= 0 && after.size.height <= 0) return;
+
+ _notificationToFrame = after;
+ _notificationCurve = UIViewAnimationCurveEaseInOut;
+ _notificationDuration = 0;
+ _hasNotification = YES;
+ _lastIsNotification = YES;
+
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_notifyAllObservers) object:nil];
+ [self performSelector:@selector(_notifyAllObservers) withObject:nil afterDelay:0 inModes:@[NSRunLoopCommonModes]];
+}
+
+- (void)_keyboardFrameChanged:(UIView *)keyboard {
+ if (keyboard != self.keyboardView) return;
+
+ UIWindow *window = keyboard.window;
+ if (window) {
+ _observedToFrame = [window convertRect:keyboard.frame toWindow:nil];
+ } else {
+ _observedToFrame = keyboard.frame;
+ }
+ _hasObservedChange = YES;
+ _lastIsNotification = NO;
+
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_notifyAllObservers) object:nil];
+ [self performSelector:@selector(_notifyAllObservers) withObject:nil afterDelay:0 inModes:@[NSRunLoopCommonModes]];
+}
+
+- (void)_notifyAllObservers {
+ UIApplication *app = YYTextSharedApplication();
+ if (!app) return;
+
+ UIView *keyboard = self.keyboardView;
+ UIWindow *window = keyboard.window;
+ if (!window) {
+ window = app.keyWindow;
+ }
+ if (!window) {
+ window = app.windows.firstObject;
+ }
+
+ YYTextKeyboardTransition trans = {0};
+
+ // from
+ if (_fromFrame.size.width == 0 && _fromFrame.size.height == 0) { // first notify
+ _fromFrame.size.width = window.bounds.size.width;
+ _fromFrame.size.height = trans.toFrame.size.height;
+ _fromFrame.origin.x = trans.toFrame.origin.x;
+ _fromFrame.origin.y = window.bounds.size.height;
+ }
+ trans.fromFrame = _fromFrame;
+ trans.fromVisible = _fromVisible;
+
+ // to
+ if (_lastIsNotification || (_hasObservedChange && CGRectEqualToRect(_observedToFrame, _notificationToFrame))) {
+ trans.toFrame = _notificationToFrame;
+ trans.animationDuration = _notificationDuration;
+ trans.animationCurve = _notificationCurve;
+ trans.animationOption = _notificationCurve << 16;
+
+ // Fix iPad(iOS7) keyboard frame error after rorate device when the keyboard is not docked to bottom.
+ if (((int)[self _systemVersion]) == 7) {
+ UIInterfaceOrientation ori = app.statusBarOrientation;
+ if (_fromOrientation != UIInterfaceOrientationUnknown && _fromOrientation != ori) {
+ switch (ori) {
+ case UIInterfaceOrientationPortrait: {
+ if (CGRectGetMaxY(trans.toFrame) != window.frame.size.height) {
+ trans.toFrame.origin.y -= trans.toFrame.size.height;
+ }
+ } break;
+ case UIInterfaceOrientationPortraitUpsideDown: {
+ if (CGRectGetMinY(trans.toFrame) != 0) {
+ trans.toFrame.origin.y += trans.toFrame.size.height;
+ }
+ } break;
+ case UIInterfaceOrientationLandscapeLeft: {
+ if (CGRectGetMaxX(trans.toFrame) != window.frame.size.width) {
+ trans.toFrame.origin.x -= trans.toFrame.size.width;
+ }
+ } break;
+ case UIInterfaceOrientationLandscapeRight: {
+ if (CGRectGetMinX(trans.toFrame) != 0) {
+ trans.toFrame.origin.x += trans.toFrame.size.width;
+ }
+ } break;
+ default: break;
+ }
+ }
+ }
+ } else {
+ trans.toFrame = _observedToFrame;
+ }
+
+ if (window && trans.toFrame.size.width > 0 && trans.toFrame.size.height > 0) {
+ CGRect rect = CGRectIntersection(window.bounds, trans.toFrame);
+ if (!CGRectIsNull(rect) && !CGRectIsEmpty(rect)) {
+ trans.toVisible = YES;
+ }
+ }
+
+ if (!CGRectEqualToRect(trans.toFrame, _fromFrame)) {
+ for (id<YYTextKeyboardObserver> observer in _observers.copy) {
+ if ([observer respondsToSelector:@selector(keyboardChangedWithTransition:)]) {
+ [observer keyboardChangedWithTransition:trans];
+ }
+ }
+ }
+
+ _hasNotification = NO;
+ _hasObservedChange = NO;
+ _fromFrame = trans.toFrame;
+ _fromVisible = trans.toVisible;
+ _fromOrientation = app.statusBarOrientation;
+}
+
+- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view {
+ UIApplication *app = YYTextSharedApplication();
+ if (!app) return CGRectZero;
+
+ if (CGRectIsNull(rect)) return rect;
+ if (CGRectIsInfinite(rect)) return rect;
+
+ UIWindow *mainWindow = app.keyWindow;
+ if (!mainWindow) mainWindow = app.windows.firstObject;
+ if (!mainWindow) { // no window ?!
+ if (view) {
+ [view convertRect:rect fromView:nil];
+ } else {
+ return rect;
+ }
+ }
+
+ rect = [mainWindow convertRect:rect fromWindow:nil];
+ if (!view) return [mainWindow convertRect:rect toWindow:nil];
+ if (view == mainWindow) return rect;
+
+ UIWindow *toWindow = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
+ if (!mainWindow || !toWindow) return [mainWindow convertRect:rect toView:view];
+ if (mainWindow == toWindow) return [mainWindow convertRect:rect toView:view];
+
+ // in different window
+ rect = [mainWindow convertRect:rect toView:mainWindow];
+ rect = [toWindow convertRect:rect fromWindow:mainWindow];
+ rect = [view convertRect:rect fromView:toWindow];
+ return rect;
+}
+
+@end
--
Gitblit v1.8.0