| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949 |
- /*
- Version 0.3.9
- WYPopoverController is available under the MIT license.
- Copyright © 2013 Nicolas CHENG
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #import "WYPopoverController.h"
- #import <objc/runtime.h>
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
- #define WY_BASE_SDK_7_ENABLED
- #endif
- #ifdef DEBUG
- #define WY_LOG(fmt, ...) NSLog((@"%s (%d) : " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
- #else
- #define WY_LOG(...)
- #endif
- #define WY_IS_IOS_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
- #define WY_IS_IOS_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
- #define WY_IS_IOS_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
- #define WY_IS_IOS_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface WYKeyboardListener : NSObject
- + (BOOL)isVisible;
- + (CGRect)rect;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @implementation WYKeyboardListener
- static BOOL _isVisible;
- static CGRect _keyboardRect;
- + (void)load {
- @autoreleasepool {
- _keyboardRect = CGRectZero;
- _isVisible = NO;
- [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
- [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(keyboardWillHide) name:UIKeyboardWillHideNotification object:nil];
- }
- }
- + (void)keyboardWillShow:(NSNotification *)notification {
- NSDictionary *info = [notification userInfo];
- _keyboardRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
- _isVisible = YES;
- }
- + (void)keyboardWillHide {
- _keyboardRect = CGRectZero;
- _isVisible = NO;
- }
- + (BOOL)isVisible {
- return _isVisible;
- }
- + (CGRect)rect {
- return _keyboardRect;
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface UIColor (WYPopover)
- - (BOOL)wy_getValueOfRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)apha;
- - (NSString *)wy_hexString;
- - (UIColor *)wy_colorByLighten:(float)d;
- - (UIColor *)wy_colorByDarken:(float)d;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @implementation UIColor (WYPopover)
- - (BOOL)wy_getValueOfRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha {
- // model: kCGColorSpaceModelRGB, num_comps: 4
- // model: kCGColorSpaceModelMonochrome, num_comps: 2
- CGColorSpaceRef colorSpace = CGColorSpaceRetain(CGColorGetColorSpace([self CGColor]));
- CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
- CGColorSpaceRelease(colorSpace);
- CGFloat rFloat = 0.0, gFloat = 0.0, bFloat = 0.0, aFloat = 0.0;
- BOOL result = NO;
- if (colorSpaceModel == kCGColorSpaceModelRGB) {
- result = [self getRed:&rFloat green:&gFloat blue:&bFloat alpha:&aFloat];
- } else if (colorSpaceModel == kCGColorSpaceModelMonochrome) {
- result = [self getWhite:&rFloat alpha:&aFloat];
- gFloat = rFloat;
- bFloat = rFloat;
- }
- if (red) *red = rFloat;
- if (green) *green = gFloat;
- if (blue) *blue = bFloat;
- if (alpha) *alpha = aFloat;
- return result;
- }
- - (NSString *)wy_hexString {
- CGFloat rFloat, gFloat, bFloat, aFloat;
- int r, g, b, a;
- [self wy_getValueOfRed:&rFloat green:&gFloat blue:&bFloat alpha:&aFloat];
- r = (int)(255.0 * rFloat);
- g = (int)(255.0 * gFloat);
- b = (int)(255.0 * bFloat);
- a = (int)(255.0 * aFloat);
- return [NSString stringWithFormat:@"#%02x%02x%02x%02x", r, g, b, a];
- }
- - (UIColor *)wy_colorByLighten:(float)d {
- CGFloat rFloat, gFloat, bFloat, aFloat;
- [self wy_getValueOfRed:&rFloat green:&gFloat blue:&bFloat alpha:&aFloat];
- return [UIColor colorWithRed:MIN(rFloat + d, 1.0)
- green:MIN(gFloat + d, 1.0)
- blue:MIN(bFloat + d, 1.0)
- alpha:1.0];
- }
- - (UIColor *)wy_colorByDarken:(float)d {
- CGFloat rFloat, gFloat, bFloat, aFloat;
- [self wy_getValueOfRed:&rFloat green:&gFloat blue:&bFloat alpha:&aFloat];
- return [UIColor colorWithRed:MAX(rFloat - d, 0.0)
- green:MAX(gFloat - d, 0.0)
- blue:MAX(bFloat - d, 0.0)
- alpha:1.0];
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface UINavigationController (WYPopover)
- @property(nonatomic, assign, getter = wy_isEmbedInPopover) BOOL wy_embedInPopover;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @implementation UINavigationController (WYPopover)
- static char const * const UINavigationControllerEmbedInPopoverTagKey = "UINavigationControllerEmbedInPopoverTagKey";
- @dynamic wy_embedInPopover;
- + (void)load {
- Method original, swizzle;
- original = class_getInstanceMethod(self, @selector(pushViewController:animated:));
- swizzle = class_getInstanceMethod(self, @selector(sizzled_pushViewController:animated:));
- method_exchangeImplementations(original, swizzle);
- original = class_getInstanceMethod(self, @selector(setViewControllers:animated:));
- swizzle = class_getInstanceMethod(self, @selector(sizzled_setViewControllers:animated:));
- method_exchangeImplementations(original, swizzle);
- }
- - (BOOL)wy_isEmbedInPopover {
- BOOL result = NO;
- NSNumber *value = objc_getAssociatedObject(self, UINavigationControllerEmbedInPopoverTagKey);
- if (value) {
- result = [value boolValue];
- }
- return result;
- }
- - (void)setWy_embedInPopover:(BOOL)value
- {
- objc_setAssociatedObject(self, UINavigationControllerEmbedInPopoverTagKey, [NSNumber numberWithBool:value], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (CGSize)contentSize:(UIViewController *)aViewController {
- CGSize result = CGSizeZero;
- #pragma clang diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated"
- if ([aViewController respondsToSelector:@selector(contentSizeForViewInPopover)]) {
- result = aViewController.contentSizeForViewInPopover;
- }
- #pragma clang diagnostic pop
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([aViewController respondsToSelector:@selector(preferredContentSize)]) {
- result = aViewController.preferredContentSize;
- }
- #endif
- return result;
- }
- - (void)setContentSize:(CGSize)aContentSize {
- #pragma clang diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated"
- [self setContentSizeForViewInPopover:aContentSize];
- #pragma clang diagnostic pop
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([self respondsToSelector:@selector(setPreferredContentSize:)]) {
- [self setPreferredContentSize:aContentSize];
- }
- #endif
- }
- - (void)sizzled_pushViewController:(UIViewController *)aViewController animated:(BOOL)aAnimated {
- if (self.wy_isEmbedInPopover) {
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([aViewController respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
- aViewController.edgesForExtendedLayout = UIRectEdgeNone;
- }
- #endif
- CGSize contentSize = [self contentSize:aViewController];
- [self setContentSize:contentSize];
- }
- [self sizzled_pushViewController:aViewController animated:aAnimated];
- if (self.wy_isEmbedInPopover) {
- CGSize contentSize = [self contentSize:aViewController];
- [self setContentSize:contentSize];
- }
- }
- - (void)sizzled_setViewControllers:(NSArray *)aViewControllers animated:(BOOL)aAnimated {
- NSUInteger count = [aViewControllers count];
- #ifdef WY_BASE_SDK_7_ENABLED
- if (self.wy_isEmbedInPopover && count > 0) {
- for (UIViewController *viewController in aViewControllers) {
- if ([viewController respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
- viewController.edgesForExtendedLayout = UIRectEdgeNone;
- }
- }
- }
- #endif
- [self sizzled_setViewControllers:aViewControllers animated:aAnimated];
- if (self.wy_isEmbedInPopover && count > 0) {
- UIViewController *topViewController = [aViewControllers objectAtIndex:(count - 1)];
- CGSize contentSize = [self contentSize:topViewController];
- [self setContentSize:contentSize];
- }
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface UIViewController (WYPopover)
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @implementation UIViewController (WYPopover)
- + (void)load {
- Method original, swizzle;
- #pragma clang diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated"
- original = class_getInstanceMethod(self, @selector(setContentSizeForViewInPopover:));
- swizzle = class_getInstanceMethod(self, @selector(sizzled_setContentSizeForViewInPopover:));
- method_exchangeImplementations(original, swizzle);
- #pragma clang diagnostic pop
- #ifdef WY_BASE_SDK_7_ENABLED
- original = class_getInstanceMethod(self, @selector(setPreferredContentSize:));
- swizzle = class_getInstanceMethod(self, @selector(sizzled_setPreferredContentSize:));
- if (original != NULL) {
- method_exchangeImplementations(original, swizzle);
- }
- #endif
- }
- - (void)sizzled_setContentSizeForViewInPopover:(CGSize)aSize {
- [self sizzled_setContentSizeForViewInPopover:aSize];
- if ([self isKindOfClass:[UINavigationController class]] == NO && self.navigationController != nil) {
- #pragma clang diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated"
- [self.navigationController setContentSizeForViewInPopover:aSize];
- #pragma clang diagnostic pop
- }
- }
- - (void)sizzled_setPreferredContentSize:(CGSize)aSize {
- [self sizzled_setPreferredContentSize:aSize];
- if ([self isKindOfClass:[UINavigationController class]] == NO && self.navigationController != nil)
- {
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([self.navigationController wy_isEmbedInPopover] == NO) {
- return;
- } else if ([self respondsToSelector:@selector(setPreferredContentSize:)]) {
- [self.navigationController setPreferredContentSize:aSize];
- }
- #endif
- }
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface WYPopoverArea : NSObject
- @property (nonatomic, assign) WYPopoverArrowDirection arrowDirection;
- @property (nonatomic, assign) CGSize areaSize;
- @property (nonatomic, assign, readonly) float value;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverArea
- @implementation WYPopoverArea
- - (NSString*)description {
- const NSDictionary *directionMap = @{@(WYPopoverArrowDirectionUp) : @"UP",
- @(WYPopoverArrowDirectionDown) : @"DOWN",
- @(WYPopoverArrowDirectionLeft) : @"LEFT",
- @(WYPopoverArrowDirectionRight) : @"RIGHT",
- @(WYPopoverArrowDirectionNone) : @"NONE"};
- NSString *direction = directionMap[@(_arrowDirection)];
- return [NSString stringWithFormat:@"%@ [ %f x %f ]", direction, _areaSize.width, _areaSize.height];
- }
- - (float)value {
- float result = 0;
- if (_areaSize.width > 0 && _areaSize.height > 0) {
- float w1 = ceilf(_areaSize.width / 10.0);
- float h1 = ceilf(_areaSize.height / 10.0);
- result = (w1 * h1);
- }
- return result;
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface WYPopoverTheme ()
- - (NSArray *)observableKeypaths;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @implementation WYPopoverTheme
- + (id)theme {
- WYPopoverTheme *result = nil;
- if (WY_IS_IOS_LESS_THAN(@"7.0")) {
- result = [WYPopoverTheme themeForIOS6];
- } else {
- result = [WYPopoverTheme themeForIOS7];
- }
- return result;
- }
- + (id)themeForIOS6 {
- WYPopoverTheme *result = [[WYPopoverTheme alloc] init];
- result.usesRoundedArrow = NO;
- result.dimsBackgroundViewsTintColor = YES;
- result.tintColor = [UIColor colorWithRed:55./255. green:63./255. blue:71./255. alpha:1.0];
- result.outerStrokeColor = nil;
- result.innerStrokeColor = nil;
- result.fillTopColor = result.tintColor;
- result.fillBottomColor = [result.tintColor wy_colorByDarken:0.4];
- result.glossShadowColor = nil;
- result.glossShadowOffset = CGSizeMake(0, 1.5);
- result.glossShadowBlurRadius = 0;
- result.borderWidth = 6;
- result.arrowBase = 42;
- result.arrowHeight = 18;
- result.outerShadowColor = [UIColor colorWithWhite:0 alpha:0.75];
- result.outerShadowBlurRadius = 8;
- result.outerShadowOffset = CGSizeMake(0, 2);
- result.outerCornerRadius = 8;
- result.minOuterCornerRadius = 0;
- result.innerShadowColor = [UIColor colorWithWhite:0 alpha:0.75];
- result.innerShadowBlurRadius = 2;
- result.innerShadowOffset = CGSizeMake(0, 1);
- result.innerCornerRadius = 6;
- result.viewContentInsets = UIEdgeInsetsMake(3, 0, 0, 0);
- result.overlayColor = [UIColor clearColor];
- result.preferredAlpha = 1.0f;
- return result;
- }
- + (id)themeForIOS7 {
- WYPopoverTheme *result = [[WYPopoverTheme alloc] init];
- result.usesRoundedArrow = YES;
- result.dimsBackgroundViewsTintColor = YES;
- result.tintColor = [UIColor colorWithRed:244./255. green:244./255. blue:244./255. alpha:1.0];
- result.outerStrokeColor = [UIColor clearColor];
- result.innerStrokeColor = [UIColor clearColor];
- result.fillTopColor = nil;
- result.fillBottomColor = nil;
- result.glossShadowColor = nil;
- result.glossShadowOffset = CGSizeZero;
- result.glossShadowBlurRadius = 0;
- result.borderWidth = 0;
- result.arrowBase = 25;
- result.arrowHeight = 13;
- result.outerShadowColor = [UIColor clearColor];
- result.outerShadowBlurRadius = 0;
- result.outerShadowOffset = CGSizeZero;
- result.outerCornerRadius = 5;
- result.minOuterCornerRadius = 0;
- result.innerShadowColor = [UIColor clearColor];
- result.innerShadowBlurRadius = 0;
- result.innerShadowOffset = CGSizeZero;
- result.innerCornerRadius = 0;
- result.viewContentInsets = UIEdgeInsetsZero;
- result.overlayColor = [UIColor colorWithWhite:0 alpha:0.15];
- result.preferredAlpha = 1.0f;
- return result;
- }
- - (NSUInteger)innerCornerRadius {
- float result = _innerCornerRadius;
- if (_borderWidth == 0) {
- result = 0;
- if (_outerCornerRadius > 0) {
- result = _outerCornerRadius;
- }
- }
- return result;
- }
- - (CGSize)outerShadowOffset {
- CGSize result = _outerShadowOffset;
- result.width = MIN(result.width, _outerShadowBlurRadius);
- result.height = MIN(result.height, _outerShadowBlurRadius);
- return result;
- }
- - (UIColor *)innerStrokeColor {
- return _innerStrokeColor?: [self.fillTopColor wy_colorByDarken:0.6];
- }
- - (UIColor *)outerStrokeColor {
- return _outerStrokeColor?: [self.fillTopColor wy_colorByDarken:0.6];
- }
- - (UIColor *)glossShadowColor {
- return _glossShadowColor?: [self.fillTopColor wy_colorByLighten:0.2];
- }
- - (UIColor *)fillTopColor {
- return _fillTopColor?: _tintColor;
- }
- - (UIColor *)fillBottomColor {
- return _fillBottomColor?: self.fillTopColor;
- }
- - (NSArray *)observableKeypaths {
- return [NSArray arrayWithObjects:@"tintColor", @"outerStrokeColor", @"innerStrokeColor", @"fillTopColor", @"fillBottomColor", @"glossShadowColor", @"glossShadowOffset", @"glossShadowBlurRadius", @"borderWidth", @"arrowBase", @"arrowHeight", @"outerShadowColor", @"outerShadowBlurRadius", @"outerShadowOffset", @"outerCornerRadius", @"innerShadowColor", @"innerShadowBlurRadius", @"innerShadowOffset", @"innerCornerRadius", @"viewContentInsets", @"overlayColor", nil];
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface UIImage (WYPopover)
- + (UIImage *)wy_imageWithColor:(UIColor *)color;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - UIImage (WYPopover)
- @implementation UIImage (WYPopover)
- static float edgeSizeFromCornerRadius(float cornerRadius) {
- return cornerRadius * 2 + 1;
- }
- + (UIImage *)wy_imageWithColor:(UIColor *)color {
- return [self imageWithColor:color size:CGSizeMake(8, 8) cornerRadius:0];
- }
- + (UIImage *)imageWithColor:(UIColor *)color
- cornerRadius:(float)cornerRadius {
- float min = edgeSizeFromCornerRadius(cornerRadius);
- CGSize minSize = CGSizeMake(min, min);
- return [self imageWithColor:color size:minSize cornerRadius:cornerRadius];
- }
- + (UIImage *)imageWithColor:(UIColor *)color
- size:(CGSize)aSize
- cornerRadius:(float)cornerRadius {
- CGRect rect = CGRectMake(0, 0, aSize.width, aSize.height);
- UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius];
- roundedRect.lineWidth = 0;
- UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0f);
- [color setFill];
- [roundedRect fill];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return [image resizableImageWithCapInsets:UIEdgeInsetsMake(cornerRadius, cornerRadius, cornerRadius, cornerRadius)];
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface WYPopoverBackgroundInnerView : UIView
- @property (nonatomic, strong) UIColor *innerStrokeColor;
- @property (nonatomic, strong) UIColor *gradientTopColor;
- @property (nonatomic, strong) UIColor *gradientBottomColor;
- @property (nonatomic, assign) float gradientHeight;
- @property (nonatomic, assign) float gradientTopPosition;
- @property (nonatomic, strong) UIColor *innerShadowColor;
- @property (nonatomic, assign) CGSize innerShadowOffset;
- @property (nonatomic, assign) float innerShadowBlurRadius;
- @property (nonatomic, assign) float innerCornerRadius;
- @property (nonatomic, assign) float navigationBarHeight;
- @property (nonatomic, assign) BOOL wantsDefaultContentAppearance;
- @property (nonatomic, assign) float borderWidth;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverInnerView
- @implementation WYPopoverBackgroundInnerView
- - (id)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- self.backgroundColor = [UIColor clearColor];
- self.userInteractionEnabled = NO;
- }
- return self;
- }
- - (void)drawRect:(CGRect)rect {
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGContextRef context = UIGraphicsGetCurrentContext();
- //// Gradient Declarations
- NSArray* fillGradientColors = [NSArray arrayWithObjects:
- (id)_gradientTopColor.CGColor,
- (id)_gradientBottomColor.CGColor, nil];
- CGFloat fillGradientLocations[2] = { 0, 1 };
- CGGradientRef fillGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)fillGradientColors, fillGradientLocations);
- //// innerRect Drawing
- float barHeight = (_wantsDefaultContentAppearance == NO) ? _navigationBarHeight : 0;
- float cornerRadius = (_wantsDefaultContentAppearance == NO) ? _innerCornerRadius : 0;
- CGRect innerRect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect) + barHeight, CGRectGetWidth(rect) , CGRectGetHeight(rect) - barHeight);
- UIBezierPath* rectPath = [UIBezierPath bezierPathWithRect:innerRect];
- UIBezierPath* roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:innerRect cornerRadius:cornerRadius + 1];
- if (_wantsDefaultContentAppearance == NO && _borderWidth > 0) {
- CGContextSaveGState(context);
- {
- [rectPath appendPath:roundedRectPath];
- rectPath.usesEvenOddFillRule = YES;
- [rectPath addClip];
- CGContextDrawLinearGradient(context, fillGradient,
- CGPointMake(0, -_gradientTopPosition),
- CGPointMake(0, -_gradientTopPosition + _gradientHeight),
- 0);
- }
- CGContextRestoreGState(context);
- }
- CGContextSaveGState(context);
- {
- if (_wantsDefaultContentAppearance == NO && _borderWidth > 0) {
- [roundedRectPath addClip];
- CGContextSetShadowWithColor(context, _innerShadowOffset, _innerShadowBlurRadius, _innerShadowColor.CGColor);
- }
- UIBezierPath* inRoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(innerRect, 0.5, 0.5) cornerRadius:cornerRadius];
- if (_borderWidth == 0) {
- inRoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(innerRect, 0.5, 0.5) byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
- }
- [self.innerStrokeColor setStroke];
- inRoundedRectPath.lineWidth = 1;
- [inRoundedRectPath stroke];
- }
- CGContextRestoreGState(context);
- CGGradientRelease(fillGradient);
- CGColorSpaceRelease(colorSpace);
- }
- - (void)dealloc
- {
- _innerShadowColor = nil;
- _innerStrokeColor = nil;
- _gradientTopColor = nil;
- _gradientBottomColor = nil;
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @protocol WYPopoverOverlayViewDelegate;
- @interface WYPopoverOverlayView : UIView {
- BOOL _testHits;
- }
- @property(nonatomic, assign) id <WYPopoverOverlayViewDelegate> delegate;
- @property(nonatomic, unsafe_unretained) NSArray *passthroughViews;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverOverlayViewDelegate
- @protocol WYPopoverOverlayViewDelegate <NSObject>
- @optional
- - (BOOL)dismissOnPassthroughViewTap;
- - (void)popoverOverlayViewDidTouch:(WYPopoverOverlayView *)overlayView;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverOverlayView
- @implementation WYPopoverOverlayView
- - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
- if (_testHits) {
- return nil;
- }
- UIView *view = [super hitTest:point withEvent:event];
- if (view == self) {
- _testHits = YES;
- UIView *superHitView = [self.superview hitTest:point withEvent:event];
- _testHits = NO;
- if ([self isPassthroughView:superHitView]) {
- if ([self.delegate dismissOnPassthroughViewTap]) {
- dispatch_async(dispatch_get_main_queue(), ^ {
- if ([self.delegate respondsToSelector:@selector(popoverOverlayViewDidTouch:)]) {
- [self.delegate popoverOverlayViewDidTouch:self];
- }
- });
- }
- return superHitView;
- }
- }
- return view;
- }
- - (BOOL)isPassthroughView:(UIView *)view {
- if (view == nil) {
- return NO;
- }
- if ([self.passthroughViews containsObject:view]) {
- return YES;
- }
- return [self isPassthroughView:view.superview];
- }
- /**
- * @note This empty method is meaningful.
- * If the method is not defined, touch event isn't capture in iOS6.
- */
- - (void)drawRect:(CGRect)rect {}
- #pragma mark - UIAccessibility
- - (void)accessibilityElementDidBecomeFocused {
- self.accessibilityLabel = NSLocalizedString(@"Double-tap to dismiss pop-up window.", nil);
- }
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverBackgroundViewDelegate
- @protocol WYPopoverBackgroundViewDelegate <NSObject>
- @optional
- - (void)popoverBackgroundViewDidTouchOutside:(WYPopoverBackgroundView *)backgroundView;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- @interface WYPopoverBackgroundView () {
- WYPopoverBackgroundInnerView *_innerView;
- CGSize _contentSize;
- }
- @property(nonatomic, assign) id <WYPopoverBackgroundViewDelegate> delegate;
- @property (nonatomic, assign) WYPopoverArrowDirection arrowDirection;
- @property (nonatomic, strong, readonly) UIView *contentView;
- @property (nonatomic, assign, readonly) float navigationBarHeight;
- @property (nonatomic, assign, readonly) UIEdgeInsets outerShadowInsets;
- @property (nonatomic, assign) float arrowOffset;
- @property (nonatomic, assign) BOOL wantsDefaultContentAppearance;
- @property (nonatomic, assign, getter = isAppearing) BOOL appearing;
- - (void)tapOut;
- - (void)setViewController:(UIViewController *)viewController;
- - (CGRect)outerRect;
- - (CGRect)innerRect;
- - (CGRect)arrowRect;
- - (CGRect)outerRect:(CGRect)rect arrowDirection:(WYPopoverArrowDirection)aArrowDirection;
- - (CGRect)innerRect:(CGRect)rect arrowDirection:(WYPopoverArrowDirection)aArrowDirection;
- - (CGRect)arrowRect:(CGRect)rect arrowDirection:(WYPopoverArrowDirection)aArrowDirection;
- - (id)initWithContentSize:(CGSize)contentSize;
- @end
- ////////////////////////////////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverBackgroundView
- @implementation WYPopoverBackgroundView
- - (id)initWithContentSize:(CGSize)aContentSize {
- self = [super initWithFrame:CGRectMake(0, 0, aContentSize.width, aContentSize.height)];
- if (self != nil) {
- _contentSize = aContentSize;
- self.autoresizesSubviews = NO;
- self.backgroundColor = [UIColor clearColor];
- self.arrowDirection = WYPopoverArrowDirectionDown;
- self.arrowOffset = 0;
- self.layer.name = @"parent";
- if (WY_IS_IOS_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
- self.layer.drawsAsynchronously = YES;
- }
- self.layer.contentsScale = [UIScreen mainScreen].scale;
- //self.layer.edgeAntialiasingMask = kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge;
- self.layer.delegate = self;
- }
- return self;
- }
- - (void)tapOut {
- [self.delegate popoverBackgroundViewDidTouchOutside:self];
- }
- - (UIEdgeInsets)outerShadowInsets {
- UIEdgeInsets result = UIEdgeInsetsMake(_outerShadowBlurRadius, _outerShadowBlurRadius, _outerShadowBlurRadius, _outerShadowBlurRadius);
- result.top -= self.outerShadowOffset.height;
- result.bottom += self.outerShadowOffset.height;
- result.left -= self.outerShadowOffset.width;
- result.right += self.outerShadowOffset.width;
- return result;
- }
- - (void)setArrowOffset:(float)value {
- float coef = 1;
- if (value != 0) {
- coef = value / ABS(value);
- value = ABS(value);
- CGRect outerRect = [self outerRect];
- float delta = self.arrowBase / 2. + .5;
- delta += MIN(_minOuterCornerRadius, _outerCornerRadius);
- outerRect = CGRectInset(outerRect, delta, delta);
- if (_arrowDirection == WYPopoverArrowDirectionUp || _arrowDirection == WYPopoverArrowDirectionDown) {
- value += coef * self.outerShadowOffset.width;
- value = MIN(value, CGRectGetWidth(outerRect) / 2);
- }
- if (_arrowDirection == WYPopoverArrowDirectionLeft || _arrowDirection == WYPopoverArrowDirectionRight) {
- value += coef * self.outerShadowOffset.height;
- value = MIN(value, CGRectGetHeight(outerRect) / 2);
- }
- } else {
- if (_arrowDirection == WYPopoverArrowDirectionUp || _arrowDirection == WYPopoverArrowDirectionDown) {
- value += self.outerShadowOffset.width;
- }
- if (_arrowDirection == WYPopoverArrowDirectionLeft || _arrowDirection == WYPopoverArrowDirectionRight) {
- value += self.outerShadowOffset.height;
- }
- }
- _arrowOffset = value * coef;
- }
- - (void)setViewController:(UIViewController *)viewController {
- _contentView = viewController.view;
- _contentView.frame = CGRectIntegral(CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));
- [self addSubview:_contentView];
- _navigationBarHeight = 0;
- if ([viewController isKindOfClass:[UINavigationController class]]) {
- UINavigationController* navigationController = (UINavigationController*)viewController;
- _navigationBarHeight = navigationController.navigationBarHidden? 0 : navigationController.navigationBar.bounds.size.height;
- }
- _contentView.frame = CGRectIntegral([self innerRect]);
- if (_innerView == nil) {
- _innerView = [[WYPopoverBackgroundInnerView alloc] initWithFrame:_contentView.frame];
- _innerView.userInteractionEnabled = NO;
- _innerView.gradientTopColor = self.fillTopColor;
- _innerView.gradientBottomColor = self.fillBottomColor;
- _innerView.innerShadowColor = _innerShadowColor;
- _innerView.innerStrokeColor = self.innerStrokeColor;
- _innerView.innerShadowOffset = _innerShadowOffset;
- _innerView.innerCornerRadius = self.innerCornerRadius;
- _innerView.innerShadowBlurRadius = _innerShadowBlurRadius;
- _innerView.borderWidth = self.borderWidth;
- }
- _innerView.navigationBarHeight = _navigationBarHeight;
- _innerView.gradientHeight = self.frame.size.height - 2 * _outerShadowBlurRadius;
- _innerView.gradientTopPosition = _contentView.frame.origin.y - self.outerShadowInsets.top;
- _innerView.wantsDefaultContentAppearance = _wantsDefaultContentAppearance;
- [self insertSubview:_innerView aboveSubview:_contentView];
- _innerView.frame = CGRectIntegral(_contentView.frame);
- [self.layer setNeedsDisplay];
- }
- - (CGSize)sizeThatFits:(CGSize)size {
- CGSize result = size;
- result.width += 2 * (_borderWidth + _outerShadowBlurRadius);
- result.height += _borderWidth + 2 * _outerShadowBlurRadius;
- if (_navigationBarHeight == 0) {
- result.height += _borderWidth;
- }
- if (_arrowDirection == WYPopoverArrowDirectionUp || _arrowDirection == WYPopoverArrowDirectionDown) {
- result.height += _arrowHeight;
- }
- if (_arrowDirection == WYPopoverArrowDirectionLeft || _arrowDirection == WYPopoverArrowDirectionRight) {
- result.width += _arrowHeight;
- }
- return result;
- }
- - (void)sizeToFit {
- CGSize size = [self sizeThatFits:_contentSize];
- self.bounds = CGRectMake(0, 0, size.width, size.height);
- }
- #pragma mark Drawing
- - (void)setNeedsDisplay {
- [super setNeedsDisplay];
- [self.layer setNeedsDisplay];
-
- self.alpha = self.preferredAlpha;
-
- if (_innerView) {
- _innerView.gradientTopColor = self.fillTopColor;
- _innerView.gradientBottomColor = self.fillBottomColor;
- _innerView.innerShadowColor = _innerShadowColor;
- _innerView.innerStrokeColor = self.innerStrokeColor;
- _innerView.innerShadowOffset = _innerShadowOffset;
- _innerView.innerCornerRadius = self.innerCornerRadius;
- _innerView.innerShadowBlurRadius = _innerShadowBlurRadius;
- _innerView.borderWidth = self.borderWidth;
- _innerView.navigationBarHeight = _navigationBarHeight;
- _innerView.gradientHeight = self.frame.size.height - 2 * _outerShadowBlurRadius;
- _innerView.gradientTopPosition = _contentView.frame.origin.y - self.outerShadowInsets.top;
- _innerView.wantsDefaultContentAppearance = _wantsDefaultContentAppearance;
- [_innerView setNeedsDisplay];
- }
- }
- #pragma mark CALayerDelegate
- - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context {
- if ([layer.name isEqualToString:@"parent"]) {
- UIGraphicsPushContext(context);
- //CGContextSetShouldAntialias(context, YES);
- //CGContextSetAllowsAntialiasing(context, YES);
- //// General Declarations
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- //// Gradient Declarations
- NSArray* fillGradientColors = [NSArray arrayWithObjects:
- (id)self.fillTopColor.CGColor,
- (id)self.fillBottomColor.CGColor, nil];
- CGFloat fillGradientLocations[2] = {0, 1};
- CGGradientRef fillGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)fillGradientColors, fillGradientLocations);
- // Frames
- CGRect rect = self.bounds;
- CGRect outerRect = [self outerRect:rect arrowDirection:self.arrowDirection];
- CGRect insetRect = CGRectInset(outerRect, 0.5, 0.5);
- if (!CGRectIsEmpty(insetRect) && !CGRectIsInfinite(insetRect)) {
- outerRect = insetRect;
- }
- // Inner Path
- CGMutablePathRef outerPathRef = CGPathCreateMutable();
- CGPoint arrowTipPoint = CGPointZero;
- CGPoint arrowBasePointA = CGPointZero;
- CGPoint arrowBasePointB = CGPointZero;
- float reducedOuterCornerRadius = 0;
- if (_arrowDirection == WYPopoverArrowDirectionUp || _arrowDirection == WYPopoverArrowDirectionDown) {
- if (_arrowOffset >= 0) {
- reducedOuterCornerRadius = CGRectGetMaxX(outerRect) - (CGRectGetMidX(outerRect) + _arrowOffset + _arrowBase / 2);
- } else {
- reducedOuterCornerRadius = (CGRectGetMidX(outerRect) + _arrowOffset - _arrowBase / 2) - CGRectGetMinX(outerRect);
- }
- } else if (_arrowDirection == WYPopoverArrowDirectionLeft || _arrowDirection == WYPopoverArrowDirectionRight) {
- if (_arrowOffset >= 0) {
- reducedOuterCornerRadius = CGRectGetMaxY(outerRect) - (CGRectGetMidY(outerRect) + _arrowOffset + _arrowBase / 2);
- } else {
- reducedOuterCornerRadius = (CGRectGetMidY(outerRect) + _arrowOffset - _arrowBase / 2) - CGRectGetMinY(outerRect);
- }
- }
- reducedOuterCornerRadius = MIN(reducedOuterCornerRadius, _outerCornerRadius);
- CGFloat roundedArrowControlLength = _arrowBase / 5.0f;
- if (_arrowDirection == WYPopoverArrowDirectionUp) {
- arrowTipPoint = CGPointMake(CGRectGetMidX(outerRect) + _arrowOffset,
- CGRectGetMinY(outerRect) - _arrowHeight);
- arrowBasePointA = CGPointMake(arrowTipPoint.x - _arrowBase / 2,
- arrowTipPoint.y + _arrowHeight);
- arrowBasePointB = CGPointMake(arrowTipPoint.x + _arrowBase / 2,
- arrowTipPoint.y + _arrowHeight);
- CGPathMoveToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- if (self.usesRoundedArrow) {
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowBasePointA.x + roundedArrowControlLength, arrowBasePointA.y,
- arrowTipPoint.x - (roundedArrowControlLength * 0.75f), arrowTipPoint.y,
- arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowTipPoint.x + (roundedArrowControlLength * 0.75f), arrowTipPoint.y,
- arrowBasePointB.x - roundedArrowControlLength, arrowBasePointB.y,
- arrowBasePointB.x, arrowBasePointB.y);
- } else {
- CGPathAddLineToPoint(outerPathRef, NULL, arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointB.x, arrowBasePointB.y);
- }
- CGPathAddArcToPoint(outerPathRef, NULL, CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- (_arrowOffset >= 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL, CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL, CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL, CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- (_arrowOffset < 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- } else if (_arrowDirection == WYPopoverArrowDirectionDown) {
- arrowTipPoint = CGPointMake(CGRectGetMidX(outerRect) + _arrowOffset,
- CGRectGetMaxY(outerRect) + _arrowHeight);
- arrowBasePointA = CGPointMake(arrowTipPoint.x + _arrowBase / 2,
- arrowTipPoint.y - _arrowHeight);
- arrowBasePointB = CGPointMake(arrowTipPoint.x - _arrowBase / 2,
- arrowTipPoint.y - _arrowHeight);
- CGPathMoveToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- if (self.usesRoundedArrow) {
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowBasePointA.x - roundedArrowControlLength, arrowBasePointA.y,
- arrowTipPoint.x + (roundedArrowControlLength * 0.75f), arrowTipPoint.y,
- arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowTipPoint.x - (roundedArrowControlLength * 0.75f), arrowTipPoint.y,
- arrowBasePointB.x + roundedArrowControlLength, arrowBasePointA.y,
- arrowBasePointB.x, arrowBasePointB.y);
- } else {
- CGPathAddLineToPoint(outerPathRef, NULL, arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointB.x, arrowBasePointB.y);
- }
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- (_arrowOffset < 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- (_arrowOffset >= 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- } else if (_arrowDirection == WYPopoverArrowDirectionLeft) {
- arrowTipPoint = CGPointMake(CGRectGetMinX(outerRect) - _arrowHeight,
- CGRectGetMidY(outerRect) + _arrowOffset);
- arrowBasePointA = CGPointMake(arrowTipPoint.x + _arrowHeight,
- arrowTipPoint.y + _arrowBase / 2);
- arrowBasePointB = CGPointMake(arrowTipPoint.x + _arrowHeight,
- arrowTipPoint.y - _arrowBase / 2);
- CGPathMoveToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- if (self.usesRoundedArrow) {
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowBasePointA.x, arrowBasePointA.y - roundedArrowControlLength,
- arrowTipPoint.x, arrowTipPoint.y + (roundedArrowControlLength * 0.75f),
- arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowTipPoint.x, arrowTipPoint.y - (roundedArrowControlLength * 0.75f),
- arrowBasePointB.x, arrowBasePointB.y + roundedArrowControlLength,
- arrowBasePointB.x, arrowBasePointB.y);
- } else {
- CGPathAddLineToPoint(outerPathRef, NULL, arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointB.x, arrowBasePointB.y);
- }
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- (_arrowOffset < 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- (_arrowOffset >= 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- } else if (_arrowDirection == WYPopoverArrowDirectionRight) {
- arrowTipPoint = CGPointMake(CGRectGetMaxX(outerRect) + _arrowHeight,
- CGRectGetMidY(outerRect) + _arrowOffset);
- arrowBasePointA = CGPointMake(arrowTipPoint.x - _arrowHeight,
- arrowTipPoint.y - _arrowBase / 2);
- arrowBasePointB = CGPointMake(arrowTipPoint.x - _arrowHeight,
- arrowTipPoint.y + _arrowBase / 2);
- CGPathMoveToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- if (self.usesRoundedArrow) {
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowBasePointA.x, arrowBasePointA.y + roundedArrowControlLength,
- arrowTipPoint.x, arrowTipPoint.y - (roundedArrowControlLength * 0.75f),
- arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddCurveToPoint(outerPathRef, NULL,
- arrowTipPoint.x, arrowTipPoint.y + (roundedArrowControlLength * 0.75f),
- arrowBasePointB.x, arrowBasePointB.y - roundedArrowControlLength,
- arrowBasePointB.x, arrowBasePointB.y);
- } else {
- CGPathAddLineToPoint(outerPathRef, NULL, arrowTipPoint.x, arrowTipPoint.y);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointB.x, arrowBasePointB.y);
- }
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- (_arrowOffset >= 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- (_arrowOffset < 0) ? reducedOuterCornerRadius : _outerCornerRadius);
- CGPathAddLineToPoint(outerPathRef, NULL, arrowBasePointA.x, arrowBasePointA.y);
- } else if (_arrowDirection == WYPopoverArrowDirectionNone) {
- CGPoint origin = CGPointMake(CGRectGetMaxX(outerRect), CGRectGetMidY(outerRect));
- CGPathMoveToPoint(outerPathRef, NULL, origin.x, origin.y);
- CGPathAddLineToPoint(outerPathRef, NULL, CGRectGetMaxX(outerRect), CGRectGetMidY(outerRect));
- CGPathAddLineToPoint(outerPathRef, NULL, CGRectGetMaxX(outerRect), CGRectGetMidY(outerRect));
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMaxY(outerRect),
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMinX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- _outerCornerRadius);
- CGPathAddArcToPoint(outerPathRef, NULL,
- CGRectGetMaxX(outerRect), CGRectGetMinY(outerRect),
- CGRectGetMaxX(outerRect), CGRectGetMaxY(outerRect),
- _outerCornerRadius);
- CGPathAddLineToPoint(outerPathRef, NULL, origin.x, origin.y);
- }
- CGPathCloseSubpath(outerPathRef);
- UIBezierPath* outerRectPath = [UIBezierPath bezierPathWithCGPath:outerPathRef];
- CGContextSaveGState(context);
- {
- CGContextSetShadowWithColor(context, self.outerShadowOffset, _outerShadowBlurRadius, _outerShadowColor.CGColor);
- CGContextBeginTransparencyLayer(context, NULL);
- [outerRectPath addClip];
- CGRect outerRectBounds = CGPathGetPathBoundingBox(outerRectPath.CGPath);
- CGContextDrawLinearGradient(context, fillGradient,
- CGPointMake(CGRectGetMidX(outerRectBounds), CGRectGetMinY(outerRectBounds)),
- CGPointMake(CGRectGetMidX(outerRectBounds), CGRectGetMaxY(outerRectBounds)),
- 0);
- CGContextEndTransparencyLayer(context);
- }
- CGContextRestoreGState(context);
- ////// outerRect Inner Shadow
- CGRect outerRectBorderRect = CGRectInset([outerRectPath bounds], -_glossShadowBlurRadius, -_glossShadowBlurRadius);
- outerRectBorderRect = CGRectOffset(outerRectBorderRect, -_glossShadowOffset.width, -_glossShadowOffset.height);
- outerRectBorderRect = CGRectInset(CGRectUnion(outerRectBorderRect, [outerRectPath bounds]), -1, -1);
- UIBezierPath* outerRectNegativePath = [UIBezierPath bezierPathWithRect: outerRectBorderRect];
- [outerRectNegativePath appendPath: outerRectPath];
- outerRectNegativePath.usesEvenOddFillRule = YES;
- CGContextSaveGState(context);
- {
- float xOffset = _glossShadowOffset.width + round(outerRectBorderRect.size.width);
- float yOffset = _glossShadowOffset.height;
- CGContextSetShadowWithColor(context,
- CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),
- _glossShadowBlurRadius,
- self.glossShadowColor.CGColor);
- [outerRectPath addClip];
- CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(outerRectBorderRect.size.width), 0);
- [outerRectNegativePath applyTransform: transform];
- [[UIColor grayColor] setFill];
- [outerRectNegativePath fill];
- }
- CGContextRestoreGState(context);
- [self.outerStrokeColor setStroke];
- outerRectPath.lineWidth = 1;
- [outerRectPath stroke];
- //// Cleanup
- CFRelease(outerPathRef);
- CGGradientRelease(fillGradient);
- CGColorSpaceRelease(colorSpace);
- UIGraphicsPopContext();
- }
- }
- #pragma mark Private
- - (CGRect)outerRect {
- return [self outerRect:self.bounds arrowDirection:self.arrowDirection];
- }
- - (CGRect)innerRect {
- return [self innerRect:self.bounds arrowDirection:self.arrowDirection];
- }
- - (CGRect)arrowRect {
- return [self arrowRect:self.bounds arrowDirection:self.arrowDirection];
- }
- - (CGRect)outerRect:(CGRect)rect arrowDirection:(WYPopoverArrowDirection)aArrowDirection{
- CGRect result = rect;
- if (aArrowDirection == WYPopoverArrowDirectionUp || _arrowDirection == WYPopoverArrowDirectionDown) {
- result.size.height -= _arrowHeight;
- if (aArrowDirection == WYPopoverArrowDirectionUp) {
- result = CGRectOffset(result, 0, _arrowHeight);
- }
- }
- if (aArrowDirection == WYPopoverArrowDirectionLeft || _arrowDirection == WYPopoverArrowDirectionRight) {
- result.size.width -= _arrowHeight;
- if (aArrowDirection == WYPopoverArrowDirectionLeft) {
- result = CGRectOffset(result, _arrowHeight, 0);
- }
- }
- result = CGRectInset(result, _outerShadowBlurRadius, _outerShadowBlurRadius);
- result.origin.x -= self.outerShadowOffset.width;
- result.origin.y -= self.outerShadowOffset.height;
- return result;
- }
- - (CGRect)innerRect:(CGRect)rect arrowDirection:(WYPopoverArrowDirection)aArrowDirection {
- CGRect result = [self outerRect:rect arrowDirection:aArrowDirection];
- result.origin.x += _borderWidth;
- result.origin.y += 0;
- result.size.width -= 2 * _borderWidth;
- result.size.height -= _borderWidth;
- if (_navigationBarHeight == 0 || _wantsDefaultContentAppearance) {
- result.origin.y += _borderWidth;
- result.size.height -= _borderWidth;
- }
- result.origin.x += _viewContentInsets.left;
- result.origin.y += _viewContentInsets.top;
- result.size.width = result.size.width - _viewContentInsets.left - _viewContentInsets.right;
- result.size.height = result.size.height - _viewContentInsets.top - _viewContentInsets.bottom;
- if (_borderWidth > 0) {
- result = CGRectInset(result, -1, -1);
- }
- return result;
- }
- - (CGRect)arrowRect:(CGRect)rect arrowDirection:(WYPopoverArrowDirection)aArrowDirection {
- CGRect result = CGRectZero;
- if (_arrowHeight > 0) {
- result.size = CGSizeMake(_arrowBase, _arrowHeight);
- if (aArrowDirection == WYPopoverArrowDirectionLeft || _arrowDirection == WYPopoverArrowDirectionRight) {
- result.size = CGSizeMake(_arrowHeight, _arrowBase);
- }
- CGRect outerRect = [self outerRect:rect arrowDirection:aArrowDirection];
- if (aArrowDirection == WYPopoverArrowDirectionDown) {
- result.origin.x = CGRectGetMidX(outerRect) - result.size.width / 2 + _arrowOffset;
- result.origin.y = CGRectGetMaxY(outerRect);
- }
- if (aArrowDirection == WYPopoverArrowDirectionUp) {
- result.origin.x = CGRectGetMidX(outerRect) - result.size.width / 2 + _arrowOffset;
- result.origin.y = CGRectGetMinY(outerRect) - result.size.height;
- }
- if (aArrowDirection == WYPopoverArrowDirectionRight) {
- result.origin.x = CGRectGetMaxX(outerRect);
- result.origin.y = CGRectGetMidY(outerRect) - result.size.height / 2 + _arrowOffset;
- }
- if (aArrowDirection == WYPopoverArrowDirectionLeft) {
- result.origin.x = CGRectGetMinX(outerRect) - result.size.width;
- result.origin.y = CGRectGetMidY(outerRect) - result.size.height / 2 + _arrowOffset;
- }
- }
- return result;
- }
- #pragma mark Memory Management
- - (void)dealloc {
- _contentView = nil;
- _innerView = nil;
- _tintColor = nil;
- _outerStrokeColor = nil;
- _innerStrokeColor = nil;
- _fillTopColor = nil;
- _fillBottomColor = nil;
- _glossShadowColor = nil;
- _outerShadowColor = nil;
- _innerShadowColor = nil;
- }
- @end
- ////////////////////////////////////////////////////////////////////////////
- @interface WYPopoverController () <WYPopoverOverlayViewDelegate, WYPopoverBackgroundViewDelegate> {
- UIViewController *_viewController;
- CGRect _rect;
- UIView *_inView;
- WYPopoverOverlayView *_overlayView;
- WYPopoverBackgroundView *_backgroundView;
- WYPopoverArrowDirection _permittedArrowDirections;
- BOOL _animated;
- BOOL _isListeningNotifications;
- BOOL _isObserverAdded;
- BOOL _isInterfaceOrientationChanging;
- BOOL _ignoreOrientation;
- __weak UIBarButtonItem *_barButtonItem;
- WYPopoverAnimationOptions options;
- BOOL themeUpdatesEnabled;
- BOOL themeIsUpdating;
- }
- - (void)dismissPopoverAnimated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aAptions
- completion:(void (^)(void))aCompletion
- callDelegate:(BOOL)aCallDelegate;
- - (WYPopoverArrowDirection)arrowDirectionForRect:(CGRect)aRect
- inView:(UIView*)aView
- contentSize:(CGSize)aContentSize
- arrowHeight:(float)aArrowHeight
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections;
- - (CGSize)sizeForRect:(CGRect)aRect
- inView:(UIView *)aView
- arrowHeight:(float)aArrowHeight
- arrowDirection:(WYPopoverArrowDirection)aArrowDirection;
- - (void)registerTheme;
- - (void)unregisterTheme;
- - (void)updateThemeUI;
- - (CGSize)topViewControllerContentSize;
- @end
- ////////////////////////////////////////////////////////////////////////////
- #pragma mark - WYPopoverController
- @implementation WYPopoverController
- static WYPopoverTheme *defaultTheme_ = nil;
- @synthesize popoverContentSize = popoverContentSize_;
- + (void)setDefaultTheme:(WYPopoverTheme *)aTheme {
- defaultTheme_ = aTheme;
- @autoreleasepool {
- WYPopoverBackgroundView *appearance = [WYPopoverBackgroundView appearance];
- appearance.usesRoundedArrow = aTheme.usesRoundedArrow;
- appearance.dimsBackgroundViewsTintColor = aTheme.dimsBackgroundViewsTintColor;
- appearance.tintColor = aTheme.tintColor;
- appearance.outerStrokeColor = aTheme.outerStrokeColor;
- appearance.innerStrokeColor = aTheme.innerStrokeColor;
- appearance.fillTopColor = aTheme.fillTopColor;
- appearance.fillBottomColor = aTheme.fillBottomColor;
- appearance.glossShadowColor = aTheme.glossShadowColor;
- appearance.glossShadowOffset = aTheme.glossShadowOffset;
- appearance.glossShadowBlurRadius = aTheme.glossShadowBlurRadius;
- appearance.borderWidth = aTheme.borderWidth;
- appearance.arrowBase = aTheme.arrowBase;
- appearance.arrowHeight = aTheme.arrowHeight;
- appearance.outerShadowColor = aTheme.outerShadowColor;
- appearance.outerShadowBlurRadius = aTheme.outerShadowBlurRadius;
- appearance.outerShadowOffset = aTheme.outerShadowOffset;
- appearance.outerCornerRadius = aTheme.outerCornerRadius;
- appearance.minOuterCornerRadius = aTheme.minOuterCornerRadius;
- appearance.innerShadowColor = aTheme.innerShadowColor;
- appearance.innerShadowBlurRadius = aTheme.innerShadowBlurRadius;
- appearance.innerShadowOffset = aTheme.innerShadowOffset;
- appearance.innerCornerRadius = aTheme.innerCornerRadius;
- appearance.viewContentInsets = aTheme.viewContentInsets;
- appearance.overlayColor = aTheme.overlayColor;
- appearance.preferredAlpha = aTheme.preferredAlpha;
- }
- }
- + (WYPopoverTheme *)defaultTheme {
- return defaultTheme_;
- }
- + (void)load {
- [WYPopoverController setDefaultTheme:[WYPopoverTheme theme]];
- }
- - (id)init {
- self = [super init];
- if (self) {
- // ignore orientation in iOS8
- _ignoreOrientation = (compileUsingIOS8SDK() && [[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]);
- _popoverLayoutMargins = UIEdgeInsetsMake(10, 10, 10, 10);
- _animationDuration = WY_POPOVER_DEFAULT_ANIMATION_DURATION;
- themeUpdatesEnabled = NO;
- [self setTheme:[WYPopoverController defaultTheme]];
- themeIsUpdating = YES;
- WYPopoverBackgroundView *appearance = [WYPopoverBackgroundView appearance];
- _theme.usesRoundedArrow = appearance.usesRoundedArrow;
- _theme.dimsBackgroundViewsTintColor = appearance.dimsBackgroundViewsTintColor;
- _theme.tintColor = appearance.tintColor;
- _theme.outerStrokeColor = appearance.outerStrokeColor;
- _theme.innerStrokeColor = appearance.innerStrokeColor;
- _theme.fillTopColor = appearance.fillTopColor;
- _theme.fillBottomColor = appearance.fillBottomColor;
- _theme.glossShadowColor = appearance.glossShadowColor;
- _theme.glossShadowOffset = appearance.glossShadowOffset;
- _theme.glossShadowBlurRadius = appearance.glossShadowBlurRadius;
- _theme.borderWidth = appearance.borderWidth;
- _theme.arrowBase = appearance.arrowBase;
- _theme.arrowHeight = appearance.arrowHeight;
- _theme.outerShadowColor = appearance.outerShadowColor;
- _theme.outerShadowBlurRadius = appearance.outerShadowBlurRadius;
- _theme.outerShadowOffset = appearance.outerShadowOffset;
- _theme.outerCornerRadius = appearance.outerCornerRadius;
- _theme.minOuterCornerRadius = appearance.minOuterCornerRadius;
- _theme.innerShadowColor = appearance.innerShadowColor;
- _theme.innerShadowBlurRadius = appearance.innerShadowBlurRadius;
- _theme.innerShadowOffset = appearance.innerShadowOffset;
- _theme.innerCornerRadius = appearance.innerCornerRadius;
- _theme.viewContentInsets = appearance.viewContentInsets;
- _theme.overlayColor = appearance.overlayColor;
- _theme.preferredAlpha = appearance.preferredAlpha;
- themeIsUpdating = NO;
- themeUpdatesEnabled = YES;
- popoverContentSize_ = CGSizeZero;
- }
- return self;
- }
- - (id)initWithContentViewController:(UIViewController *)aViewController {
- self = [self init];
- if (self) {
- _viewController = aViewController;
- }
- return self;
- }
- - (void)setTheme:(WYPopoverTheme *)value {
- [self unregisterTheme];
- _theme = value;
- [self registerTheme];
- [self updateThemeUI];
- themeIsUpdating = NO;
- }
- - (void)registerTheme {
- if (_theme == nil) return;
- NSArray *keypaths = [_theme observableKeypaths];
- for (NSString *keypath in keypaths) {
- [_theme addObserver:self forKeyPath:keypath options:NSKeyValueObservingOptionNew context:NULL];
- }
- }
- - (void)unregisterTheme {
- if (_theme == nil) return;
- @try {
- NSArray *keypaths = [_theme observableKeypaths];
- for (NSString *keypath in keypaths) {
- [_theme removeObserver:self forKeyPath:keypath];
- }
- }
- @catch (NSException * __unused exception) {}
- }
- - (void)updateThemeUI {
- if (_theme == nil || themeUpdatesEnabled == NO || themeIsUpdating == YES) return;
- if (_backgroundView != nil) {
- _backgroundView.usesRoundedArrow = _theme.usesRoundedArrow;
- _backgroundView.dimsBackgroundViewsTintColor = _theme.dimsBackgroundViewsTintColor;
- _backgroundView.tintColor = _theme.tintColor;
- _backgroundView.outerStrokeColor = _theme.outerStrokeColor;
- _backgroundView.innerStrokeColor = _theme.innerStrokeColor;
- _backgroundView.fillTopColor = _theme.fillTopColor;
- _backgroundView.fillBottomColor = _theme.fillBottomColor;
- _backgroundView.glossShadowColor = _theme.glossShadowColor;
- _backgroundView.glossShadowOffset = _theme.glossShadowOffset;
- _backgroundView.glossShadowBlurRadius = _theme.glossShadowBlurRadius;
- _backgroundView.borderWidth = _theme.borderWidth;
- _backgroundView.arrowBase = _theme.arrowBase;
- _backgroundView.arrowHeight = _theme.arrowHeight;
- _backgroundView.outerShadowColor = _theme.outerShadowColor;
- _backgroundView.outerShadowBlurRadius = _theme.outerShadowBlurRadius;
- _backgroundView.outerShadowOffset = _theme.outerShadowOffset;
- _backgroundView.outerCornerRadius = _theme.outerCornerRadius;
- _backgroundView.minOuterCornerRadius = _theme.minOuterCornerRadius;
- _backgroundView.innerShadowColor = _theme.innerShadowColor;
- _backgroundView.innerShadowBlurRadius = _theme.innerShadowBlurRadius;
- _backgroundView.innerShadowOffset = _theme.innerShadowOffset;
- _backgroundView.innerCornerRadius = _theme.innerCornerRadius;
- _backgroundView.viewContentInsets = _theme.viewContentInsets;
- _backgroundView.preferredAlpha = _theme.preferredAlpha;
- [_backgroundView setNeedsDisplay];
- }
- if (_overlayView != nil) {
- _overlayView.backgroundColor = _theme.overlayColor;
- }
- [self positionPopover:NO];
- [self setPopoverNavigationBarBackgroundImage];
- }
- - (void)beginThemeUpdates {
- themeIsUpdating = YES;
- }
- - (void)endThemeUpdates {
- themeIsUpdating = NO;
- [self updateThemeUI];
- }
- - (BOOL)isPopoverVisible {
- BOOL result = (_overlayView != nil);
- return result;
- }
- - (UIViewController *)contentViewController {
- return _viewController;
- }
- - (CGSize)topViewControllerContentSize {
- CGSize result = CGSizeZero;
- UIViewController *topViewController = _viewController;
- if ([_viewController isKindOfClass:[UINavigationController class]] == YES) {
- UINavigationController *navigationController = (UINavigationController *)_viewController;
- topViewController = [navigationController topViewController];
- }
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([topViewController respondsToSelector:@selector(preferredContentSize)]) {
- result = topViewController.preferredContentSize;
- }
- #endif
- if (CGSizeEqualToSize(result, CGSizeZero)) {
- #pragma clang diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated"
- result = topViewController.contentSizeForViewInPopover;
- #pragma clang diagnostic pop
- }
- if (CGSizeEqualToSize(result, CGSizeZero)) {
- CGSize windowSize = [[UIApplication sharedApplication] keyWindow].bounds.size;
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- result = CGSizeMake(UIInterfaceOrientationIsPortrait(orientation) ? windowSize.width : windowSize.height, UIInterfaceOrientationIsLandscape(orientation) ? windowSize.width : windowSize.height);
- }
- return result;
- }
- - (CGSize)popoverContentSize {
- CGSize result = popoverContentSize_;
- if (CGSizeEqualToSize(result, CGSizeZero)) {
- result = [self topViewControllerContentSize];
- }
- return result;
- }
- - (void)setPopoverContentSize:(CGSize)size {
- popoverContentSize_ = size;
- [self positionPopover:YES];
- }
- - (void)setPopoverContentSize:(CGSize)size animated:(BOOL)animated {
- popoverContentSize_ = size;
- [self positionPopover:animated];
- }
- - (void)performWithoutAnimation:(void (^)(void))aBlock {
- if (aBlock) {
- self.implicitAnimationsDisabled = YES;
- aBlock();
- self.implicitAnimationsDisabled = NO;
- }
- }
- - (void)presentPopoverFromRect:(CGRect)aRect
- inView:(UIView *)aView
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated {
- [self presentPopoverFromRect:aRect
- inView:aView
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- completion:nil];
- }
- - (void)presentPopoverFromRect:(CGRect)aRect
- inView:(UIView *)aView
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated
- completion:(void (^)(void))completion {
- [self presentPopoverFromRect:aRect
- inView:aView
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- options:WYPopoverAnimationOptionFade
- completion:completion];
- }
- - (void)presentPopoverFromRect:(CGRect)aRect
- inView:(UIView *)aView
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions {
- [self presentPopoverFromRect:aRect
- inView:aView
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- options:aOptions
- completion:nil];
- }
- - (void)presentPopoverFromRect:(CGRect)aRect
- inView:(UIView *)aView
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions
- completion:(void (^)(void))completion {
- NSAssert((aArrowDirections != WYPopoverArrowDirectionUnknown), @"WYPopoverArrowDirection must not be UNKNOWN");
- _rect = aRect;
- _inView = aView;
- _permittedArrowDirections = aArrowDirections;
- _animated = aAnimated;
- options = aOptions;
- if (!_inView) {
- _inView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
- if (CGRectIsEmpty(_rect)) {
- _rect = CGRectMake((int)_inView.bounds.size.width / 2 - 5, (int)_inView.bounds.size.height / 2 - 5, 10, 10);
- }
- }
- CGSize contentViewSize = self.popoverContentSize;
- if (_overlayView == nil) {
- _overlayView = [[WYPopoverOverlayView alloc] initWithFrame:_inView.window.bounds];
- _overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _overlayView.autoresizesSubviews = NO;
- _overlayView.delegate = self;
- _overlayView.passthroughViews = _passthroughViews;
- _backgroundView = [[WYPopoverBackgroundView alloc] initWithContentSize:contentViewSize];
- _backgroundView.appearing = YES;
- _backgroundView.delegate = self;
- _backgroundView.hidden = YES;
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:_backgroundView action:@selector(tapOut)];
- tap.cancelsTouchesInView = NO;
- [_overlayView addGestureRecognizer:tap];
- if (self.dismissOnTap) {
- tap = [[UITapGestureRecognizer alloc] initWithTarget:_backgroundView action:@selector(tapOut)];
- tap.cancelsTouchesInView = NO;
- [_backgroundView addGestureRecognizer:tap];
- }
- [_inView.window addSubview:_backgroundView];
- [_inView.window insertSubview:_overlayView belowSubview:_backgroundView];
- }
- [self updateThemeUI];
- __weak __typeof__(self) weakSelf = self;
- void (^completionBlock)(BOOL) = ^(BOOL animated) {
- __typeof__(self) strongSelf = weakSelf;
- if (strongSelf) {
- if (_isObserverAdded == NO) {
- _isObserverAdded = YES;
- if ([strongSelf->_viewController respondsToSelector:@selector(preferredContentSize)]) {
- [strongSelf->_viewController addObserver:self forKeyPath:NSStringFromSelector(@selector(preferredContentSize)) options:0 context:nil];
- } else {
- [strongSelf->_viewController addObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeForViewInPopover)) options:0 context:nil];
- }
- }
- strongSelf->_backgroundView.appearing = NO;
- }
- if (completion) {
- completion();
- } else if (strongSelf && strongSelf->_delegate && [strongSelf->_delegate respondsToSelector:@selector(popoverControllerDidPresentPopover:)]) {
- [strongSelf->_delegate popoverControllerDidPresentPopover:strongSelf];
- }
- };
- void (^adjustTintDimmed)() = ^() {
- #ifdef WY_BASE_SDK_7_ENABLED
- if (_backgroundView.dimsBackgroundViewsTintColor && [_inView.window respondsToSelector:@selector(setTintAdjustmentMode:)]) {
- for (UIView *subview in _inView.window.subviews) {
- if (subview != _backgroundView) {
- [subview setTintAdjustmentMode:UIViewTintAdjustmentModeDimmed];
- }
- }
- }
- #endif
- };
- _backgroundView.hidden = NO;
- if (_animated) {
- if ((options & WYPopoverAnimationOptionFade) == WYPopoverAnimationOptionFade) {
- _overlayView.alpha = 0;
- _backgroundView.alpha = 0;
- }
- CGAffineTransform endTransform = _backgroundView.transform;
- if ((options & WYPopoverAnimationOptionScale) == WYPopoverAnimationOptionScale) {
- CGAffineTransform startTransform = [self transformForArrowDirection:_backgroundView.arrowDirection];
- _backgroundView.transform = startTransform;
- }
- [UIView animateWithDuration:_animationDuration animations:^{
- __typeof__(self) strongSelf = weakSelf;
- if (strongSelf) {
- strongSelf->_overlayView.alpha = 1;
- strongSelf->_backgroundView.alpha = strongSelf->_backgroundView.preferredAlpha;
- strongSelf->_backgroundView.transform = endTransform;
- }
- adjustTintDimmed();
- } completion:^(BOOL finished) {
- completionBlock(YES);
- }];
- } else {
- adjustTintDimmed();
- completionBlock(NO);
- }
- if (_isListeningNotifications == NO) {
- _isListeningNotifications = YES;
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(didChangeStatusBarOrientation:)
- name:UIApplicationDidChangeStatusBarOrientationNotification
- object:nil];
- [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(didChangeDeviceOrientation:)
- name:UIDeviceOrientationDidChangeNotification
- object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(keyboardWillShow:)
- name:UIKeyboardWillShowNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(keyboardWillHide:)
- name:UIKeyboardWillHideNotification object:nil];
- }
- }
- - (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)aItem
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated {
- [self presentPopoverFromBarButtonItem:aItem
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- completion:nil];
- }
- - (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)aItem
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated
- completion:(void (^)(void))completion {
- [self presentPopoverFromBarButtonItem:aItem
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- options:WYPopoverAnimationOptionFade
- completion:completion];
- }
- - (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)aItem
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions {
- [self presentPopoverFromBarButtonItem:aItem
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- options:aOptions
- completion:nil];
- }
- - (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)aItem
- permittedArrowDirections:(WYPopoverArrowDirection)aArrowDirections
- animated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions
- completion:(void (^)(void))completion {
- _barButtonItem = aItem;
- UIView *itemView = [_barButtonItem valueForKey:@"view"];
- aArrowDirections = WYPopoverArrowDirectionDown | WYPopoverArrowDirectionUp;
- [self presentPopoverFromRect:itemView.bounds
- inView:itemView
- permittedArrowDirections:aArrowDirections
- animated:aAnimated
- options:aOptions
- completion:completion];
- }
- - (void)presentPopoverAsDialogAnimated:(BOOL)aAnimated {
- [self presentPopoverAsDialogAnimated:aAnimated
- completion:nil];
- }
- - (void)presentPopoverAsDialogAnimated:(BOOL)aAnimated
- completion:(void (^)(void))completion {
- [self presentPopoverAsDialogAnimated:aAnimated
- options:WYPopoverAnimationOptionFade
- completion:completion];
- }
- - (void)presentPopoverAsDialogAnimated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions {
- [self presentPopoverAsDialogAnimated:aAnimated
- options:aOptions
- completion:nil];
- }
- - (void)presentPopoverAsDialogAnimated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions
- completion:(void (^)(void))completion {
- [self presentPopoverFromRect:CGRectZero
- inView:nil
- permittedArrowDirections:WYPopoverArrowDirectionNone
- animated:aAnimated
- options:aOptions
- completion:completion];
- }
- - (CGAffineTransform)transformForArrowDirection:(WYPopoverArrowDirection)arrowDirection {
- CGAffineTransform transform = _backgroundView.transform;
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- CGSize containerViewSize = _backgroundView.frame.size;
- if (_backgroundView.arrowHeight > 0) {
- if (UIInterfaceOrientationIsLandscape(orientation)) {
- containerViewSize.width = _backgroundView.frame.size.height;
- containerViewSize.height = _backgroundView.frame.size.width;
- }
- //WY_LOG(@"containerView.arrowOffset = %f", containerView.arrowOffset);
- //WY_LOG(@"containerViewSize = %@", NSStringFromCGSize(containerViewSize));
- //WY_LOG(@"orientation = %@", WYStringFromOrientation(orientation));
- if (arrowDirection == WYPopoverArrowDirectionDown) {
- transform = CGAffineTransformTranslate(transform, _backgroundView.arrowOffset, containerViewSize.height / 2);
- }
- if (arrowDirection == WYPopoverArrowDirectionUp) {
- transform = CGAffineTransformTranslate(transform, _backgroundView.arrowOffset, -containerViewSize.height / 2);
- }
- if (arrowDirection == WYPopoverArrowDirectionRight) {
- transform = CGAffineTransformTranslate(transform, containerViewSize.width / 2, _backgroundView.arrowOffset);
- }
- if (arrowDirection == WYPopoverArrowDirectionLeft) {
- transform = CGAffineTransformTranslate(transform, -containerViewSize.width / 2, _backgroundView.arrowOffset);
- }
- }
- transform = CGAffineTransformScale(transform, 0.01, 0.01);
- return transform;
- }
- - (void)setPopoverNavigationBarBackgroundImage {
- if ([_viewController isKindOfClass:[UINavigationController class]] == YES) {
- UINavigationController *navigationController = (UINavigationController *)_viewController;
- navigationController.wy_embedInPopover = YES;
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([navigationController respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
- UIViewController *topViewController = [navigationController topViewController];
- [topViewController setEdgesForExtendedLayout:UIRectEdgeNone];
- }
- #endif
- if (_wantsDefaultContentAppearance == NO) {
- [navigationController.navigationBar setBackgroundImage:[UIImage wy_imageWithColor:[UIColor clearColor]] forBarMetrics:UIBarMetricsDefault];
- }
- }
- _viewController.view.clipsToBounds = YES;
- if (_backgroundView.borderWidth == 0) {
- _viewController.view.layer.cornerRadius = _backgroundView.outerCornerRadius;
- }
- }
- - (void)positionPopover:(BOOL)aAnimated {
- CGRect savedContainerFrame = _backgroundView.frame;
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- CGSize contentViewSize = self.popoverContentSize;
- CGSize minContainerSize = WY_POPOVER_MIN_SIZE;
- CGRect viewFrame;
- CGRect containerFrame = CGRectZero;
- float minX, maxX, minY, maxY, offset = 0;
- CGSize containerViewSize = CGSizeZero;
- float overlayWidth;
- float overlayHeight;
- float keyboardHeight;
- if (_ignoreOrientation) {
- overlayWidth = _overlayView.window.frame.size.width;
- overlayHeight = _overlayView.window.frame.size.height;
- CGRect convertedFrame = [_overlayView.window convertRect:WYKeyboardListener.rect toView:_overlayView];
- keyboardHeight = convertedFrame.size.height;
- } else {
- overlayWidth = UIInterfaceOrientationIsPortrait(orientation) ? _overlayView.bounds.size.width : _overlayView.bounds.size.height;
- overlayHeight = UIInterfaceOrientationIsPortrait(orientation) ? _overlayView.bounds.size.height : _overlayView.bounds.size.width;
- keyboardHeight = UIInterfaceOrientationIsPortrait(orientation) ? WYKeyboardListener.rect.size.height : WYKeyboardListener.rect.size.width;
- }
- if (_delegate && [_delegate respondsToSelector:@selector(popoverControllerShouldIgnoreKeyboardBounds:)]) {
- BOOL shouldIgnore = [_delegate popoverControllerShouldIgnoreKeyboardBounds:self];
- if (shouldIgnore) {
- keyboardHeight = 0;
- }
- }
- WYPopoverArrowDirection arrowDirection = _permittedArrowDirections;
- _overlayView.bounds = _inView.window.bounds;
- _backgroundView.transform = CGAffineTransformIdentity;
- viewFrame = [_inView convertRect:_rect toView:nil];
- viewFrame = WYRectInWindowBounds(viewFrame, orientation);
- minX = _popoverLayoutMargins.left;
- maxX = overlayWidth - _popoverLayoutMargins.right;
- minY = WYStatusBarHeight() + _popoverLayoutMargins.top;
- maxY = overlayHeight - _popoverLayoutMargins.bottom - keyboardHeight;
- // Which direction ?
- //
- arrowDirection = [self arrowDirectionForRect:_rect
- inView:_inView
- contentSize:contentViewSize
- arrowHeight:_backgroundView.arrowHeight
- permittedArrowDirections:arrowDirection];
- // Position of the popover
- //
- minX -= _backgroundView.outerShadowInsets.left;
- maxX += _backgroundView.outerShadowInsets.right;
- minY -= _backgroundView.outerShadowInsets.top;
- maxY += _backgroundView.outerShadowInsets.bottom;
- if (arrowDirection == WYPopoverArrowDirectionDown) {
- _backgroundView.arrowDirection = WYPopoverArrowDirectionDown;
- containerViewSize = [_backgroundView sizeThatFits:contentViewSize];
- containerFrame = CGRectZero;
- containerFrame.size = containerViewSize;
- containerFrame.size.width = MIN(maxX - minX, containerFrame.size.width);
- containerFrame.size.height = MIN(maxY - minY, containerFrame.size.height);
- _backgroundView.frame = CGRectIntegral(containerFrame);
- _backgroundView.center = CGPointMake(viewFrame.origin.x + viewFrame.size.width / 2, viewFrame.origin.y + viewFrame.size.height / 2);
- containerFrame = _backgroundView.frame;
- offset = 0;
- if (containerFrame.origin.x < minX) {
- offset = minX - containerFrame.origin.x;
- containerFrame.origin.x = minX;
- offset = -offset;
- } else if (containerFrame.origin.x + containerFrame.size.width > maxX) {
- offset = (_backgroundView.frame.origin.x + _backgroundView.frame.size.width) - maxX;
- containerFrame.origin.x -= offset;
- }
- _backgroundView.arrowOffset = offset;
- offset = _backgroundView.frame.size.height / 2 + viewFrame.size.height / 2 - _backgroundView.outerShadowInsets.bottom;
- containerFrame.origin.y -= offset;
- if (containerFrame.origin.y < minY) {
- offset = minY - containerFrame.origin.y;
- containerFrame.size.height -= offset;
- if (containerFrame.size.height < minContainerSize.height) {
- // popover is overflowing
- offset -= (minContainerSize.height - containerFrame.size.height);
- containerFrame.size.height = minContainerSize.height;
- }
- containerFrame.origin.y += offset;
- }
- }
- if (arrowDirection == WYPopoverArrowDirectionUp) {
- _backgroundView.arrowDirection = WYPopoverArrowDirectionUp;
- containerViewSize = [_backgroundView sizeThatFits:contentViewSize];
- containerFrame = CGRectZero;
- containerFrame.size = containerViewSize;
- containerFrame.size.width = MIN(maxX - minX, containerFrame.size.width);
- containerFrame.size.height = MIN(maxY - minY, containerFrame.size.height);
- _backgroundView.frame = containerFrame;
- _backgroundView.center = CGPointMake(viewFrame.origin.x + viewFrame.size.width / 2, viewFrame.origin.y + viewFrame.size.height / 2);
- containerFrame = _backgroundView.frame;
- offset = 0;
- if (containerFrame.origin.x < minX) {
- offset = minX - containerFrame.origin.x;
- containerFrame.origin.x = minX;
- offset = -offset;
- }
- else if (containerFrame.origin.x + containerFrame.size.width > maxX) {
- offset = (_backgroundView.frame.origin.x + _backgroundView.frame.size.width) - maxX;
- containerFrame.origin.x -= offset;
- }
- _backgroundView.arrowOffset = offset;
- offset = _backgroundView.frame.size.height / 2 + viewFrame.size.height / 2 - _backgroundView.outerShadowInsets.top;
- containerFrame.origin.y += offset;
- if (containerFrame.origin.y + containerFrame.size.height > maxY) {
- offset = (containerFrame.origin.y + containerFrame.size.height) - maxY;
- containerFrame.size.height -= offset;
- if (containerFrame.size.height < minContainerSize.height) {
- // popover is overflowing
- containerFrame.size.height = minContainerSize.height;
- }
- }
- }
- if (arrowDirection == WYPopoverArrowDirectionRight) {
- _backgroundView.arrowDirection = WYPopoverArrowDirectionRight;
- containerViewSize = [_backgroundView sizeThatFits:contentViewSize];
- containerFrame = CGRectZero;
- containerFrame.size = containerViewSize;
- containerFrame.size.width = MIN(maxX - minX, containerFrame.size.width);
- containerFrame.size.height = MIN(maxY - minY, containerFrame.size.height);
- _backgroundView.frame = CGRectIntegral(containerFrame);
- _backgroundView.center = CGPointMake(viewFrame.origin.x + viewFrame.size.width / 2, viewFrame.origin.y + viewFrame.size.height / 2);
- containerFrame = _backgroundView.frame;
- offset = _backgroundView.frame.size.width / 2 + viewFrame.size.width / 2 - _backgroundView.outerShadowInsets.right;
- containerFrame.origin.x -= offset;
- if (containerFrame.origin.x < minX) {
- offset = minX - containerFrame.origin.x;
- containerFrame.size.width -= offset;
- if (containerFrame.size.width < minContainerSize.width) {
- // popover is overflowing
- offset -= (minContainerSize.width - containerFrame.size.width);
- containerFrame.size.width = minContainerSize.width;
- }
- containerFrame.origin.x += offset;
- }
- offset = 0;
- if (containerFrame.origin.y < minY) {
- offset = minY - containerFrame.origin.y;
- containerFrame.origin.y = minY;
- offset = -offset;
- } else if (containerFrame.origin.y + containerFrame.size.height > maxY) {
- offset = (_backgroundView.frame.origin.y + _backgroundView.frame.size.height) - maxY;
- containerFrame.origin.y -= offset;
- }
- _backgroundView.arrowOffset = offset;
- }
- if (arrowDirection == WYPopoverArrowDirectionLeft) {
- _backgroundView.arrowDirection = WYPopoverArrowDirectionLeft;
- containerViewSize = [_backgroundView sizeThatFits:contentViewSize];
- containerFrame = CGRectZero;
- containerFrame.size = containerViewSize;
- containerFrame.size.width = MIN(maxX - minX, containerFrame.size.width);
- containerFrame.size.height = MIN(maxY - minY, containerFrame.size.height);
- _backgroundView.frame = containerFrame;
- _backgroundView.center = CGPointMake(viewFrame.origin.x + viewFrame.size.width / 2, viewFrame.origin.y + viewFrame.size.height / 2);
- containerFrame = CGRectIntegral(_backgroundView.frame);
- offset = _backgroundView.frame.size.width / 2 + viewFrame.size.width / 2 - _backgroundView.outerShadowInsets.left;
- containerFrame.origin.x += offset;
- if (containerFrame.origin.x + containerFrame.size.width > maxX) {
- offset = (containerFrame.origin.x + containerFrame.size.width) - maxX;
- containerFrame.size.width -= offset;
- if (containerFrame.size.width < minContainerSize.width) {
- // popover is overflowing
- containerFrame.size.width = minContainerSize.width;
- }
- }
- offset = 0;
- if (containerFrame.origin.y < minY) {
- offset = minY - containerFrame.origin.y;
- containerFrame.origin.y = minY;
- offset = -offset;
- } else if (containerFrame.origin.y + containerFrame.size.height > maxY) {
- offset = (_backgroundView.frame.origin.y + _backgroundView.frame.size.height) - maxY;
- containerFrame.origin.y -= offset;
- }
- _backgroundView.arrowOffset = offset;
- }
- if (arrowDirection == WYPopoverArrowDirectionNone) {
- _backgroundView.arrowDirection = WYPopoverArrowDirectionNone;
- containerViewSize = [_backgroundView sizeThatFits:contentViewSize];
- containerFrame = CGRectZero;
- containerFrame.size = containerViewSize;
- containerFrame.size.width = MIN(maxX - minX, containerFrame.size.width);
- containerFrame.size.height = MIN(maxY - minY, containerFrame.size.height);
- _backgroundView.frame = CGRectIntegral(containerFrame);
- _backgroundView.center = CGPointMake(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2);
- containerFrame = _backgroundView.frame;
- _backgroundView.arrowOffset = offset;
- }
- containerFrame = CGRectIntegral(containerFrame);
- _backgroundView.frame = containerFrame;
- _backgroundView.wantsDefaultContentAppearance = _wantsDefaultContentAppearance;
- [_backgroundView setViewController:_viewController];
- // keyboard support
- if (keyboardHeight > 0) {
- float keyboardY = overlayHeight - keyboardHeight;
- float yOffset = containerFrame.origin.y + containerFrame.size.height - keyboardY;
- if (yOffset > 0) {
- if (containerFrame.origin.y - yOffset < minY) {
- yOffset -= minY - (containerFrame.origin.y - yOffset);
- }
- if ([_delegate respondsToSelector:@selector(popoverController:willTranslatePopoverWithYOffset:)]) {
- [_delegate popoverController:self willTranslatePopoverWithYOffset:&yOffset];
- }
- containerFrame.origin.y -= yOffset;
- }
- }
- CGPoint containerOrigin = containerFrame.origin;
- _backgroundView.transform = CGAffineTransformMakeRotation(WYInterfaceOrientationAngleOfOrientation(orientation));
- containerFrame = _backgroundView.frame;
- containerFrame.origin = WYPointRelativeToOrientation(containerOrigin, containerFrame.size, orientation);
- if (aAnimated == YES && !self.implicitAnimationsDisabled) {
- _backgroundView.frame = savedContainerFrame;
- __weak __typeof__(self) weakSelf = self;
- [UIView animateWithDuration:0.10f animations:^{
- __typeof__(self) strongSelf = weakSelf;
- strongSelf->_backgroundView.frame = containerFrame;
- }];
- } else {
- _backgroundView.frame = containerFrame;
- }
- [_backgroundView setNeedsDisplay];
- // WY_LOG(@"popoverContainerView.frame = %@", NSStringFromCGRect(_backgroundView.frame));
- }
- - (void)dismissPopoverAnimated:(BOOL)aAnimated {
- [self dismissPopoverAnimated:aAnimated
- options:options
- completion:nil];
- }
- - (void)dismissPopoverAnimated:(BOOL)aAnimated
- completion:(void (^)(void))completion {
- [self dismissPopoverAnimated:aAnimated
- options:options
- completion:completion];
- }
- - (void)dismissPopoverAnimated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions {
- [self dismissPopoverAnimated:aAnimated
- options:aOptions
- completion:nil];
- }
- - (void)dismissPopoverAnimated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions
- completion:(void (^)(void))completion {
- [self dismissPopoverAnimated:aAnimated
- options:aOptions
- completion:completion
- callDelegate:NO];
- }
- - (void)dismissPopoverAnimated:(BOOL)aAnimated
- options:(WYPopoverAnimationOptions)aOptions
- completion:(void (^)(void))completion
- callDelegate:(BOOL)callDelegate {
- float duration = self.animationDuration;
- WYPopoverAnimationOptions style = aOptions;
- __weak __typeof__(self) weakSelf = self;
- void (^adjustTintAutomatic)() = ^() {
- #ifdef WY_BASE_SDK_7_ENABLED
- if ([_inView.window respondsToSelector:@selector(setTintAdjustmentMode:)]) {
- for (UIView *subview in _inView.window.subviews) {
- if (subview != _backgroundView) {
- [subview setTintAdjustmentMode:UIViewTintAdjustmentModeAutomatic];
- }
- }
- }
- #endif
- };
- void (^completionBlock)() = ^() {
- __typeof__(self) strongSelf = weakSelf;
- if (strongSelf) {
- [strongSelf->_backgroundView removeFromSuperview];
- strongSelf->_backgroundView = nil;
- [strongSelf->_overlayView removeFromSuperview];
- strongSelf->_overlayView = nil;
- // inView is captured strongly in presentPopoverInRect:... method, so it needs to be released in dismiss method to avoid potential retain cycles
- strongSelf->_inView = nil;
- }
- if (completion) {
- completion();
- }
- else if (callDelegate && strongSelf && strongSelf->_delegate && [strongSelf->_delegate respondsToSelector:@selector(popoverControllerDidDismissPopover:)]) {
- [strongSelf->_delegate popoverControllerDidDismissPopover:strongSelf];
- }
- if (self.dismissCompletionBlock) {
- self.dismissCompletionBlock(strongSelf);
- }
- };
- if (_isListeningNotifications == YES) {
- _isListeningNotifications = NO;
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:UIApplicationDidChangeStatusBarOrientationNotification
- object:nil];
- [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:UIDeviceOrientationDidChangeNotification
- object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:UIKeyboardWillShowNotification
- object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:UIKeyboardWillHideNotification
- object:nil];
- }
- @try {
- if (_isObserverAdded == YES) {
- _isObserverAdded = NO;
- if ([_viewController respondsToSelector:@selector(preferredContentSize)]) {
- [_viewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(preferredContentSize))];
- } else {
- [_viewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeForViewInPopover))];
- }
- }
- }
- @catch (NSException * __unused exception) {}
- if (aAnimated && !self.implicitAnimationsDisabled) {
- [UIView animateWithDuration:duration animations:^{
- __typeof__(self) strongSelf = weakSelf;
- if (strongSelf) {
- if ((style & WYPopoverAnimationOptionFade) == WYPopoverAnimationOptionFade) {
- strongSelf->_backgroundView.alpha = 0;
- }
- if ((style & WYPopoverAnimationOptionScale) == WYPopoverAnimationOptionScale) {
- CGAffineTransform endTransform = [self transformForArrowDirection:strongSelf->_backgroundView.arrowDirection];
- strongSelf->_backgroundView.transform = endTransform;
- }
- strongSelf->_overlayView.alpha = 0;
- }
- adjustTintAutomatic();
- } completion:^(BOOL finished) {
- completionBlock();
- }];
- } else {
- adjustTintAutomatic();
- completionBlock();
- }
- }
- #pragma mark KVO
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- if (object == _viewController) {
- if ([keyPath isEqualToString:NSStringFromSelector(@selector(preferredContentSize))]
- || [keyPath isEqualToString:NSStringFromSelector(@selector(contentSizeForViewInPopover))]) {
- CGSize contentSize = [self topViewControllerContentSize];
- [self setPopoverContentSize:contentSize];
- }
- } else if (object == _theme) {
- [self updateThemeUI];
- }
- }
- #pragma mark WYPopoverOverlayViewDelegate
- - (void)popoverOverlayViewDidTouch:(WYPopoverOverlayView *)aOverlayView {
- BOOL shouldDismiss = !_viewController.modalInPopover;
- if (shouldDismiss && _delegate && [_delegate respondsToSelector:@selector(popoverControllerShouldDismissPopover:)]) {
- shouldDismiss = [_delegate popoverControllerShouldDismissPopover:self];
- }
- if (shouldDismiss) {
- [self dismissPopoverAnimated:_animated options:options completion:nil callDelegate:YES];
- }
- }
- #pragma mark WYPopoverBackgroundViewDelegate
- - (void)popoverBackgroundViewDidTouchOutside:(WYPopoverBackgroundView *)aBackgroundView {
- [self popoverOverlayViewDidTouch:nil];
- }
- #pragma mark Private
- - (WYPopoverArrowDirection)arrowDirectionForRect:(CGRect)aRect
- inView:(UIView *)aView
- contentSize:(CGSize)contentSize
- arrowHeight:(float)arrowHeight
- permittedArrowDirections:(WYPopoverArrowDirection)arrowDirections {
- WYPopoverArrowDirection arrowDirection = WYPopoverArrowDirectionUnknown;
- NSMutableArray *areas = [NSMutableArray arrayWithCapacity:0];
- WYPopoverArea *area;
- if ((arrowDirections & WYPopoverArrowDirectionDown) == WYPopoverArrowDirectionDown) {
- area = [[WYPopoverArea alloc] init];
- area.areaSize = [self sizeForRect:aRect inView:aView arrowHeight:arrowHeight arrowDirection:WYPopoverArrowDirectionDown];
- area.arrowDirection = WYPopoverArrowDirectionDown;
- [areas addObject:area];
- }
- if ((arrowDirections & WYPopoverArrowDirectionUp) == WYPopoverArrowDirectionUp) {
- area = [[WYPopoverArea alloc] init];
- area.areaSize = [self sizeForRect:aRect inView:aView arrowHeight:arrowHeight arrowDirection:WYPopoverArrowDirectionUp];
- area.arrowDirection = WYPopoverArrowDirectionUp;
- [areas addObject:area];
- }
- if ((arrowDirections & WYPopoverArrowDirectionLeft) == WYPopoverArrowDirectionLeft) {
- area = [[WYPopoverArea alloc] init];
- area.areaSize = [self sizeForRect:aRect inView:aView arrowHeight:arrowHeight arrowDirection:WYPopoverArrowDirectionLeft];
- area.arrowDirection = WYPopoverArrowDirectionLeft;
- [areas addObject:area];
- }
- if ((arrowDirections & WYPopoverArrowDirectionRight) == WYPopoverArrowDirectionRight) {
- area = [[WYPopoverArea alloc] init];
- area.areaSize = [self sizeForRect:aRect inView:aView arrowHeight:arrowHeight arrowDirection:WYPopoverArrowDirectionRight];
- area.arrowDirection = WYPopoverArrowDirectionRight;
- [areas addObject:area];
- }
- if ((arrowDirections & WYPopoverArrowDirectionNone) == WYPopoverArrowDirectionNone) {
- area = [[WYPopoverArea alloc] init];
- area.areaSize = [self sizeForRect:aRect inView:aView arrowHeight:arrowHeight arrowDirection:WYPopoverArrowDirectionNone];
- area.arrowDirection = WYPopoverArrowDirectionNone;
- [areas addObject:area];
- }
- if ([areas count] > 1) {
- NSIndexSet* indexes = [areas indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
- WYPopoverArea* popoverArea = (WYPopoverArea*)obj;
- BOOL result = (popoverArea.areaSize.width > 0 && popoverArea.areaSize.height > 0);
- return result;
- }];
- areas = [NSMutableArray arrayWithArray:[areas objectsAtIndexes:indexes]];
- }
- [areas sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
- WYPopoverArea *area1 = (WYPopoverArea *)obj1;
- WYPopoverArea *area2 = (WYPopoverArea *)obj2;
- float val1 = area1.value;
- float val2 = area2.value;
- NSComparisonResult result = NSOrderedSame;
- if (val1 > val2) {
- result = NSOrderedAscending;
- } else if (val1 < val2) {
- result = NSOrderedDescending;
- }
- return result;
- }];
- for (NSUInteger i = 0; i < [areas count]; i++) {
- WYPopoverArea *popoverArea = (WYPopoverArea *)[areas objectAtIndex:i];
- if (popoverArea.areaSize.width >= contentSize.width) {
- arrowDirection = popoverArea.arrowDirection;
- break;
- }
- }
- if (arrowDirection == WYPopoverArrowDirectionUnknown) {
- if ([areas count] > 0) {
- arrowDirection = ((WYPopoverArea *)[areas objectAtIndex:0]).arrowDirection;
- } else {
- if ((arrowDirections & WYPopoverArrowDirectionDown) == WYPopoverArrowDirectionDown) {
- arrowDirection = WYPopoverArrowDirectionDown;
- } else if ((arrowDirections & WYPopoverArrowDirectionUp) == WYPopoverArrowDirectionUp) {
- arrowDirection = WYPopoverArrowDirectionUp;
- } else if ((arrowDirections & WYPopoverArrowDirectionLeft) == WYPopoverArrowDirectionLeft) {
- arrowDirection = WYPopoverArrowDirectionLeft;
- } else {
- arrowDirection = WYPopoverArrowDirectionRight;
- }
- }
- }
- return arrowDirection;
- }
- - (CGSize)sizeForRect:(CGRect)aRect
- inView:(UIView *)aView
- arrowHeight:(float)arrowHeight
- arrowDirection:(WYPopoverArrowDirection)arrowDirection {
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- CGRect viewFrame = [aView convertRect:aRect toView:nil];
- viewFrame = WYRectInWindowBounds(viewFrame, orientation);
- float minX, maxX, minY, maxY = 0;
- float keyboardHeight = WYKeyboardListener.rect.size.height;
- float overlayWidth = _overlayView.bounds.size.width;
- float overlayHeight = _overlayView.bounds.size.height;
-
- if (!_ignoreOrientation && UIInterfaceOrientationIsLandscape(orientation)) {
- keyboardHeight = WYKeyboardListener.rect.size.width;
- overlayWidth = _overlayView.bounds.size.height;
- overlayHeight = _overlayView.bounds.size.width;
- }
- if (_delegate && [_delegate respondsToSelector:@selector(popoverControllerShouldIgnoreKeyboardBounds:)]) {
- BOOL shouldIgnore = [_delegate popoverControllerShouldIgnoreKeyboardBounds:self];
- if (shouldIgnore) {
- keyboardHeight = 0;
- }
- }
- minX = _popoverLayoutMargins.left;
- maxX = overlayWidth - _popoverLayoutMargins.right;
- minY = WYStatusBarHeight() + _popoverLayoutMargins.top;
- maxY = overlayHeight - _popoverLayoutMargins.bottom - keyboardHeight;
- CGSize result = CGSizeZero;
- if (arrowDirection == WYPopoverArrowDirectionLeft) {
- result.width = maxX - (viewFrame.origin.x + viewFrame.size.width);
- result.width -= arrowHeight;
- result.height = maxY - minY;
- } else if (arrowDirection == WYPopoverArrowDirectionRight) {
- result.width = viewFrame.origin.x - minX;
- result.width -= arrowHeight;
- result.height = maxY - minY;
- } else if (arrowDirection == WYPopoverArrowDirectionDown) {
- result.width = maxX - minX;
- result.height = viewFrame.origin.y - minY;
- result.height -= arrowHeight;
- } else if (arrowDirection == WYPopoverArrowDirectionUp) {
- result.width = maxX - minX;
- result.height = maxY - (viewFrame.origin.y + viewFrame.size.height);
- result.height -= arrowHeight;
- } else if (arrowDirection == WYPopoverArrowDirectionNone) {
- result.width = maxX - minX;
- result.height = maxY - minY;
- }
- return result;
- }
- #pragma mark Inline functions
- static BOOL compileUsingIOS8SDK() {
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
- return YES;
- #endif
- return NO;
- }
- __unused static NSString* WYStringFromOrientation(NSInteger orientation) {
- NSString *result = @"Unknown";
- switch (orientation) {
- case UIInterfaceOrientationPortrait:
- result = @"Portrait";
- break;
- case UIInterfaceOrientationPortraitUpsideDown:
- result = @"Portrait UpsideDown";
- break;
- case UIInterfaceOrientationLandscapeLeft:
- result = @"Landscape Left";
- break;
- case UIInterfaceOrientationLandscapeRight:
- result = @"Landscape Right";
- break;
- default:
- break;
- }
- return result;
- }
- static float WYStatusBarHeight() {
- if (compileUsingIOS8SDK() && [[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
- CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
- return statusBarFrame.size.height;
- } else {
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- float statusBarHeight = 0;
- CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
- statusBarHeight = statusBarFrame.size.height;
- if (UIInterfaceOrientationIsLandscape(orientation))
- {
- statusBarHeight = statusBarFrame.size.width;
- }
- return statusBarHeight;
- }
- }
- static float WYInterfaceOrientationAngleOfOrientation(UIInterfaceOrientation orientation) {
- float angle;
- // no transformation needed in iOS 8
- if (compileUsingIOS8SDK() && [[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
- angle = 0.0;
- } else {
- switch (orientation) {
- case UIInterfaceOrientationPortraitUpsideDown:
- angle = M_PI;
- break;
- case UIInterfaceOrientationLandscapeLeft:
- angle = -M_PI_2;
- break;
- case UIInterfaceOrientationLandscapeRight:
- angle = M_PI_2;
- break;
- default:
- angle = 0.0;
- break;
- }
- }
- return angle;
- }
- static CGRect WYRectInWindowBounds(CGRect rect, UIInterfaceOrientation orientation) {
- UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
- float windowWidth = keyWindow.bounds.size.width;
- float windowHeight = keyWindow.bounds.size.height;
- CGRect result = rect;
- if (!(compileUsingIOS8SDK() && [[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)])) {
- if (orientation == UIInterfaceOrientationLandscapeRight) {
- result.origin.x = rect.origin.y;
- result.origin.y = windowWidth - rect.origin.x - rect.size.width;
- result.size.width = rect.size.height;
- result.size.height = rect.size.width;
- }
- if (orientation == UIInterfaceOrientationLandscapeLeft) {
- result.origin.x = windowHeight - rect.origin.y - rect.size.height;
- result.origin.y = rect.origin.x;
- result.size.width = rect.size.height;
- result.size.height = rect.size.width;
- }
- if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
- result.origin.x = windowWidth - rect.origin.x - rect.size.width;
- result.origin.y = windowHeight - rect.origin.y - rect.size.height;
- }
- }
- return result;
- }
- static CGPoint WYPointRelativeToOrientation(CGPoint origin, CGSize size, UIInterfaceOrientation orientation) {
- UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
- float windowWidth = keyWindow.bounds.size.width;
- float windowHeight = keyWindow.bounds.size.height;
- CGPoint result = origin;
- if (!(compileUsingIOS8SDK() && [[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)])) {
- if (orientation == UIInterfaceOrientationLandscapeRight) {
- result.x = windowWidth - origin.y - size.width;
- result.y = origin.x;
- }
- if (orientation == UIInterfaceOrientationLandscapeLeft) {
- result.x = origin.y;
- result.y = windowHeight - origin.x - size.height;
- }
- if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
- result.x = windowWidth - origin.x - size.width;
- result.y = windowHeight - origin.y - size.height;
- }
- }
- return result;
- }
- #pragma mark Selectors
- - (void)didChangeStatusBarOrientation:(NSNotification *)notification {
- _isInterfaceOrientationChanging = YES;
- }
- - (void)didChangeDeviceOrientation:(NSNotification *)notification {
- if (_isInterfaceOrientationChanging == NO) return;
- _isInterfaceOrientationChanging = NO;
- if ([_viewController isKindOfClass:[UINavigationController class]]) {
- UINavigationController* navigationController = (UINavigationController*)_viewController;
- if (navigationController.navigationBarHidden == NO) {
- navigationController.navigationBarHidden = YES;
- navigationController.navigationBarHidden = NO;
- }
- }
- if (_barButtonItem) {
- _inView = [_barButtonItem valueForKey:@"view"];
- _rect = _inView.bounds;
- } else if ([_delegate respondsToSelector:@selector(popoverController:willRepositionPopoverToRect:inView:)]) {
- CGRect anotherRect;
- UIView *anotherInView;
- [_delegate popoverController:self willRepositionPopoverToRect:&anotherRect inView:&anotherInView];
- #pragma clang diagnostic push
- #pragma GCC diagnostic ignored "-Wtautological-pointer-compare"
- if (&anotherRect != NULL) {
- _rect = anotherRect;
- }
- if (&anotherInView != NULL) {
- _inView = anotherInView;
- }
- #pragma GCC diagnostic pop
- }
- [self positionPopover:NO];
- }
- - (void)keyboardWillShow:(NSNotification *)notification {
- //UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- //WY_LOG(@"orientation = %@", WYStringFromOrientation(orientation));
- //WY_LOG(@"WYKeyboardListener.rect = %@", NSStringFromCGRect(WYKeyboardListener.rect));
- BOOL shouldIgnore = NO;
- if (_delegate && [_delegate respondsToSelector:@selector(popoverControllerShouldIgnoreKeyboardBounds:)]) {
- shouldIgnore = [_delegate popoverControllerShouldIgnoreKeyboardBounds:self];
- }
- if (shouldIgnore == NO) {
- [self positionPopover:YES];
- }
- }
- - (void)keyboardWillHide:(NSNotification *)notification {
- BOOL shouldIgnore = NO;
- if (_delegate && [_delegate respondsToSelector:@selector(popoverControllerShouldIgnoreKeyboardBounds:)]) {
- shouldIgnore = [_delegate popoverControllerShouldIgnoreKeyboardBounds:self];
- }
- if (shouldIgnore == NO) {
- [self positionPopover:YES];
- }
- }
- #pragma mark Memory management
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [_backgroundView removeFromSuperview];
- [_backgroundView setDelegate:nil];
- [_overlayView removeFromSuperview];
- [_overlayView setDelegate:nil];
- @try {
- if (_isObserverAdded == YES) {
- _isObserverAdded = NO;
- if ([_viewController respondsToSelector:@selector(preferredContentSize)]) {
- [_viewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(preferredContentSize))];
- } else {
- [_viewController removeObserver:self forKeyPath:NSStringFromSelector(@selector(contentSizeForViewInPopover))];
- }
- }
- }
- @catch (NSException *exception) {
- }
- @finally {
- _viewController = nil;
- }
- [self unregisterTheme];
- _barButtonItem = nil;
- _passthroughViews = nil;
- _inView = nil;
- _overlayView = nil;
- _backgroundView = nil;
- _theme = nil;
- }
- @end
|