swift技术文章收藏借鉴

Swift3微博项目笔记(第二部分)

2016-11-02  本文已影响135人  字节码
发布模块
##
 - 点击发布按钮,modal弹出一个控制器,有发布微博、选择相册照片、表情键盘功能
- 1.发布按钮属于单独的模块,新建一个文件来管理,创建一个ComposeViewController,继承自UIViewController,由于界面是固定的,使用XIB描述
- 2.点击发布按钮时,创建ComposeViewController对象,并包装为导航控制器,然后modal弹出
- 3.给导航栏添加【关闭】和【发布】按钮,默认情况下用户没有输入文字时【发布】按钮不能点击‘
- 4.导航标题上有两个Label,上面显示【发微博】,下面显示【开发者的昵称】,由于导航的title只能显示一个Label,所以这里需要自定UIView来添加两个按钮
- 5.创建ComposeTitleView,继承UIView,重写initWithFrame,懒加载这两个Lable,将这两个控件添加到ComposeTitleView中,这里不要设置Frame,因为这两个Label还要有间距,如果直接设置Frame,下面一个控件的Y值就不好计算了,所以可以使用约束,导入SnapKit框架,接下来将控件的属性也封装在里面
- 6.在ComposeViewController中懒加载ComposeTitleView
##
- 7.使用TextView作为输入框,但是TextView在没有输入文字时并没有【占位文字】,需要自定义TextView,往里面添加一个Label子控件作为占位文字
- 8.在XIB上添加TextView,设置约束距离控制器View上下左右为0
- 9.创建一个继承自UITextView的类ComposeTextView,然XIB上的TextView控件的Class成为ComposeTextView
- 10.在awakeFromNib或initWithCoder中初始化,当一个控件从XIB中加载时,会先执行initWithCoder,再执行awakeFromNib方法,用哪个都可以,但是如果是添加子控件用initWithCoder方法,如果是对子控件进行初始化操作用awakeFromNib方法
- 11.懒加载placeHolderLabel控件,将其添加到ComposeTextView中,设置其约束及属性及文字
- 12.设置TextView的文本内容的内边距属性textContainerInset,使用决定文字输入后的文字在什么位置,
- 13.在控制器的ViewDidAppear显示完成的时候让TextView成为第一响应者弹出键盘
- 14.开始输入文字时,占位Label隐藏,可以通过代理或通知,这里我们使用代理,让控制器成为TextView的代理,判断当TextView中有文字就隐藏,没有文字就显示,可以使用textView的hasText方法判断有没有文字,而且此时还要判断是否有文字hasText来决定导航条发布按钮是否可以点击
- 15.滚动textView时,让键盘隐藏,但此时textView并不能滚动,原因:虽然textView继承自UIScrollView,由于当前textView的contentSize内容不够所以不能滚动,但是我们也可以在不设置contentSize的情况下让textView滚动,有两个属性:开启【Bounce horizontally】可以左右滚动,开启【Bounce vertically】可以上下滚动,这两个属性都是UIScrollView的
- 16.调用scrollView的滚动代理方法让textView失去第一响应者即可
##
- 17.实现底部工具栏:
     -(1)在XIB中在TextView底部拖一个UIToolBar,删除ToolBar中的item,拖UIButton进去,因为ToolBar自带的item没有点击时高亮状态,设置约束,距离底、右、左为0,ToolBar高度默认为44
     -(2)在ToolBar中添加几个需要的Button,但是我们需要Button之间有间距,如果使用弹簧的话两边距离控制器view间距会变得很大,如果不希望这两边间距很大,可以使用小技巧:往view两边与按钮之间各拖入一个item,删除item的文字,给item输入几个固定的空格即可
     -(3)当键盘弹出时,让toolBar一起上移:监听键盘即将改变frame的通知
