直播项目笔记(二)

2017-11-30  本文已影响0人  Closer3

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

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

// 添加待模糊的图片视图
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)

// 给 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("未处理按钮")
        }
    }
/// 属性说明
//不会随父视图的改变而改变
    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

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]

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抽象相同的方法

面向协议示例

/* 命名一般以 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

上一篇 下一篇

猜你喜欢

热点阅读