iOS开发实战 - 完美解决UIScrollView嵌套滑动手势冲突
我们应该都有用过这个功能,你的朋友微信给你分享了一个淘宝里面的商品链接,然后当你复制这个链接打开淘宝APP的时候,就会弹出一个弹窗,像这样: example.PNG 这个功能想必大家都挺熟悉,受这个启发我们产品也想在我们APP上添加这样一个功能,与这个不一样的是,当我们复制一段网址的时候打开我们的APP会弹出框填一些信息后上传到我们的“资源库”。大体功能就这样,所以记录一下实现的过程。 一、弹窗视图功能 .h中:两个信号一个是确定信号一个是取消信号 两个方法,一个显示一个隐藏方法 1 2 3 4 5 @property(nonatomic,strong)RACSubject*uploadSureSignal; //确定上传信号 @property(nonatomic,strong)RACSubject*hideSucSignal; //隐藏 -( void )show; -( void )hide; .m中:主要是两个textview,还有涉及到在keywindow上,IQKeyboard的一些操作 1 2 3 @property(nonatomic,assign)CGFloatkeyboardHeight; //键盘高度 @property(nonatomic,strong)CustomUITextView*nameTV; @property(nonatomic,strong)CustomUITextView*desTV; 因为发现IQKeyboard在这个弹出界面有问题,所以在显示这个界面的时候,将IQKeyboard禁用取之使用系统的keyboard监听方法 在(void)show方法中: 1 2 3 4 5 6 7 8 -( void )show{ //键盘通知 NSNotificationCenter*defaultCenter=[NSNotificationCenterdefaultCenter]; [defaultCenteraddObserver:selfselector:@selector(keyboardWillShowOrHide:)name:UIKeyboardWillShowNotificationobject:nil]; [defaultCenteraddObserver:selfselector:@selector(keyboardWillShowOrHide:)name:UIKeyboardWillHideNotificationobject:nil]; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 //监听方法 -( void )keyboardWillShowOrHide:(NSNotification*)notification{ //获取通知名 NSString*notificationName=notification.name; //获取通知内容 NSDictionary*keyboardInfo=notification.userInfo; //键盘弹出时,让画面整体稍稍上移,并伴随动画 //键盘回收时反之 CGRectkeyboardFrame=[notification.userInfo[UIKeyboardFrameEndUserInfoKey]CGRectValue]; CGFloatheight=keyboardFrame.size.height; self.keyboardHeight=height; //动画结束后self.view的frame值 CGRectselfViewFrame=self.bgView.frame; //通过通知名字判断弹出还是回收 if ([notificationNameisEqualToString:UIKeyboardWillShowNotification]){ selfViewFrame.origin.y=SCREEN_HEIGHT-PANELHEIGHT-height; } else { selfViewFrame.origin.y=SCREEN_HEIGHT-PANELHEIGHT; } //取出动画时长 NSTimeIntervalduration=[keyboardInfo[UIKeyboardAnimationDurationUserInfoKey]doubleValue]; //使用动画更改self.view.frame [UIViewanimateWithDuration:durationanimations:^{ //这里填入一些view的最终状态属性设置,即会自动产生过渡动画 self.bgView.frame=selfViewFrame; }]; } 同时在show方法中显示keyWindow,进而改变界面的frame进行显示 1 2 3 4 5 6 7 8 9 10 -( void )show{ UIWindow*keyWindow=[UIApplicationsharedApplication].keyWindow; [keyWindowaddSubview:self]; CGRectframe=self.bgView.frame; if (frame.origin.y==SCREEN_HEIGHT){ frame.origin.y=SCREEN_HEIGHT-PANELHEIGHT; [UIViewanimateWithDuration: 0.4 animations:^{ self.bgView.frame=frame; }]; } hide方法这里要考虑到键盘弹出后将self.bgView向上提高后frame的变化。 1 2 3 4 5 6 7 8 9 10 11 12 13 CGRectselfFrame=self.bgView.frame; if (selfFrame.origin.y==SCREEN_HEIGHT-PANELHEIGHT||selfFrame.origin.y==SCREEN_HEIGHT-PANELHEIGHT-self.keyboardHeight){ [selfresignFirstResponder]; selfFrame.origin.y=SCREEN_HEIGHT; [UIViewanimateWithDuration: 0.4 animations:^{ self.bgView.frame=selfFrame; }completion:^(BOOLfinished){ [IQKeyboardManagersharedManager].enable=YES; [[NSNotificationCenterdefaultCenter]removeObserver:self]; //[self.hideSucSignalsendNext:nil]; [selfremoveFromSuperview]; }]; } delegate中的操作 这里首先要弄懂APPdelegate中的这几个代理方法的意思: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 //App已经启动 -(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{ //Overridepointforcustomizationafterapplicationlaunch. return YES; } //App挂起状态 -( void )applicationWillResignActive:(UIApplication*)application{ //Sentwhentheapplicationisabouttomovefromactivetoinactivestate.Thiscanoccurforcertaintypesoftemporaryinterruptions(suchasanincomingphonecallorSMSmessage)orwhentheuserquitstheapplicationanditbeginsthetransitiontothebackgroundstate. //Usethismethodtopauseongoingtasks,disabletimers,andinvalidategraphicsrenderingcallbacks.Gamesshouldusethismethodtopausethegame. } //APP进入后台 -( void )applicationDidEnterBackground:(UIApplication*)application{ //Usethismethodtoreleasesharedresources,saveuserdata,invalidatetimers,andstoreenoughapplicationstateinformationtorestoreyourapplicationtoitscurrentstateincaseitisterminatedlater. //Ifyourapplicationsupportsbackgroundexecution,thismethodiscalledinsteadofapplicationWillTerminate:whentheuserquits. } //APP将重新回到前台 -( void )applicationWillEnterForeground:(UIApplication*)application{ //Calledaspartofthetransitionfromthebackgroundtotheactivestate;hereyoucanundomanyofthechangesmadeonenteringthebackground. } //APP进入活跃状态 -( void )applicationDidBecomeActive:(UIApplication*)application{ //Restartanytasksthatwerepaused(ornotyetstarted)whiletheapplicationwasinactive.Iftheapplicationwaspreviouslyinthebackground,optionallyrefreshtheuserinterface. } //系统时间发生改变时执行 -( void )applicationWillTerminate:(UIApplication*)application{ //Calledwhentheapplicationisabouttoterminate.Savedataifappropriate.SeealsoapplicationDidEnterBackground:. } 在上面的这些代理方法中,我们需要用到的是 applicationDidBecomeActive方法。在这个方法中我们去检查系统的粘贴板UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 if (pasteboard.string){ NSLog(@ "string:%@" ,pasteboard.string); NSString*urlStr=pasteboard.string; if ([urlStrhasPrefix:@ "https://" ]||[urlStrhasPrefix:@ "http://" ]){ //如果粘贴板中的字符串包含https或http字段,我们去检查当前的控制器如果当前的控制器是我们弹出做操作的控制器的话isPopVC=NO; BOOLisPopVC=NO; UIViewController*Rootvc=self.window.rootViewController; if ([RootvcisKindOfClass:[UINavigationController class ]]){ UINavigationController*nav=(UINavigationController*)Rootvc; UIViewController*v=[nav.viewControllerslastObject]; if ([visKindOfClass:[UploadResCofingVC class ]]){ isPopVC=YES; } } //如果popView==nil并且isPopVC==NO弹出popView弹窗视图进行操作 if (!self.popView&&!isPopVC){ UploadResourcesPopupView*popView=[UploadResourcesPopupView new ]; [popViewshow]; self.popView=popView; [self.popView.hideSucSignalsubscribeNext:^(idx){ @strongify(self); self.popView=nil; }]; } } } } 总结 以上大体就是实现这个功能的基本思路,细节方面因项目而异了,比如我们需要判断当前用户的角色,当前用户是否登录,对弹窗视图后续的一些操作。当然并不完美,欢迎批评指正。 转自:http://www.cocoachina.com/ios/20180508/23307.html