##
- 18.选中照片的布局
     -(1)ToolBar上第一个按钮点击可以选照片
      点击选中照片时:第一先退出键盘,第二弹出一个界面可以选择照片,这个界面并没有将工具栏隐藏及盖上,反而工具栏在最底部,界面上有一个➕按钮,点击后弹出相册可以选照片
     -(2)在XIB上面拖一个CollectionView,让它在ToolBar的后面(不要盖住ToolBar),默认情况下设置约束为左、右、底部(view)、高度为0,目的是默认不显示出来,当点击ToolBar上的选照片按钮时改变CollectionView高度约束让它显示(最好让高度约束为屏幕高度的比例0.65)
     -(3)给CollectionView设置数据源,如果让发布控制器成为其数据源,那发布控制器的代码会很多,所以我们可以自定义UICollectionView,让它来管理XIB的CollectionView,并让它自己成为自己的代理
     -(4)注册cell,XIB中CollectionView上没有cell,storyboard中CollectionView有cell,所以只能通过代码注册cell类型
     -(5)给collectionView设置布局,取出collectionView的布局转为流水布局,设置一共有3列item,每个item的间距为10,计算item的宽度和高度为(屏幕的宽度 - 4个间距) / 3,这里有个问题:item之间的间距太多,但是设置最小间距不好解决,可以设置collectionView的contentInset解决,让边上的内容往里面挤
     -(6)自定义cell类并使用XIB搭建,并让collectionView的cell注册为这个XIB,往XIB上添加两个按钮,一个【➕】按钮,一个【X】按钮,默认【X】按钮隐藏,
     -(7)点击【➕】按钮时弹出照片选择器:需要监听【➕】按钮的点击事件,但是由于cell并不是控制器无法弹出照片浏览控制器,而cell的父控件是collectionView也不是控制器,但collectionView的父控件是发布控制器,这里可以使用代理、闭包、通知,其中一种方式让发布控制器弹出照片浏览控制器,用什么方法会好些呢:由于这里涉及到多层传递,多层之间传递使用通知最好
     -(8)点击【➕】按钮时发布通知,在发布控制器中注册通知,当发布控制器接收到通知后弹出选择照片控制器
     -(9)显示选中的照片:在发布控制器中定义一个UIImage类型的懒加载数组images变量,当选择照片时,将选中的照片添加到这个数组中,在collectionView中定义一个images变量,然后将这个数组赋值给collectionView的images,让collectionView去展示数据,监听collectionView的images发送改变,只要改变就刷新数据
     -(10)在cell中定义一个image变量,监听image发生改变,只要image发生改变就将image设置为➕按钮的背景,在collectionView中给cell的image传值
     -(11)存在问题:collectionView上选择后的照片被压扁了,这里不能通过改变➕按钮的contentModl来解决,因为当前是把照片设置在➕按钮的背景上了,并不是按钮内部的图片上
          解决步骤:
          (1)在XIB中拖一个imageView到加号按钮上面(不是子控件哦),且在删除按钮后面,不能盖住删除按钮,设置这个imageView的contentModl为填充Fill模式,并将其拖线到cell中,然后给其设置图片即可
          (2)在监听cell的image属性发送改变时,当有图片就把图片设置给这个imageView,不要设置给➕按钮了,防止循环利用,没有图片时设置imageView的image为nil
          (3)当有时明明把删除按钮放在了imageView的上面,但是还是不显示删除按钮时,可以尝试在XIB中拖动下imageView的顺序,在拖回去,这一般是小bug
