美文网首页
直播项目笔记(二)

直播项目笔记(二)

作者: Closer3 | 来源:发表于2017-11-30 19:53 被阅读0次

    毛玻璃 + runtime全局pop + 面向协议编程 + 粒子动画

    组合第一天封装CLOPageView和瀑布流布局

    • UIVisualEffectView视图实现毛玻璃效果
    // 添加待模糊的图片视图
    let imageView = UIImageView(image: UIImage(named: "timg"))
    imageView.frame = view.frame
    imageView.contentMode = .scaleAspectFill
    imageView.clipsToBounds = true
    view.addSubview(imageView)
      
    // 生成特定样式的模糊效果
    let blur = UIBlurEffect(style: .light)
      
    // 根据模糊效果生成模糊视图
    let blurView = UIVisualEffectView(effect: blur)
      
    // 设置模糊区域大小
    blurView.frame = view.frame
      
    view.addSubview(blurView)
    
    • UIStackView 实现并列布局, 可做工具栏。 UIStackView的核心便是方便垂直或水平排布多个 subview
    
    // 给 5 个 button 设置不同的 tag 同时连线下面的方法
    @IBAction func menuClick(_ sender: UIButton) {
        switch sender.tag {
            case 0:
                print("点击了功能1")
            case 1:
                print("点击了功能2")
            case 2:
                print("点击了功能3")
            case 3:
                print("点击了功能4")
            case 4:
                print("点击了功能5")
            default:
                fatalError("未处理按钮")
            }
        }
    
    • autoresizingUIView的属性,一直存在,使用也比较简单,但是没有autolayout那样强大。如果你的界面比较简单,要求的细节没有那么高,那么你完全可以使用autoresizing去进行自动布局
    /// 属性说明
    //不会随父视图的改变而改变
        UIViewAutoresizingNone                 = 0,
    //自动调整view与父视图左边距,以保证右边距不变
        UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    //自动调整view的宽度,保证左边距和右边距不变
        UIViewAutoresizingFlexibleWidth        = 1 << 1,
    //自动调整view与父视图右边距,以保证左边距不变
        UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    //自动调整view与父视图上边距,以保证下边距不变
        UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    //自动调整view的高度,以保证上边距和下边距不变
        UIViewAutoresizingFlexibleHeight       = 1 << 4,
    //自动调整view与父视图的下边距,以保证上边距不变
        UIViewAutoresizingFlexibleBottomMargin = 1 << 5
    
    
    • swift中数组常用的两个方法

    map函数能够被数组调用,它接受一个闭包作为参数,作用于数组中的每个元素。闭包返回一个变换后的元素,接着将所有这些变换后的元素组成一个新的数组

    // 可以看到我们甚至可以不再定义可变的数组直接用不可变的就可以
    let numbers = [1,2,3]
    let sumNumbers = numbers.map { (number: Int) -> Int in
        return number + number
    }
    // 最终简化写法
    let sumNumbers3 = numbers.map { $0 + $0 } 
    // [2,4,6]
    

    filter可以取出数组中符合条件的元素 重新组成一个新的数组

    let numbers = [1,2,3,4,5,6]
    let evens = numbers.filter { $0 % 2 == 0 }
    // [2,4,6]
    
    • swift 4.x中字典转模型问题,要在属性前面加@objc

    • swift常用的第三方框架

    Alamofire相当于OCAFNetworking
    Kingfisher 相当于OCSDWebImage

    runtime实现全局pop

    runtime的方法打印interactivePopGestureRecognizer隐藏属性 找出添加手势所需的targetaction

    var count:UInt32 = 0
    let ivars = class_copyIvarList(UIGestureRecognizer.self, &count)!
    for i in 0..<count {
      //拿到ivar指针
      let nameP = ivar_getName(ivars[Int(i)])
      //根据指针找到对应的属性的字符串
      let name = String(cString: nameP!)
      print(name)
    }
       
    //        _gestureFlags
    //        _targets
    //        _delayedTouches
    //        _delayedPresses
    //        _view
       
    guard let targets = interactivePopGestureRecognizer?.value(forKey: "_targets") as? [NSObject] else { return }
    print(targets)
       
    //        Optional([(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7ff117701e10>)])
       
    let targetObjc = targets[0]
    let target = targetObjc.value(forKey: "target")
    let action = Selector(("handleNavigationTransition:"))
       
    let panGes = UIPanGestureRecognizer(target: target, action: action)
    view.addGestureRecognizer(panGes)
    

    面向协议编程

    面向对象or面向协议?

    • 传统的面向对象思维方式:

    有一只狗,有自己的名字, 可以跑
    有一只猫,有自己的名字, 可以跑
    有一个人,有自己的名字, 可以跑
    抽象出一个动物类, 之后, 将跑的行为放入动物类中
    如果需要一个吃的行为, 也可以抽象在动物类中

    • 面向对象开发弊端

    如果有一个机器人(一辆车), 也有跑的行为, 这个时候如何抽象呢, 显然该抽象方式并不是特别合理

    • 真实开发中的场景

    对UIViewController/UITableViewController/UICollectionViewController抽象相同的方法

    • 面向对象开发核心是: 封装-继承-(多态)

    面向协议示例

    • Swift 标准库中有 50 多个复杂不一的协议,几乎所有的实际类型都是满足若干协议的

    • 面向协议开发核心是: 模块化(组件化)

    • 面向协议开发应用: 将功能抽取在单独的协议中, 如果有控制器需要, 实现我的协议即可

    /* 命名一般以 able 结尾
     swift 可以在协议中实现方法 */
    
    // MARK: - 方法声明
    protocol NibLoadable {
        
    }
    
    // MARK: - 方法实现
    
    /* 方法实现只能写在 extension 中
       用协议封装 加载 xib 的方法
       用 where 给协议方法增加条件约束 只有 UIView 才能调用
       协议方法只能用 static 修饰  */
    extension NibLoadable where Self: UIView {
        static func loadFromNib(_ nibName: String? = nil) -> Self {
            let loadName = nibName == nil ? "\(self)" : nibName!
            return Bundle.main.loadNibNamed(loadName, owner: nil, options: nil)?.first as! Self
        }
    }
    

    TestView中遵循并实现协议 TestView.loadFromNib()

    粒子动画

    func emitterAnimationStart(_ point: CGPoint) {
        
        // 1.创建发射器
        let emitter = CAEmitterLayer()
        
        // 2.设置发射器的位置
        emitter.position = point
        
        // 3.开启三维效果
        emitter.preservesDepth = true
        
        // 4.创建粒子,并且设置粒子相关属性
        // 4.1 创建粒子 cell
        let cell = CAEmitterCell()
        
        // 4.2 设置粒子速度
        cell.velocity = 150
        cell.velocity = 100
        
        // 4.3 设置粒子的大小
        cell.scale = 0.7
        cell.scaleRange = 0.3
        
        // 4.4 设置粒子方向
        cell.emissionLongitude = CGFloat(-Double.pi / 2)
        cell.emissionRange = CGFloat(Double.pi / 4)
        
        // 4.5 设置粒子存活时间
        cell.lifetime = 6
        cell.lifetimeRange = 1.5
        
        // 4.6 设置粒子旋转
        cell.spin = CGFloat(Double.pi / 2)
        cell.spinRange = CGFloat(Double.pi / 4)
        
        // 4.7 设置粒子每秒弹出的个数
        cell.birthRate = 20
        
        // 4.8 设置粒子展示图片
        cell.contents = UIImage(named: "good2_30x30_")?.cgImage
        
        // 5.将粒子加入到发射器中
        emitter.emitterCells = [cell]
        
        // 6.将发射的 layer 添加到父 layer 中
        view.layer.addSublayer(emitter)
    }
    
    func stop() {
        /*
         for layer in view.layer.sublayers! {
             if layer.isKind(of: CAEmitterLayer.self) {
                 layer.removeFromSuperlayer()
             }
         }
         */
        view.layer.sublayers?.filter({ $0.isKind(of: CAEmitterLayer.self)}).first?.removeFromSuperlayer()
    }
    

    坐标转换

    // 将像素point由point所在视图转换到目标视图view中,返回在目标视图view中的像素值
    - (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;
    // 将像素point从view中转换到当前视图中,返回在当前视图中的像素值
    - (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;
    
    // 将rect由rect所在视图转换到目标视图view中,返回在目标视图view中的rect
    - (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;
    // 将rect从view中转换到当前视图中,返回在当前视图中的rect
    - (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;
    
    //例把UITableViewCell中的subview(btn)的frame转换到 controllerA中
    
    // controllerA 中有一个UITableView, UITableView里有多行UITableVieCell,cell上放有一个button
    // 在controllerA中实现:
    CGRect rc = [cell convertRect:cell.btn.frame toView:self.view];
    或
    CGRect rc = [self.view convertRect:cell.btn.frame fromView:cell];
    // 此rc为btn在controllerA中的rect
    
    //或当已知btn时:
    CGRect rc = [btn.superview convertRect:btn.frame toView:self.view];
    或
    CGRect rc = [self.view convertRect:btn.frame fromView:btn.superview];
    

    通过按钮的点击实现一个功能的开启和关闭

    button.isSelected = !sender.isSelected
    button.isSelected ? emitterAnimationStart(point!) : stopEmitterAnimation()
    

    CLOPageView 拓展

    主要思路:对中间的 collectionView自定义layout

    相关文章

      网友评论

          本文标题:直播项目笔记(二)

          本文链接:https://www.haomeiwen.com/subject/zkdbbxtx.html