• override func viewWillDisappear(_ animated: Bool) {  super.viewWillDisappear(animated)  navigationController?.interactivePopGestureRecognizer?.isEnabled = true;  }

      

    问题原因:

    当时项目有侧滑功能,还有push的动画 和系统本来的侧滑返回,---这三个东西在你频繁操作的时候会偶发,最终造成界面卡死。


    会出现侧滑异常,这里就吧侧滑返回功能给禁止了。


      overridefunc viewWillDisappear(_ animated:Bool) {

            super.viewWillDisappear(animated)

            navigationController?.interactivePopGestureRecognizer?.isEnabled =true;


        }

        

        overridefunc viewDidAppear(_ animated:Bool) {

            navigationController?.interactivePopGestureRecognizer?.isEnabled =false;


        }

        

    展开全文
  • 1、使用苹果手机的朋友应该都知道,在使用App的时候,如果要返回前一个界面,一般可以使用手指从屏幕左边缘开始向右一滑,就可以返回前一个界面,这也是返回时ios自带的返回动画,这里就简单介绍一下实现方式: ...

    1、使用苹果手机的朋友应该都知道,在使用App的时候,如果要返回前一个界面,一般可以使用手指从屏幕左边缘开始向右一滑,就可以返回前一个界面,这也是返回时ios自带的返回动画,这里就简单介绍一下实现方式:

    2、首先在正在显示的视图控制器的类名上需要实现 这两个协议:UIGestureRecognizerDelegate ,UINavigationControllerDelegate

         接着设置返回的代理:
            self.navigationController?.interactivePopGestureRecognizer?.delegate = self

        在前一个界面吊机跳转的地方通过

    self.navigationController?.pushViewController(要跳转的视图控制器的实例, animated: true)

    就可以实现了

    不过有时候我们还需要在顶部导航上加一个返回的图片按钮,在点击的时候实现和滑动返回同样的功能,也很简单,在设置返回的点击事件时,这样写:

         self.navigationController?.popViewController(animated: true)

    有时我发现在点击返回或者滑动返回时无法响应,就是返回不了,我有遇到过,不过我是用这种方式处理的,加一个方法协议中的函数即可:

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            if (gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer) {
                //只有二级以及以下的页面允许手势返回
                return self.navigationController!.viewControllers.count > 1
            }
            return true
    }

    3、在新手写布局界面的时候,有时候遇到前一个页面和后一个页面在跳转的时候,前一个页面的顶部导航栏会影响后一个顶部导航栏,虽然我在后一个界面设置了新的导航栏样式或者颜色,但是我在滑动返回时,返回了一般但是我又不想返回了,又回到后一个页面时,这时会发现,当前的顶部导航栏已经被前一个页面的顶部导航栏影响了,颜色可能变成前一个导航栏的样式了,其实这个也好解决,就是需要知道视图控制器的生命周期即可实现,

       解决办法:我们知道视图控制器有好几个生命周期,其中一个生命周期是 视图将要显示出现的时候(viewWillAppear(_ animated: Bool)) 这个重写的函数,我就可以处理了,我们只需要把我们要初始化的导航栏样式全部写在这个生命周期函数中,就可以解决这个问题了,

     

    注:我是ios的新手,都是自学swift的,如果有大神请路过,切勿喷我们新手菜鸟!如果好的意见或者建议可以指点更好!

     

    展开全文
  • DEMO的github地址:https://github.com/YYProgrammer/YYPhotoBrowserLikeWX效果如下图效果图.gif实现图片组的浏览,包含捏合缩放、双击缩放...架构设计下文称下图中左边的界面界面A,右边为界面BA-B.jpeg界面A只是一
        

    点击上方“iOS开发”,选择“置顶公众号”

    关键时刻,第一时间送达!

    640?wxfrom=5&wx_lazy=1

    0.gif?wxfrom=5&wx_lazy=1


    DEMO的github地址:https://github.com/YYProgrammer/YYPhotoBrowserLikeWX


    效果如下图


    ?wx_fmt=gif&wxfrom=5&wx_lazy=1

    效果图.gif


    • 实现图片组的浏览,包含捏合缩放、双击缩放、单击退出、向下拖拽退出等。

    • 重点是“向下拖拽退出”的实现。


    架构设计


    下文称下图中左边的界面为界面A,右边为界面B


    ?wx_fmt=jpeg

    A-B.jpeg


    界面A只是一个用来测试的界面,界面B才是图片浏览器,架构设计主要针对界面B。主要需要考虑以下几个点:


    • 界面B的结构:N张图片需要左右滑动、图片本身需要缩放、N种手势交互、后期额外控件的添加等。

    • A到B、B到A的转场动画。

    • 重点:向下拖拽的交互怎么实现


    界面B的结构


    • N张图片需要左右滑动:必然需要UIScrollView或其子类(UICollectionView),来放所有图片。

    • 图片本身需要缩放:所以图片本身需要一个UIScrollView包装起来用于做缩放。

    • N种手势交互:UIScrollView本身带有很多手势,再往上添加手势不妥,所以应当创建个UIView,UIView里有UIScrollView,手势加在UIView上,例如单击、双击等。

    • 后期额外控件的添加:


    ?wx_fmt=jpeg

    额外控件.jpeg


    例如上图红圈的控件,明显不能添加到UIScrollView中否则就跟着滑走了。


    最终设计如下图:


    ?wx_fmt=jpeg

    结构示意.jpeg


    • 蓝色是个scrollview,里面放图片,这样可以缩放图片。(demo中我把它封装成了YYPhotoBrowserSubScrollView)

    • 绿色是个scrollview,里面放蓝色scrollview,这样可以实现左右滑动翻页。(demo中我把它封装成了YYPhotoBrowserMainScrollView)

    • 红色是个控制器的view,这样做可以随意添加额外控件,而且控制器的话,也方便做界面A-界面B的转场动画(demo中对应YYPhotoBrowserViewController)。

    • 消息传递我采用的代理模式。


    转场动画


    这里B是modal出的控制器,我把转场效果交给了转场代理transitioningDelegate,转场动画具体做法可以参考文章:http://www.jianshu.com/p/a65d3463f4bc


    值得一提的是,拖拽时背景颜色透明,出现A的界面。换句话说,B被present之后,A并没有消失。这需要设置一个属性


    B.modalPresentationStyle = UIModalPresentationOverCurrentContext;


    重点:向下拖拽的交互的实现


    控件简介


    结合上图,拖拽事件发生在蓝色这一层。


    蓝色是个UIView(YYPhotoBrowserSubScrollView),添加了子控件UIScrollview(demo中对象命名为mainScrollView),mainScrollView的宽高占满了YYPhotoBrowserSubScrollView。mainScrollView中有UIImageView。


    双击手势添加给YYPhotoBrowserSubScrollView,双击后改变mainScrollView的zoomScale(缩放比例系数)来实现缩放,单击手势也添加给YYPhotoBrowserSubScrollView,单击后通知代理-绿色控件,绿色再通知红色控制器,控制器退回。


    需求介绍


    用户向上拖拽时,图片向上移动(即正常的scrollview的滚动效果,结合demo中第一张长图片查看)。


    向下拖拽到最顶部并持续向下拖拽时,图片遂手势移动,并变小,背景逐渐透明。松手瞬间,如果手势是向下移动的,B页退出,如果手势是向上移动的,图片回到原来的位置


    解决方案分析


    那么问题来了,拖拽的交互理所当然动用手势-UIPanGestureRecognizer,添加给谁呢?


    首先我们来看一下一个手势发生时,发生了哪些事情:


    1、生成一个UIEvent事件;


    2、通过事件响应链查找最合适的事件执行者;


    3、调用事件执行者绑定的手势事件。


    所以,手势所绑定的事件在执行前,会先通过逐级查找的方式,找到最适合响应手势的控件,再执行其方法,流程如下图(白色原点处发生点击)


    ?wx_fmt=jpeg

    事件响应链.jpeg


    图中控件与上面的结构图的控件一致,蓝色线是向下询问过程,橙色是返回结果的过程。


    询问过程:


    1、application:window你好,我收到一个事件(UIEvent),是在点你身上的,你看一看具体是你哪个孩子(subview)来响应,问好了告诉我。


    2、window:我确认了一下,我是可见的(hidden != NO && alpha >= 0.01),我是可点击的(userInteractionEnabled != NO),而且点击的点确实在我身上([self pointInside:point withEvent:event] == YES),那么,我来遍历一下我的孩子们(subview),看看谁最合适,如果没有的话,那就是我了。


    3、4、5、同上。


    返回过程:


    1、UIImageView:我不能被点击。


    2、UIScrollview:我的孩子都不能响应,那就是我了。


    3、YYPhotoBrowserMainScrollView:UIScrollview可以。


    4、5、同上。


    最后蓝色那个UIScrollview就成了事件的响应者。


    其实这个询问和返回的过程,就是UIView里的方法


    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event


    按系统流程重写的话,内部过程如下:


    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

    {

        // 1.判断当前控件能否接收事件

        if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;

         

        // 2. 判断点在不在当前控件

        if ([self pointInside:point withEvent:event] == NO) return nil;

         

        // 3.从后往前遍历自己的子控件(后添加的视图在上面,在上面优先响应)

        NSInteger count = self.subviews.count;

        for (NSInteger i = count - 1; i >= 0; i--)

        {

            UIView *childView = self.subviews[i];

            //把当前控件上的坐标系转换成子控件上的坐标系

            CGPoint childP = [self convertPoint:point toView:childView];

            //让subview继续找它的subview

            UIView *fitView = [childView hitTest:childP withEvent:event];

            if (fitView)//寻找到最合适的view

            {

                return fitView;

            }

        }

         

        // 循环结束,表示没有比自己更合适的view

        return self;

    }


    然后,再调用响应者绑定的对应方法去执行,并且在调用时会将本次触摸相关的等信息装进UIGestureRecognizer里作为参数。


    现在,我们来看一下这几个不可行的方案:


    • 添加一个pan手势给UIImageView,在手势事件中判断手势方向,如果使向上拖拽,把事件传递给scrollview,如果是向下,做“向下拖拽退出”交互效果。

      不可行原因:

      要判断手势方向,只能在手势事件中进行(hitTest中无法通过携带的UIEvent参数判断方向),通过方向来改变响应者,而要改变手势响应者,只能在hitTest方法中,但hitTest是在手势事件执行前,所以已经确定了UIImageView为响应者,再想改变响应者,UIImageView就会中断对事件的响应,本次触摸事件就宣告结束,需要再次抬起手指,重新下拉,生成新的事件,这个时候才能让scrollview来响应。

    • 重写scroolview的pan手势的绑定事件。如果是向上拖动,就按系统的交互写,如果是向下,就做“向下拖拽退出”交互效果。

      无论是新建一个pan手势覆盖掉scroolview自带的,还是找到它自带的pan手势打印出它绑定的方法(没记错的话叫handlePan:)然后重写,还是自己用UIView的子类实现一个自定义Scrollview,都算作重写,因为都要自己实现系统的交互效果。

      不可行原因:

      理论上不是不可行,是非常难。因为系统交互上,不只是单纯的手指移动,内容跟着动,还有:例如,快速滑动页面后松手,页面会持续滑动并以一个加速度做系数来减速直到停止,这个加速度怎么算?又如:内容滚到顶部后持续下拉再松手,会像弹簧一样弹回去,回去的速度是变化的,这里的加速度又是多少?


    可行方案


    思考题做到这里,其实答案已经很接近了。


    所有拖动的交互都离不开pan手势UIPanGestureRecognizer,所以UIScrollview既然能在手指移动时做事儿,那它也离不开UIPanGestureRecognizer。


    翻看UIScrollview的.h文件不难发现,它其实已经暴露了它的pan手势(不暴露就runtime遍历属性,总能找到想要的)。


    ?wx_fmt=jpeg

    h文件.jpeg


    上文说到,调用手势绑定事件时,会把触摸相关的信息放进手势对象里,所以手指在scrollview里移动时,就能从它的panGestureRecognizer拿到我们想要的信息:手指移动路径,就能根据这些数据,做想要的效果。


    所以方案如下:当scrollview在顶部并向下拖拽时,隐藏scrollview中本来的UIImageview,造一个一模一样的用来移动的imageview。获取到scrollview的panGestureRecognizer的手指位置信息,移动并缩放图片,通知代理设置控制器背景透明度。手指松开时,根据手指瞬间方向判断是否需要退出页面,并执行相应操作。


    难点解决


    • 手势绑定事件的方法在父类中,怎么实时监控手势发生并移动了呢?怎么监听手势结束呢?

      当然是用到UIScrollview的代理方法。


    /** scrollview正在滚动 */

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView;   

    /** scrollview即将结束拖拽 */

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset;


    这里需要注意的是,如果图片没有屏幕大,那么scrollview的contentSize是小于frame的,这个时候并不能拖拽,代理方法自然也不执行。需要设置scrollview的属性:


    /** 总是有弹簧效果 */

    _mainScrollView.alwaysBounceVertical = YES;

    _mainScrollView.alwaysBounceHorizontal = YES;//这是为了左右滑时能够及时回调scrollViewDidScroll代理


    注意左右的弹簧属性也要设置,否则向下拖动交互进行中,如果用户开始左右拖动,而mainScrollView不能左右拖动,那代理方法不会执行,会造成图片卡住不动的感觉。


    • 造跟着手指动的imageView时,初始frame的计算

      其实不算很难,但是要场景要考虑全面,因为在拖动时,图片可能已经是放大状态。


    - (void)saveFrameBeginPan

    {

        imageWidthBeforeDrag = self.mainImageView.yy_width;//开始时的高

        imageHeightBeforeDrag = self.mainImageView.yy_height;//开始时的宽

        //计算图片Y需要考虑到图片此时的高,如果足够高时,交互发生时y一定是0

        CGFloat imageBeginY = (imageHeightBeforeDrag < kMainScreenHeight) ? (kMainScreenHeight - imageHeightBeforeDrag) * 0.5 : 0.0;

        imageYBeforeDrag = imageBeginY; //+ imageHeightBeforeDrag * 0.5;

        //centerX需要考虑到offset

        scrollOffsetX = self.mainScrollView.contentOffset.x;

        CGFloat imageX = -scrollOffsetX;

        imageCenterXBeforeDrag = imageX + imageWidthBeforeDrag * 0.5;

    }


    为什么是y值加centerX的值?


    因为这样图片缩小的效果是往图片最中间缩。


    其它小细节


    • 双手捏合来缩放图片时,也会调用代理scrollViewDidScroll

      解决:根据手势的手指数>1判断是否做交互,另外还可以设置一个变量来记录是不是正在缩放。

    • 向下拖拽时向左右滑动会出现上一张/下一张图片的边缘

      解决:拖拽时通知代理隐藏其它图片,结束时显示出来。

    • 手势拖动时,其实scrollview正在被拖动,里面的图片也就正在移动,图片弹回去时,位置就变化了,会有一个瞬移的感觉

      解决:拖动开始记录下offset,结束拖动时赋值回去。

    • 松开时怎么判断是否返回

      解决:在拖动时记录瞬间的方向,即如果当前手势点的y大于之前的,解释向下移动,松开就要退出页面。否则不退出页面。甚至还可以加一个,如果只像下拉了一丢丢,就不退出页面。

    • 当scrollview的offset.y小于0时才执行交互代码,那如果向下拉了,不松手又向上拉,此时offset.y就大于0了,那不就不执行代码了,图片不就卡住不动了吗?

      解决:设置变量来记录是否正在下拉,拉动开始是为yes,结束时为no,当offset.y<0或者变量为yes,就执行下拉。

    • 小细节太多了。。。。


    实战效果


    ?wx_fmt=gif

    项目效果.gif


    其它


    • demo地址:https://github.com/YYProgrammer/YYPhotoBrowserLikeWX

    • 项目中用到的动画用的pop框架,以及转场动画的做法,在这里可以看到详解:http://www.jianshu.com/p/a65d3463f4bc



    640?

    • 作者:YY程序猿

    • 链接:http://www.jianshu.com/p/a62d1546f648

    • iOS开发整理发布,转载请联系作者授权

    0.gif

    0?【点击成为Android大神】

    展开全文
  • iOS开发从入门到精通 基于Xcode9和Swift4视频培训教程,本教程手把手教您学习Xcode9和Swift4语言!一看就懂,一学就会! 视频教程拥有180节课程,包含iOS开发基础知识、数据处理、网络访问、多线程、社会化分享、...
    iOS开发从入门到精通 基于Xcode9和Swift4视频教程—11966人已学习 
    课程介绍    
    201708171532285725.png
        iOS开发从入门到精通 基于Xcode9和Swift4视频培训教程,本教程手把手教您学习Xcode9和Swift4语言!一看就懂,一学就会! 视频教程拥有180节课程,包含iOS开发基础知识、数据处理、网络访问、多线程、社会化分享、CoreImage、CoreText、面部检测、Storyboard技巧、关键帧动画、本地通知、陀螺仪相机定位设备、本地化、IAP内购实现营利、App上传审核等超多干货,以及ARKit、CoreML、颜色集、无线调试等iOS11新特性!
    课程收益
        理解和掌握基于Xcode9和Swift4的移动开发技术中的高级、实用内容。
        教程特点:
        1、语言简洁、精练、瞄准问题的核心所在,减少对思维的干扰,并节省您宝贵的时间;
        2、完美贴心的操作提示,让您的眼睛始终处于操作的焦点位置,不用再满屏找光标;
        3、每个视频都很短小精悍,即方便于您的学习和记忆,也方便日后对功能的检索。
    讲师介绍
        李发展更多讲师课程
        10年以上IT行业工作经验、三年以上IT行业教学经验。丰富的项目经验和授课经验,授课形式不拘一格。熟悉JAVA,iOS,Swift,平面设计、网页设计、Javascript开发等技术。代表作品:拥有百万下载量、千份五星好评的iOS应用《互动教程 for Photoshop》、《互动教程 for Xcode》、《互动教程 for Illustrator》、《互动教程 for Pages》等。
    课程大纲
      第1章:认识Xcode9
        1.第一课:iOS项目模板的介绍  6:55
        2.您的第一个iOS工程项目  2:36
        3.使用资源文件夹导入并管理图片素材  3:33
        4.检测模拟器在各个方向上的切换  2:39
        5.设置项目的属性  3:20
        6.iOS模拟器的基本使用方法  2:38
        7.使用不同设备类型的iOS模拟器  3:05
        8.使用iOS模拟器演示App的生命周期  3:29
        9.Xcode左侧界面介绍一  5:21
        10.Xcode左侧界面介绍二  2:26
        11.Xcode右侧界面介绍  3:41
        12.Xcode代码区的样式设置  1:13
        13.Xcode声音效果的设置  1:38
        14.快速查找并打开文件  1:42
        15.快速更改同名变量  1:23
        16.将代码段提取为方法  1:30
        17.代码的查找和替换  1:27
        18.代码编写的自动补全功能  3:27
        19.代码方法块的折叠与展开  1:57
        20.代码语法颜色样式的设置  2:39
        21.几种在控制台输出日志的方式  2:07
        22.代码的Debug调试  2:03
        23.在顶部状态栏显示风火轮  1:24
        24.为应用程序添加图标  2:29
        25.读取iOS应用的配置信息  2:38
      第2章:视图与视图控制器
        1.UIView视图的基本使用  2:10
        2.UIView视图的层次关系  2:23
        3.UIView视图的基本操作  5:30
        4.给图像视图添加边框效果  2:03
        5.给图像视图添加圆角效果  1:56
        6.给图像视图添加阴影效果  2:01
        7.UIView视图的渐变填充  2:07
        8.UIView视图的纹理填充  2:12
        9.CGAffineTransform仿射变换的使用  1:59
        10.UITapGestureRecognizer手势之单击  3:13
        11.UITapGestureRecognizer手势之长按  3:12
        12.UITapGestureRecognizer手势之双击  3:16
        13.视图控制器和滚动视图  10:54
        14.选项卡(标签)视图控制器的使用  5:59
        15.导航视图控制器的使用  5:27
        16.导航控制器的导航栏和工具栏  3:48
        17.导航控制器的入栈和出栈  6:51
        18.导航控制器的的导航栏样式  1:50
        19.自定义导航控制器的导航按钮  3:21
      第3章:常用控件的使用
        1.UIButton控件的使用  3:45
        2.UIButton图片按钮的使用  4:03
        3.UILabel文本标签的使用  2:07
        4.UILabel文本标签的自动换行  1:59
        5.UILabel自定义文字样式  4:06
        6.UISwitch开关控件的使用  2:51
        7.UIStepper控件的使用  3:39
        8.UITextField控件的使用  3:35
        9.普通警告窗口的使用  2:50
        10.动作表样式警告窗口的使用  3:18
        11.UIDatePicker日期时间选择器  4:00
        12.环形进度条控件的使用  2:44
        13.使用UIWebView控件加载网页  1:46
        14.使用网页视图加载本地HTML  1:32
        15.使用MKMapView加载简单地图  1:42
        16.为MKMapView指定地理坐标  2:08
        17.在地图视图上显示提示框  2:46
        18.将地理坐标转换为实际地名  1:54
        19.使用UITableView制作简单表格  3:22
        20.设置UITableView单元格的高度  3:27
        21.设置UITableView单元格图标  5:01
        22.设置UITableView的数据源  3:39
        23.设置UITableView单元格背景色  3:55
        24.UITableView滑动到指定单元格  4:00
        25.UITableView单元格间隔背景色  3:39
        26.自定义单元格的Accessory样式  4:20
        27.删除UITableView单元格  4:50
        28.插入UITableView单元格  4:46
        29.调整UITableView单元格的顺序  4:55
      第4章:多媒体相关技术
        1.使用图形上下文按一定比例缩放图片  2:57
        2.使用图形上下文转换图片为灰度图  3:11
        3.CoreImage设置图片的单色效果  2:32
        4.使用CoreImage更改图片的色相  2:06
        5.CoreImage给图片添加马赛克效果  2:06
        6.使用UIBlurEffect添加模糊效果  2:28
        7.遍历系统提供的所有滤镜  1:55
        8.CATransaction的渐变动画  2:09
        9.CATransaction的入场动画  1:58
        10.UIView视图的动画块  3:29
        11.UIView视图卷曲动画的制作  3:25
        12.检测UIView视图动画的结束事件  4:29
        13.使用UIImageView制作帧动画  2:29
        14.使用SystemSoundId播放简短声音  2:04
        15.使用AudioPlayer播放音乐  2:40
        16.实现音乐的背景播放功能  3:49
        17.使用MediaPlayer框架播放影片  3:50
      第5章:数据处理、iOS11新特性
        1.程序沙箱结构中常用的几个目录  4:28
        2.文件夹的创建  2:04
        3.创建各种类型的文件  5:09
        4.对文件夹进行遍历操作  2:04
        5.复制、移动和删除文件  6:03
        6.退出系统前的事件处理  1:55
        7.检测App是否首次运行  3:06
        8.读取和解析Plist属性列表文件  3:42
        9.通过代码创建Plist文件  1:59
        10.NSKeyedArchiver存储解析数据  5:21
        11.创建CoreData实体并插入数据  7:14
        12.查找CoreData中的数据  3:12
        13.编辑CoreData中的数据  3:13
        14.删除CoreData中的数据  3:28
        15.单例模式的使用  3:16
        16.解析Xml文档  5:10
        17.解析Json文档  2:27
        18.与设计师的心灵沟通  4:38
        19.iOS11新特性 - 颜色集的使用  6:07
        20.iOS11新特性 - CoreML机器学习框架  4:30
        21.iOS11新特性 - ARKit增强现实  7:05
        22.利用OCR技术识别信用卡号码  11:54
        23.UITesting界面测试功能的使用  3:15
        24.iOS11新特性 - 真机无线调试  1:56
      第6章:网络、多线程与社会化分享
        1.检测网络的连接状态  3:01
        2.使用UIApplication打开网页  1:20
        3.使用UIApplication拨打电话  1:22
        4.使用UIApplication发送短信  1:18
        5.使用UIApplication发送邮件  1:17
        6.使用UIApplication打开地图  1:56
        7.使用邮件撰写视图控制器编写邮件  5:06
        8.使用同步Get的方式查询某地天气  3:45
        9.使用异步Get的方式查询网页源码  2:07
        10.使用异步Get的方式查询优酷信息  5:43
        11.使用同步Post的方式查询IP信息  9:27
        12.使用异步Post的方式查询IP信息  4:05
        13.使用异步的方式下载网络图片  2:15
        14.URLSession将地名转为地理坐标  3:40
        15.使用URLSession下载图片  3:47
        16.使用URLSession显示下载进度  6:15
        17.使用URLSession上传图片至服务器  1:58
        18.PerformSelector消息处理方法  3:19
        19.PerformSelector方法的延迟执行  2:59
        20.使用Timer执行定时任务  1:44
        21.使用Thread暂停动作的执行  2:53
        22.使用GCD多线程技术下载图片  2:29
        23.多线程的同步与异步  2:51
        24.使用微博开放平台并获得应用key  2:49
        25.使用QQ开放平台并获得应用key  3:58
        26.使用微信开放平台并获得应用key  3:16
        27.注册ShareSdk并获得对应的key  3:33
        28.ShareSdk的下载安装及配置  8:45
        29.实现ShareSdk的社会化分享功能  5:36
      第7章:实用进阶内容
        1.隐藏顶部的状态栏  2:00
        2.列出设备上所有的字体  1:29
        3.给代码方法添加宏注释  2:16
        4.计算两个日期间的差值  2:17
        5.正则表达式的使用  3:37
        6.在Swift中调OC类和方法  3:53
        7.使用Xcode的版本管理功能(SCM)  3:28
        8.实现App的Settings设置  6:03
        9.陀螺仪设备的使用  4:18
        10.定位设备的使用  3:13
        11.系统本地通知的创建  4:35
        12.从系统相册中读取图片  4:42
        13.调用相机并获取拍摄后的图片  4:44
        14.使用CoreText框架创建富文本  3:02
        15.截取当前屏幕上的显示内容  2:46
        16.给图片添加水印效果  4:54
        17.使用CGBlendMode改变图片颜色  6:14
        18.图像中人物的面部检测  4:05
        19.使用Quarz2d绘制自定义图形  5:15
        20.创建位移关键帧动画  3:05
        21.查看运行中程序的元素层级  4:35
        22.在故事板中设置初始视图控制器  3:53
        23.在故事板中使用标签和按钮控件  6:18
        24.在故事板中使用图像视图控件  10:02
        25.在故事板中使用表格控件  7:07
        26.在故事板中使用集合控件  7:24
        27.故事板的常用项目结构  6:08
        28.多个故事板中的页面跳转  8:50
        29.使用Segue跳转页面并传递参数  11:19
        30.在故事板中适配页面至各分辨率  22:53
        31.对Storyboard进行本地化处理  4:14
        32.App内容文本的本地化  6:31
        33.在iTunesConnect中创建新App  8:51
        34.为新的App添加IAP内购项目  4:23
        35.为内购添加沙箱技术测试人员  2:38
        36.IAP内购功能的具体实现和测试  10:36
        37.项目的打包上传和提交审核  10:30
    大家可以点击【查看详情】查看我的课程
    展开全文
  • Swift之微信朋友圈图片浏览器 最近闲来无事,突然对微信, 微博, QQ等社交APP的九宫格的图片浏览功能非常感兴趣, 最近就尝试着研究了一下: 这里先附上Demo地址 在介绍项目之前, 先介绍三个基础知识 CATransition转场...

    Swift之微信朋友圈图片浏览器

    最近闲来无事,突然对微信, 微博, QQ等社交APP的九宫格的图片浏览功能非常感兴趣, 最近就尝试着研究了一下:

    这里先附上Demo地址

    • 在介绍项目之前, 先介绍三个基础知识
      • CATransition转场动画
      • ViewController自定义转场
      • UIBesization贝塞尔曲线

    一. CATransition转场动画

    示例代码

    //4. 转场动画
    let transition = CATransition()
    transition.type = transitionType
    transition.subtype = isNext ? kCATransitionFromRight : kCATransitionFromLeft
    transition.duration = 1
    downloadImage(url: imageURL)
    baseImage.layer.add(transition, forKey: "transition")

    更多关于该动画的详细介绍, 可参考iOS出门必备之CoreAnimation(核心动画)中第七种CA动画, 故这里不多做介绍

    二. ViewController自定义转场

    从iOS7开始,苹果更新了自定义ViewController转场的API,会用到的几个协议protocol:

    • 描述ViewController转场的:
      • UIViewControllerTransitioningDelegate
      • UINavigationControllerDelegate
      • UITabBarControllerDelegate
    • 定义动画内容的
      • UIViewControllerAnimatedTransitioning
      • UIViewControllerInteractiveTransitioning
    • 表示动画上下文的
      • UIViewControllerContextTransitioning

    1-1. 描述ViewController转场的

    • 为什么苹果要引入这一套API?因为在iOS7之前,做转场动画很麻烦,要写一大堆代码在ViewController中。
    • 引入这一套API之后,在丰富功能的同时极大程度地降低了代码耦合,实现方式就是将之前在ViewController里面的代码通过protocol分离了出来。
    • 顺着这个思路往下想,实现自定义转场动画首先需要找到ViewController的delegate。
    • 苹果告诉我们切换ViewController有三种形式:
      • UITabBarController内部切换
      • UINavigationController切换
      • present ViewController
      • 这三种方式是不是需要不同的protocol呢?

    1-2. 详解Protocol

    • UIViewControllerTransitioningDelegate 自定义模态转场动画时使用。

      • 设置UIViewController的属性transitioningDelegate
      weak open var transitioningDelegate: UIViewControllerTransitioningDelegate?
    • UINavigationControllerDelegate 自定义navigation转场动画时使用

      • 设置UINavigationController的属性delegate
      weak open var delegate: UINavigationControllerDelegate?
    • UITabBarControllerDelegate自定义tab转场动画时使用

      • 设置UITabBarController的属性delegate
      weak open var delegate: UITabBarControllerDelegate?

    实际上这三个protocol干的事情是一样的只不过他们的应用场景不同罢了。我们下面以UINavigationControllerDelegate为例,其他的类似

    • UINavigationControllerDelegate主要的方法
        @available(iOS 7.0, *)
        optional public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?
    
    
        @available(iOS 7.0, *)
        optional public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
    
    • 两个方法分别返回UIViewControllerInteractiveTransitioningUIViewControllerAnimatedTransitioning,它们的任务是描述动画行为(转场动画如何执行,就看它俩的)。
    • 从名字可以看出,这两个protocol的区别在于是否是interactive的。如何理解?
    • interactive动画可以根据输入信息的变化改变动画的进程。例如iOS系统为UINavigationController提供的默认右滑退出手势就是一个interactive 动画,整个动画的进程由用户手指的移动距离控制

    1-3. UIViewControllerInteractiveTransitioning协议

    定义了两个属性可以做到平滑过渡
    - completionCurve: 交互结束后剩余动画的速率曲线
    - completionSpeed: 交互结束后动画的开始速率由该参数与原来的速率相乘得到,实际上是个缩放参数,这里应该使用单位变化速率(即你要的速率/距离)。
    - 注意:
    - completionSpeed会影响剩余的动画时间,而不是之前设定的转场动画时间剩下的时间;
    - 当completionSpeed很小时剩余的动画时间可能会被拉伸得很长,所以过滤下较低的速率比较好。
    - 如果不设置两个参数,转场动画将以原来的速率曲线在当前进度的速率继续。
    - 不过从实际使用效果来看,往往不到0.5s的动画时间,基本上看不出什么效果来

    1-4. 定义动画内容的UIViewControllerAnimatedTransitioning

    • 必须实现的方法
    //返回动画的执行时间
    public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
    
    //处理具体的动画  
    public func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
    

    1-5. 表示动画上下文UIViewControllerContextTransitioning

    • UIViewControllerContextTransitioning提供了一系列方法
    • 是唯一一个我们不需要实现的Protocol
    • 下面是一些我们常用的属性和方法:
    //转场动画发生在该View中    
    public var containerView: UIView { get }
    
    //上报动画执行完毕
    public func completeTransition(_ didComplete: Bool)
    
    //根据key返回一个ViewController。我们通过`FromViewControllerKey`找到将被替换掉的VC,通过`ToViewControllerKey`找到将要显示的VC
    public func viewController(forKey key: UITransitionContextViewControllerKey) -> UIViewController?
    
    //根据key返回一个view, 我们通过from找到将要消失的view, 根据to找到将要弹出的view
    @available(iOS 8.0, *)
    public func view(forKey key: UITransitionContextViewKey) -> UIView?
    

    1-5. UIViewControllerTransitioningDelegate自定义模态转场时使用

    // 该方法是告诉系统,弹出动画交给谁来处理
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        isPresent = true
        return self
    }
    
    // 该方法是告诉系统,消失动画交给谁来处理
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        isPresent = false
        return self
    }
    

    三. 图片浏览器项目介绍

    1. 项目结构Alamofire + MVVM

    框架结构

    图片浏览器.gif

    2. 自定义ViewController的弹出和消失动画

    2-1. 自定义ViewController弹出和消失的Protocol

    //MARK: 自定义协议
    protocol JunBrowsePresentDelefate: NSObjectProtocol {
        /// 1. 提供弹出的imageView
        func imageForPresent(indexPath: IndexPath) -> UIImageView
    
        /// 2. 提供弹出的imageView的frame
        func startImageRectForpresent(indexPath: IndexPath) -> CGRect
    
        /// 3.提供弹出后imageView的frame
        func endImageRectForpresent(indexPath: IndexPath) -> CGRect
    }
    
    protocol JunBrowserDismissDelegate {
        /// 1.提供推出的imageView
        func imageViewForDismiss() -> UIImageView
    
        /// 2. 提供推出的indexPath
        func indexPathForDismiss() -> IndexPath
    }
    

    2-2. 遵循协议

    • UIViewControllerTransitioningDelegate告诉系统弹出/消失动画的处理页面
    • UIViewControllerAnimatedTransitioning
      • 需要返回动画的执行时间
      • 需要在弹出和消失页面的时候分别执行不同的动画
    //MARK: UIViewControllerTransitioningDelegate
    extension PhotoBrowseAnimation: UIViewControllerTransitioningDelegate {
        // 该方法是告诉系统,弹出动画交给谁来处理
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            isPresent = true
            return self
        }
    
        // 该方法是告诉系统,消失动画交给谁来处理
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            isPresent = false
            return self
        }
    }
    
    
    //MARK: 继承AnimatedTransitioning协议
    extension PhotoBrowseAnimation: UIViewControllerAnimatedTransitioning {
        //返回动画的执行时间
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.6
        }
    
        //处理具体的动画
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            isPresent ? presentAnimation(transitionContext) : dismissAnimation(transitionContext)
        }
    }
    

    2-3. 图片列表界面

    1. 在点击需要展示的imageView的时候,调用下面的方法

    // MARK:- 弹出照片浏览器
    extension JunScrollViewController {
        fileprivate func presentPhotoBrowse(indexPath: IndexPath) {
            //1. 创建图片浏览器
            let photoBrowseVC = BrowseViewController(images: imageVM.imageArray, currentIndexP: indexPath)
            //2. 设置弹出样式为自定义
            photoBrowseVC.modalPresentationStyle = .custom
            //3. 设置转场动画代理
            photoBrowseVC.transitioningDelegate = photoAnimation
            //4. 设置broseAnimation的属性
            photoAnimation.setProperty(indexPath: indexPath, self, photoBrowseVC)
            //5. 弹出图片浏览器
            present(photoBrowseVC, animated: true, completion: nil)
        }
    }
    

    2. 遵循并实现自定义的协议方法

    //MARK: JunBrowsePresentDelefate
    extension JunScrollViewController: JunBrowsePresentDelefate {
        func imageForPresent(indexPath: IndexPath) -> UIImageView {
            let imageV = UIImageView()
            imageV.contentMode = .scaleAspectFill
            imageV.clipsToBounds = true
            //设置图片
            imageV.kf.setImage(with: URL(string: imageVM.imageArray[indexPath.item].pic74), placeholder: UIImage(named: "coderJun"))
            return imageV
        }
    
        func startImageRectForpresent(indexPath: IndexPath) -> CGRect {
            // 1.取出cell
            guard let cell = imageCollection.cellForItem(at: indexPath) else {
                return CGRect(x: imageCollection.bounds.width * 0.5, y: kScreenHeight + 50, width: 0, height: 0)
            }
    
            // 2.计算转化为UIWindow上时的frame
            return imageCollection.convert( cell.frame, to: UIApplication.shared.keyWindow)
        }
    
        func endImageRectForpresent(indexPath: IndexPath) -> CGRect {
            //1. 取出对应的image的url
            let imageUrl = URL(string: imageVM.imageArray[indexPath.item].pic74)!
    
            //2.从缓存中取出image
            var image = KingfisherManager.shared.cache.retrieveImageInDiskCache(forKey: imageUrl.absoluteString)
            if image == nil {
                image = UIImage(named: "coderJun")
            }
    
            // 3.根据image计算位置
            let imageH = kScreenWidth / image!.size.width * image!.size.height
            let y: CGFloat = imageH < kScreenHeight ? (kScreenHeight - imageH) / 2 : 0
    
            return CGRect(x: 0, y: y, width: kScreenWidth, height: imageH)
        }
    }
    

    2-4. 在图片展示界面

    • 遵循并实现相关dismiss协议方法
    • 该协议主要实现viewController返回到该图片对应的IndexPath所在的位置
    //MARK: JunBrowserDismissDelegate
    extension JunTranstionPhotoController: JunBrowserDismissDelegate{
        func imageViewForDismiss() -> UIImageView {
            let imageV = UIImageView()
            imageV.contentMode = .scaleAspectFill
            imageV.clipsToBounds = true
    
            //设置图片
            imageV.image = baseImage.image
            imageV.frame = baseImage.convert(baseImage.frame, to: UIApplication.shared.keyWindow)
    
            return imageV
        }
    
        func indexPathForDismiss() -> IndexPath {
            return IndexPath(item: currentIndex, section: 0)
        }
    }
    

    GitHubDemo地址

    • 注意:
      • 这里只是列出了主要的核心代码,具体的代码逻辑请参考demo
      • 文中相关介绍有的地方如果有不是很详细或者有更好建议的,欢迎联系小编
    展开全文
  • 我们使用金融软件经常会发现手机锁屏或者长时间未操作就会退出程序或者需要重新输入密码等情况。下面让我们看一下如何实现这种功能。我们知道iOS有一个事件循环机制,也就是大家所说的runloop。我们在对程序进行手势...
  • Swift实现一款天气预报APP(一) 用Swift实现一款天气预报APP(二) 用Swift实现一款天气预报APP(三) 通过前面的学习,一个天气预报的APP已经基本可用了。至少可以查看现在当前的天气情况和未来几个小时的天气...
  • Swift 语法小结

    2016-02-18 15:17:52
    Swift 语法小结 1. Optional 就是枚举  An Optional is just an enum  enum Optional{  case None  case Some(T)  } 2.Array的声明  var a=Array()  var a=[String]()  let
  • Swift 调用 Shell - 优化

    2019-04-20 15:25:22
    之前写过Swift调用Shell1.0 版本的代码,在实际测试中发现1.0版本的调用会导致App内存泄露而Crash。最新代码已维护至Gitlab https://gitlab.com/cyril_j/mutils/blob/master/Swift/Exec_shell.swift 先上代码: /// ...
  • 本文转载自SwiftGG, 原文地址: [使用 Realm 和 Swift 创建 ToDo 应用](http://swift.gg/2015/12/08/building-a-todo-app-using-realm-and-swift/). 同时加上了个别的补充.
  • Swift / Objective_C / Xcode实际开发中可能遇到的小功能小技巧总结<持续添加更新...>
  • 一 部分功能图(后面会完善)二 讲解思路1 项目目录结构搭建2 抽取工具类3 自定义cell4 分层思想5 业务逻辑三 项目目录搭建和相关配置1 采用搭建搭建结构思路 : MCV模式—-> 1.1 文件夹图片 :2 注意 一 : 当我们在创建...
  • 当手机锁屏时出现在锁屏界面,可以通过滑动打开该App, 在通知中心中出现推送的消息 App图标会有微标值① badgeValue 推送通知提示音 注意: 发送通知时,如果程序正在前台允许,那么推送通知UI就不会显示出来;...
  • TextField退出键盘: 1、sender.resignFirstResponder(); 2、self.view.endEditing(true); 定义Model类时,为了方便编程人员之间的交流,实例化方法需要提供两种 1、init(xxx: XXX); 2、class func modelWithXXX...
  • // 禁止右滑 if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = NO;...
  • 本教程手把手教您学习Xcode8和Swift3语言!一看就懂,一学就会! 视频教程拥有180节课程,包含iOS开发基础知识、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、Core...
  • 从双击或缩放以放大图片,向左或向右滑动以更改Snapchat和Instagram上的场景,所有这些操作均由手势识别器完成。在本次分享中,我们将在iOS中探索一些手势识别器,让您了解它们是什么以及如何使用它们。我是做iOS...
  • 参考:https://www.jianshu.com/p/55bbfbdf78de =============方法一:使用sdwebImage ... 在桥接文件中导入 #import &lt;SDWebImage/UIImageView+WebCache.h&... let imagev:UIImageV...
  • 1.首先把顶部左侧返回按钮隐藏掉 ...//禁止页面左侧滑动返回,注意,如果仅仅需要禁止此单个页面返回,还需要在viewWillDisapper下开放侧滑权限 // 禁用返回手势 if ([self.navigationController res
  • 原文地址:http://www.raywenderlich.com/74904/swift-tutorial-part-2-simple-ios-app 泰然翻译组:永远的微笑。校对:gloryming。...在第一个Swift教程中,你们学习了Swift语言的基础语法,并创建了自己的小费计
1 2 3 4 5 ... 20
收藏数 408
精华内容 163