##
- 19.删除选中照片
     -(1)删除选中照片的按钮默认设置为隐藏,并在cell的image监听器中根据只要image不为nil就让删除按钮显示,image为nil时隐藏
     -(2)将删除按钮拖线到cell中,点击删除按钮时删除这张照片,删除照片应该从发布控制器的images数组中删除,删除后刷新表格
     -(3)由于删除按钮的点击事件是在cell类中,要想点击了cell上按钮让控制器去做事情时,可以使用通知,这里就发布一个点击了删除按钮的通知,然后在发布控制器中监听这个通知,接收到通知后将当前点击删除按钮上的image从images数组中删除,然后刷新表格
     -(4)问题:点击删除按钮要删除对应的那个照片,但是那个照片在数组中的索引我们并不知道
         解决方法:
           (1)在发布通知时,将点击的imageView.image通过object参数传出去,
           (2)在接收到通知的方法中,通过object参数获取这个image,当然也可以通过发布通知的userInfo参数传出来,但是userInfo一般适合传多个参数的,所有使用object参数
           (3)通过object参数获取的是AnyObject的可选对象,需要使用guard做校验,获取不到就return,校验的同时并转为UIImage对象
           (4)通过images数组调用indexOf方法将这个image传进去就可以获取这个image在images数组中的下标值(索引),获取的是可选类型,需要使用guard做校验,获取不到就return
     -(5)通过获取的下标值将其从images数组中remove掉
     -(6)重新把移除后的images数组赋值给collectionView的images
     -(7)其实重新赋值完成后,collectionView的images值就会发生变化,此时它的监听器监听到发生改变后就会调用reloadData刷新表格,就会更新界面
##
- 20.点击toolBar上的表情按钮时,切换键盘为表情键盘,再点击表情按钮时,键盘再切换回去,【切换键盘要通过UITextView或UITextField的[inputView]属性设置,当设置为nil时就是默认的普通键盘哦】
     -(1)监听toolBar上表情按钮的点击,拖线到发布控制器中
     -(2)当点击表情按钮时:(1.先退出键盘 2.切换键盘,3.弹出键盘)
     -(3)注意:要想切换键盘,必须要先将键盘退出,才能切换,切换以后再弹出切换好的键盘
     -(4)切换键盘可以通过判断textView的inputView是否为nil,当为nil时就设置为自定义的键盘,不为nil时就让其为nil(nil时键盘为默认的普通键盘),所以可以使用三目运算符做判断
## 
- 21.自定义表情键盘Emoticon
    建议:由于表情键盘做起来比较复杂,可以单独创建一个项目,并与当前项目界面差不多,然后在新的项目中封装好以后,再拖到这个项目中使用即可
     -(1)由于表情键盘上的业务逻辑较为复杂,需要自定义一个控制器来管理键盘表情,让inputView成为控制器的view,并且专门给器创建一个文件夹
     -(2)自定义一个EmoticonViewController类,继承自UIViewController,如果想要把某个单独功能封装起来方便其他项目再次使用的话,最好不要使用XIB
Snip20161002_16.png
   -(3)Emoticon键盘分为两个部分:上面为表情,下面是工具栏(选择表情类型的),上面的部分可以使用collectionView,因为每个表情就可以是一个cell,下面的控件用ToolBar
   -(4)在EmoticonViewController控制器中,添加这两个控件,先进行懒加载,注意collectionView需要布局,懒加载时给其传一个布局,由于frame不确定,所以可以使用CGRectZero
   -(5)在viewDidLoad方法中添加两个子控件,通过代码给子控件设置约束,封装功能或框架最后不要使用第三方框架,不然产生依赖,不方便拿到其他项目中复用
   -(6)注册cell和设置collectionView的数据源为当前控制器
   -(7)设置collectionView的布局,直接在当前控制器中,自定义EmoticonCollectionViewLayout,继承自UICollectionViewFlowlayout
      -(1)重写prepareLayout方法(准备布局时调用),在这个方法中#1先计算每个item的宽高,由于当前需求每个item之间没有间距,且每列有7个item,所有宽高等于屏幕的宽度除以7即可,然后设置为itemSzie,最小间距为0。#2设置collectionView的相关属性
          此时有个问题:每行item之间有间隔,虽然设置了最小间距为0,但是大于0也是成立的,所以产生间隔正常,如果不要这个分割,可以设置collectionView的contentInset,让它的顶部和底部有这个间距内边距,间隔高度的的计算方法:collectionView的高度除以3(共3行)行item的高度,再除以2即可
     注意:如果使用自定义的布局,在创建的collectionView时也要使用这个自定义的布局类来创建,不然等于白做
## 
- 22.表情键盘上的toolBar
    -(1)先定义一个标题数组专门存放toolBar上的标题字符串
    -(2)遍历标题数组,取出每一个标题,遍历时创建UIBarButtonItem添加到toolBar上,并把每个标题设置为UIBarButtonItem的title,绑定每个UIBarButtonItem的tag为遍历的索引
     注意:(1)如果将创建的UIBarButtonItem添加到toolBar的items属性中不能显示toolBar上的按钮时,可以将创建的UIBarButtonItem先添加到一个临时[UIBarButtonItem]类型数组,再将这个临时数组赋值给toolBar的items属性
    -(3)创建UIBarButtonItem时,每添加一个弹簧,但是最后一个不需要弹簧,可以在创建好以后,从toolBar的items数组中删除最后一个
## 
- 23.加载表情数据
     -(1)emoticon表情其实就是字符串,一般存储在一个plist文件中,对应的code就是emotion的字符串,但是需要转换 ,浪小花和默认表情是png图片
     -(2)表情分为:默认表情、emoticon表情、浪小花表情、最近表情,所以创建模型时要有对应的组,
     -(3)创建3个模型:第1个是EmoticonManager模型用来管理所有的组的(4个组),第2个是EmoticonPackage组模型,组里面放的是每一个的表情模型,第3个是Emoticon表情的模型,每一个表情也是一个模型
##
- 24.自定义cell展示表情
##
- 25.每20个表情后面添加一个删除按钮:
     -(1)修改模型:在EmoticonPackage添加模型的代码中,判断当索引为20时,添加一个删除表情按钮模型,并且把索引重置为0
##
- 26.如果是第一中类型表情一共107个,显示5页,每页21个,这样会空两个出来没有表情
解决方法:添加空白表情,拿到所有表情的个数 抹去% 21,当%后的值没有的话,就没有空白,不用添加,当%后有值,就添加21-抹去后的值的个数
注意:最近分组也需要添加空白表情
## 
- 27.当选中一个表情时不光有插入到文本,还有放到最近表情里面
     -(1)监听cell的点击:设置cell的代理方法,
     -(2)取出点击表情模型
     -(3)将点击的表情模型插入到最近分组中,但是需要判断如果是空白表情或删除按钮,只要有其中一个都不需要插入
     -(4)将点击的模型表情插入到最新分组的第0个位置,但是在插入之前要删除一个表情,判断最新分组中有没有包含点击的那个表情,如果有包含表示原来有这个表情,当没有包含原来的表情时,就remove第19个(因为索引从0开始,第20个是删除按钮,所以删除倒数第二个),如果包含原来的表情,就删除自己
##
- 28.点击emoticon表情时,将表情插入到文本输入框中
        这里说的外面是外界调用我封装好的这个emoticon的控制器,内部指的就是emoticonViewController
     -(1)分析:插入的输入框一般在最外界的控制器里面,需要在当我点击这个表情时,将表情回调到外面的控制器中
     -(2)采取闭包的方式回调:在外面封装一个闭包(闭包就是一个{代码块},去内部拿到闭包的引用,之后通过这个闭包的引用来调用闭包、执行闭包
     -(3)点击某个表情时回调到外面:在创建emoticonViewController时,就传进去一个闭包,可以重写emoticonViewController构造函数,在参数中添加一个闭包,因为有可能还有在其他地方使用这个闭包可以emoticonViewController中定义一个属性保存这个闭包,由于需要将emoticon模型传到外界,所以闭包中添加一个emoticon模型参数,注意:自定义控制器的构造函数,必须调用super设计好的构造方法super.init(inbName:nil bundle:nil)
     -(4)在collectionView的代理方法中当点击了表情时,调用闭包并传入点击的表情模型,就完成回调闭包
     -(5)当外界需要拿到emoticonViewController的view设置为键盘时,需要先通过刚刚的自定义构造函数创建,通过里面的闭包的参数就可以拿到内部传递出去的表情
     -(6)注意循环引用:由于在外界要使用这个闭包回调的表情模型参数设置给当前控制器self.textView控件,此时外界就对闭包产生强引用,那内部emoticonViewController也对闭包产生强引用,就会导致循环引用,所以在外界要使用weak self来修饰
     -(7)emoji表情不需要做图文混排,因为本身就是字符串,普通表情需要图文混排
     -(8)插入表情到文本输入框光标所在的位置
        -1.先判断是不是空白表情,如果是就return
        -2.判断是不是删除按钮,如果是先删除光标前面的文字:textView.delegateBackward,然后return
        -3.判断是不是emoji表情,如果是就获取光标所在的位置,再把光标所在的位置替换为emoji表情,然后return
          注意:外界使用时一定要先取出emoticonViewController的view,再给textView设置inputView为它的view,不然不会显示
##
- 29.图文混排实现
     创建图文混排的类是NSTextAttachment,属性字符串的类NSAttributedString,通过创建一个属性字符串时,将NSTextAttachment类的images传进一个属性字符串中,由于属性字符串之间不能相加拼接,还需要创建NSMutableAttributedString可变的属性字符串,然后将图文混排的属性字符串与普通的属性字符串之间拼接,最后将拼接后的属性字符串赋值给控件的attributedText属性
## 
- 30.通过图文混排将普通表情添加到文本输入框中
        -(1).根据表情图片的全路径pngPath创建图文混排的属性字符串
        -(2).如果直接将创建好的图片属性字符串直接赋值给textView的attributedText属性,就会将teextView上所有的文字全部替换掉了,我们想要的效果是,将图片属性字符串替换到光标所在的位置,所以我们需要先拿到textView的attributedText属性,就等于拿到了textView上的所有文本,然后将其转为可变的属性字符串,如果表情太大可以将textView的font取出,将字体的lineHeight设置为图片混排的bounds属性即可
        -存在的问题1:当输入表情后,文字会跟随表情的大小而改变字体大小
        -解决方法:设置表情的大小时,先取出textView的字体用常量保存,设置完成后,再将取出的这个字体赋值回去给textView的font即可
        -存在的问题2:选择某个表情替换到textView的指定位置后,光标跑到文本的最后面了
        -解决方法:将光标设置回原来的位置+1,就是插入的表情后面,设置textView的selectedRange属性
##
- 31.获取表情文字字符串
        -(1)当点击发布按钮时,会将编辑好的文本发送到服务器,假如文本中有表情的话,是不能图片属性字符串将其发送到服务器的,应该将表情替换为对应文字
        -(2)当点击发布按钮时,获取textView的属性字符串,在遍历属性字符串
##    
- 32.封装插入和获取表情的方法:
        插入表情是往textView中插入,获取表情是从textView中获取,由于都是和textView有关系,可以先给textView扩充Extension,再给textView扩充两个方法:给textView插入表情方法和获取textView属性字符串对应的表情字符串方法
##
- 33.项目集成表情键盘
      将单独封装的emoticon拿到项目中使用即可
      - 问题1: 插入表情时,占位文字需要隐藏掉
      - 解决方法: 这是因为插入表情时,并没有触发textView的代理方法,可以在插入表情时,主动调用textView的代理方法
##
- 34.点击发布按钮时,发布一条文字微博
      - (1)到新浪开发者网站找到微博接口,里面有写入接口,找到发布一条微博
      - (2)在网络工具类中,写一个发微博的方法
##
- 35.点击发布按钮时,发布一条图片文字微博
       -(1)如果点击发布按钮发送的是图片微博,需要更换接口为上传拖并发布一条微博,这个接口只能发一张图片,因为当前项目使用的是授权方式,而不是官方api接口
       -(2)在网络工具类中,写一个发送微博并且携带图片的方法
## 
- 36.正则表达式
       -(1)创建正则表达式规则
       -(2)创建正则表达式对象,(一般使用regex常量名),注意:创建时方法后面有throws,是抛出异常,需要使用try? 、try!、try处理异常,一般使用try?,返回的是可选类型需要进行校
       -(3)匹配字符串内容,想整个字符串都进行匹配,可以从0的位置loction开始匹配,到这个字符串长度lenght,switft中要想拿到字符串的,可以通过字符串的characters.count获取,匹配的结果会在数组中返回
       -(4)遍历匹配结果数组,获取结果
       swift中如果字符中写\会报错,可以在\后面在加一个\进行转译就可,也就是两个\\
##
微博表情显示
-(1)分析:微博正文一般会有表情需要显示,但是客户端发送给服务器的一般是类似[哈哈]文字的,其实[哈哈]在表情info.plist中是chs,我们可以通过chs获取表情的pngPath图片路径,通过图片路径创建UIImage对象,在通过UIImage对象创建NSTextAttachment,再根据NSTextAttachment创建属性字符串,最终显示的是属性字符串
使用图片浏览器展示微博图片
## 一、点击图片时,将图片所在的控件cell的数据传递给图片浏览器
-(1)需求:点击微博上的图片时,进入图片浏览器,图片可以滚动查看下一张,当从第一张图片开始展开,浏览到其他位置图片时,点击关闭按钮,图片会以动画显示到点击关闭的那个图片
-(2)图片是在collectionViewCell上的,所以需要监听cell的点击,设置cell的代理,由于cell是UIView不能弹出控制器,所以当cell发生点击时通知homeViewController来弹出控制器(原则:内部子控件发生点击通知外界来做事情)
-(3)使用通知的方式通知外界:由于cell的父控件是collectionView,collectionView的父控件是tableViewCell,tableViewCell的父控件是tableView,tableView的父控件才是homeViewController,层级关系比较多,所以最好使用通知
-(4)点击cell时发布通知,并传递参数
-(5)获取通知需要传递的参数:1.点击图片是第几个:index,2. 所有图片的url:picURLs,当数据比较多放大通知的userInfo参数里,当数据只有一个对象时就放到通知的object参数,注意:通知名和需要传递的参数的key要写成常量,这是开发规则
-(6)在HomeViewController中监听通知
-(7)自定义photoBrowserViewController(图片浏览器),继承自UIViewController
-(8) homeViewController中接收cell发来的通知时,弹出photoBrowserViewController
-(9)在监听通知方法中需要通过key取出cell传递的数据,然后传递给photoBrowserViewController
-(10)#在photoBrowserViewController类中自定义init构造函数,并添加两个参数:picURLs和indexPath,这样外界在使用photoBrowserViewController创建对象时,就必须要传入这两个参数才可以,注意:由于当前自定义控制器的init构造函数,所有必须调用super的init(initName:nil,bundle:nil)
-(11)#在photoBrowserViewController类中定义两个属性,用于保存外界传递的indexPath和picURLs,注意:在自定义的构造函数中需要将init的参数赋值给定义的这两个属性,这样最终就实现:当外界创建photoBrowserViewController时就会先将indexPath和picURLs传递进去,然后再赋值给了photoBrowserViewController的两个参数,那么就可以在类中使用这两个参数了
##二、在图片浏览器中展示微博图片
-(1)图片浏览器界面分析:由于图片可以拖动切换下一张,顶部还有两个控件关闭和保存按钮,拖动图片的控件使用collectionView,每个图片就是一个cell,关闭和保存按钮使用UIButton,所以共三个控件
-(2)photoBrowserViewController中懒加载这三个控件并创建
-(3)设置UI界面:1.添加这三个子控件到控制器view上(注意要先添加collectionView,再添加两个button,不然collectionView会盖住这两个button),2.设置frame,collectionView占据整个view可以设置为view的bounds,两个按钮在底部可以使用约束设置,3.设置两个按钮的背景颜色、文字、及字体大小,由于设置button的代码较多,可以在UIButton的Extension分类中,给UIButton增加一个便利构造函数init,在init中添加这三个参数,便利构造函数里面是调用self的init(),而不是super的哦,在便利构造函数中把这三个参数设置为UIButton的相关属性即可,那这样就可不用在初始化UI界面的设置关闭和保存按钮的属性了,在懒加载时使用构造函数创建出来就可以设置了,
-(4)设置collectionView的数据源及注册collectionView: cell的个数就是picURLs数组的总个数
-(5)自定义的流水布局并在创建collectionView时使用这个自定义的布局,重写prepare方法(准备布局时调用):1.设置itemSize为collectionView的size(占据屏幕),滚动方向为水平滚动
-(6)自定义collectionViewCell并在注册collectionView的cell时使用自定义的cell,
-(7)在自定义cell中定义picURL属性,把collectionView的picURLs对应的url传递给cell,让cell自己去展示图片
-(8)重写cell的initWithFrame构造函数添加子控件,给cell的contentView添加scrollView,给scrollView添加imageView展示图片:为什么使用scrollView,这是因为,有些长图片是需要上下滚动查看的,注意:1.子控件使用懒加载的方式创建2.imageView需要根据图片的比例设置frame,目前已经image的x值0,宽度为屏幕的宽度,未知y和高度,由于每个图片大小不同,无法固定器frame,所以需要在cell的picURL属性监听器didSet中设置,只要图片发送了改变,就根据图片的等比例去计算高度及y值,不过y值分两种情况1是当图片的高没有超过屏幕时就让其居中,当超过屏幕高度时y值就为0,图片的真实高度需要通过SDWebImage从沙盒缓存中获取出image就能拿到真实宽高
-(9)设置imageView的image从沙盒中取出的图片,即可展示图片了
##三、下载大图及绘制下载图片进度
-(1)由于当前展示的图片的url是缩略图的,导致展示的图片非常模糊,所以在设置imageView的image时需要设置为大图片
-(2)新浪的图片URL是有规则的:小图的URL有thumbnail字符,中图有bmiddle,大图是large,所以我们把小图的url字符串中thumbnail字符替换为bmiddle就可以获取大=中图的url
-(3)绘制图片的下载进度:
   -1.自定义ProgressView继承自UIView,使用drawRect方法绘制一个圆
   -2.创建贝塞尔曲线对象进行绘制
   -3.在cell类中懒加载ProgressView,并将ProgressView添加到cell的contentView上,设置ProgressView的center为cell的屏幕的中心点,宽高为50
  -4.让ProgressView默认隐藏,并清空背景颜色
  -5.当下载图片时显示ProgressView,下载完成后隐藏
##四、问题解决
-(1).当点击微博的图片时,不管点击的哪一张展示的都是第一张图片
     -解决方法:在photoBrowserViewController中让collectionView滚动到对应的位置,调用collectionView的scrollToItemAtIndexPath方法,然后将之前保存的indexPath属性传进去、再传入左对齐、不需要动画,即可
-(2).每张图片之间的挨的太紧不美观,让图片之间产生间距
     -解决方法:设置photoBrowserViewController的view.frame.size+=20,重写loadView方法中设置,再在cell中设置scrollView.frame.size.width -= 20,注意:不要通过bounds来修改,一定要使用frame,不然会出现问题,这是因为修改bounds的width时,会以中心点为原点,控件的左边加10的宽,右边加10的宽,而frame是以左上角为原点增加宽度,所以最终是右边加20宽度
-(3).点击图片时关闭图片浏览器
   -分析:设置cell的代理,didSelectItemAtIndexPath方法中调用closeButtonClick,但是此时点击图片时并没有反应,这是因为imageView的父控件把事件劫走了,而且我们想要的消失是只有点击图片才可以退出界面,点击图片以外的无反应,所以最终是给imageView添加点按手势
   -解决方法:当点击imageView时,通知cell的代理关闭图片浏览器
   -1.创建代理协议
     protocol XYPhotoBrowerCellDelegate {
             func photoBrowerImageViewClick()
       }
     var delegate : XYPhotoBrowerCellDelegate?  // 代理属性

##五、点击保存按钮时将图片保存到相册中
-(1).获取当前正在显示的image:通过collectionView的visbibleCells,这个方法会返回所有在显示的cell的数组,由于当前正在显示的只要一个imageView,所以可以取出数组中first,通过cell获取到imageView的image

##六、自定义弹出和消失动画
-(1).需求当点击图片时,从图片的位置慢慢放大显示图片,而且图片后面的界面不可以消失
   -解决方法(一、设置渐变效果显示和关闭控制器):
     1.修改modal的弹出样式presentationStyle为自定义custom,这样在modal出控制器时就不会隐藏控制器的view了
     2.使用自定义转场,让图片位置慢慢放大图片,设置转场代理
     3.创建PhotoBrowerAnimation类继承自NSObject,用于管理转场动画
     4.在Home控制器中,懒加载属性PhotoBrowerAnimation对象,在弹出图片浏览器的方法中,设置图片浏览器photoBrowerVc的转场代理为PhotoBrowerAnimation对象,在PhotoBrowerAnimation类中实现转场的代理方法
-(2).从图片的位置慢慢放大显示图片,而且图片后面的界面不可以消失
   -解决方法(最终方法):
     1.需要拿到三个东西:(1)图片开始始frame,(2)最终要显示在照片浏览器中的frame,(3)临时创建一个imageVew用于做动画的
     2.把这个临时的imageView的frame设置为图片开始的frame,然后将imageView慢慢放大到图片显示浏览器中的frame,放大完后再移除这个临时imageView
     3.由于我们是在XYPhotoBrowerAnimation类中执行动画的,而这里拿不到图片的起始和最终frame及图片本身
     4.面向协议开发:可以找一个人帮我拿这些东西(swift和oc叫做面向协议开发),(1)在XYPhotoBrowerAnimation中定义协议protocol,继承自基协议NSObjectProtocol,目的:让别人准守协议,只要别人遵守这个协议,就可以有协议中的方法,那最终就可以通过协议方法拿到想要的东西
     5.协议中提供三个方法:用于获取开始位置、最终位置、以及获取UIImageView对象的三个方法,再提供代理属性,代理属性必须遵守协议
     6.起始位置只有cell的父控件picCollectionView可以提供,让picCollectionView遵守协议,并实现协议中的三个方法
     7.让picCollectionView成为XYPhotoBrowerAnimation的代理:在picCollectionView中发布显示图片浏览器的通知中,把picCollectionView自己传入object通知参数中,然后在HomeViewController接收到通知的方法中,取出这个object就是picCollectionView,然后就可以设置XYPhotoBrowerAnimation的代理为picCollectionView了,
     8.在XYPhotoBrowerAnimation中定义一个indexPath属性,将HomeViewController中的indexPath赋值给他,这样完成传值
     9.获取起始的frame:picCollectionView中cell相对于整个屏幕的frame,所以我们需要先通过cellForItemIndexPath获取cell,再将cell的frame转换坐标为相对keyWindow的frame
     10.获取结束位置:先通过indexPath拿到picURLs中对应的额图片url,可以通过SDWebImage获取url对应的图片,然后再计算长图时图片的frame,短图时图片的frame
     11.获取UIImageView对象: 先创建UIImageView对象,再通过SDWebImage从磁盘中获取image,设置imageView的属性:将获取的image设置为imageView的image,并设置contentMode为按照原来的宽高比填充scaleAspectFill,如果有超出的部分剪掉,然后返回这个imageView即可
     12.在弹出动画方法中拿到起始frame和结束frame,将这iamgeView添加到容器视图中,给imageView做从起始到结束frame的动画效果,动画结束后让这个imageView从父控件中移除
##七、消失动画
-(1).需求:点击照片浏览器中图片或关闭按钮时,图片从照片浏览器中慢慢消失到图片在HomeviewController中的位置
-(2).分析:做消失动画我们需要两个东西,一个是当前即将消失的图片在photoBrower中的indexPath,另外一个是需要一个临时的imageView,让imageView的frame与photoBrowerCell的imageView的frame相同,并把photoBrower中cell的imageView的image赋值给临时imageView的image,那我们拿到这两个属性后就可以直接做消失动画了
-(3).谁做消失动画的代理做合适:photoBrowerController,因为cell的父控件是collectionView,而collectionView是photoBrowerController的view的子控件,且是在photoBrowerController是collectionView的数据源,所以只有最合适,这就是面向协议开发

https://github.com/Ossey/WeiBo

上一篇下一篇

猜你喜欢

热点阅读