swift项目总结

一、常用的第三方

名称 描述
Alamofire OC的AFNetworking
SnapKit OC的Masonry
Kingfisher OC SDWebImage
ESTabBarController-swift 高度自定义的 TabBarController 组件(各种你想到的和想不到的哦)
FSPagerView 各种类型的banner滚动图片
HandyJSON、SwiftyJSON 数据转模型
DNSPageView 、SegementSlide(也很牛逼) 类似于新闻类的分页,有共同的头部
XLPagerTabStrip 分页视图和 DNSPageView类似
JXMarqueeView 跑马灯
LTScrollView ScrollView嵌套ScrolloView的库,解决多个列表公用一个头部的问题
SwiftMessages 消息提示(类似于flutter的snackBar)
StreamingKit 播放在线音频
YPImagePicker 照片视频选择器
SKPhotoBrowser 图片浏览器
KMPlaceholderTextView 可显示多行 placeholder 的 textView
PopupDialog 一个简单的,可定制的弹出对话框为iOS编写的Swift,替换UIAlertController警报样式
FaveButton 动感按钮点击效果(是的就是你想的那样,DuangDuang的)
ImageSlideshow 图片幻灯片和图片轮播器
GrowingTextView 一个非常棒的UITextView库
Hero 转场动画

各种你想要的知识:
iOS开发第三方库图像篇-swift版
iOS开发动画库-swift版

二、页面布局

image.png
1、区头设置

使用CollectionView来处理,里面涉及到的技术点。

1.1 闭包
//声明
public var cellTitleClick: ((_ title: String)->())?
//调用
self.cellTitleClick!(dataArray[indexPath.row] as String)
//在controller中使用
  private lazy var headerView:LBFMFindHeaderView = {
        let view = LBFMFindHeaderView.init(frame: CGRect(x:0, y:0, width:LBFMScreenWidth, height:190))
        view.backgroundColor = UIColor.white
        view.cellTitleClick = { (title) in
            print("外部LBFMFindController点击区头的内容:",title)
        }
        return view
    }()
1.2 UICollectionView的初始化和cell的注册
import UIKit
class LBFMFindHeaderView: UIView {
    //点击头部返回数据
    public var cellTitleClick: ((_ title: String)->())?
    let dataArray = ["电子书城","全民朗读","大咖主播","活动","直播微课","听单","游戏中心","边听变看","商城","0元购","电子书城","全民朗读","大咖主播","活动","直播微课","听单","游戏中心","边听变看","商城","0元购"]    
    private lazy var collectionView : UICollectionView = {
        let layout = UICollectionViewFlowLayout.init()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        layout.scrollDirection = UICollectionView.ScrollDirection.horizontal
        layout.itemSize = CGSize(width: (LBFMScreenWidth - 30) / 5, height:90)
        let collectionView = UICollectionView.init(frame:CGRect(x:15, y:0, width:LBFMScreenWidth - 30, height:180), collectionViewLayout: layout)
        collectionView.isPagingEnabled = true  //添加翻页效果
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.backgroundColor = UIColor.white
        collectionView.register(LBFMFindCell.self, forCellWithReuseIdentifier:"LBFMFindCell")
        return collectionView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.addSubview(self.collectionView)
        let footerView = UIView()
        footerView.backgroundColor = LBFMDownColor
        self.addSubview(footerView)
        footerView.snp.makeConstraints { (make) in
            make.left.right.bottom.equalToSuperview()
            make.height.equalTo(10)
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

extension LBFMFindHeaderView: UICollectionViewDelegate, UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dataArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell:LBFMFindCell = collectionView.dequeueReusableCell(withReuseIdentifier: "LBFMFindCell", for: indexPath) as! LBFMFindCell
        cell.dataString = self.dataArray[indexPath.row]
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        self.cellTitleClick!(dataArray[indexPath.row] as String)
        print("点击顶部内容:",dataArray[indexPath.row] as String)
    }
}
2、底部滑动Controller
2.1 引用LTScrollView三方,HeadView使用我们自定义的LBFMFindHeaderView,如果不要的话可以设置高度为0
2.2 设置滚动头部的title和对应的Controller的数组
2.3 设置LTAdvancedManager的view以及相关设置
3、导航栏左右item设置以及事件
import UIKit
import LTScrollView

class LBFMFindController: UIViewController {
    // - headerView  区头
    private lazy var headerView:LBFMFindHeaderView = {
        let view = LBFMFindHeaderView.init(frame: CGRect(x:0, y:0, width:LBFMScreenWidth, height:190))
        view.backgroundColor = UIColor.white
        view.cellTitleClick = { (title) in
            print("外部LBFMFindController点击区头的内容:",title)
        }
        return view
    }()
    
    private lazy var viewControllers: [UIViewController] = {
        let findAttentionVC = LBFMFindAttentionController()
        let findRecommendVC = LBFMFindRecommendController()
        let findDuDYVC = LBFMFindDudController()
        return [findAttentionVC, findRecommendVC, findDuDYVC]
    }()
    private lazy var titles: [String] = {
        return ["关注动态", "推荐动态", "趣配音"]
    }()
    
    private lazy var layout: LTLayout = {
        let layout = LTLayout()
        layout.isAverage = true
        layout.sliderWidth = 80
        layout.titleViewBgColor = UIColor.white
        layout.titleColor =  UIColor(r: 178, g: 178, b: 178)
        layout.titleSelectColor = UIColor.orange//UIColor(r: 16, g: 16, b: 16)
        layout.bottomLineColor = UIColor.orange
        layout.sliderHeight = 56
        /* 更多属性设置请参考 LTLayout 中 public 属性说明 */
        return layout
    }()
    
    private lazy var advancedManager: LTAdvancedManager = {
        let statusBarH = UIApplication.shared.statusBarFrame.size.height
        let advancedManager = LTAdvancedManager(frame: CGRect(x: 0, y: LBFMNavBarHeight, width: LBFMScreenWidth, height: LBFMScreenHeight - LBFMNavBarHeight), viewControllers: viewControllers, titles: titles, currentViewController: self, layout: layout, headerViewHandle: {[weak self] in
            guard let strongSelf = self else { return UIView() }
            let headerView = strongSelf.headerView
            return headerView
        })
        /* 设置代理 监听滚动 */
        advancedManager.delegate = self
        /* 设置悬停位置 */
        // advancedManager.hoverY = navigationBarHeight
        /* 点击切换滚动过程动画 */
        // advancedManager.isClickScrollAnimation = true
        /* 代码设置滚动到第几个位置 */
        // advancedManager.scrollToIndex(index: viewControllers.count - 1)
        return advancedManager
    }()
    
    // - 导航栏左边按钮
    private lazy var leftBarButton:UIButton = {
        let button = UIButton.init(type: UIButton.ButtonType.custom)
        button.frame = CGRect(x:0, y:0, width:30, height: 30)
        button.setImage(UIImage(named: "msg"), for: UIControl.State.normal)
        button.addTarget(self, action: #selector(leftBarButtonClick), for: UIControl.Event.touchUpInside)
        return button
    }()
    // - 导航栏右边按钮
    private lazy var rightBarButton:UIButton = {
        let button = UIButton.init(type: UIButton.ButtonType.custom)
        button.frame = CGRect(x:0, y:0, width:30, height: 30)
        button.setImage(UIImage(named: "搜索"), for: UIControl.State.normal)
        button.addTarget(self, action: #selector(rightBarButtonClick), for: UIControl.Event.touchUpInside)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        self.automaticallyAdjustsScrollViewInsets = false
        view.addSubview(advancedManager)
      
        advancedManagerConfig()
        
        // 导航栏左右item
        self.navigationItem.leftBarButtonItem = UIBarButtonItem.init(customView: leftBarButton)
        self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(customView: rightBarButton)        
    }
    
    // - 导航栏左边消息点击事件
    @objc func leftBarButtonClick() {
        print("点击了左边的信箱")
    }
    // - 导航栏左边消息点击事件
    @objc func rightBarButtonClick() {
        print("点击了右边的搜索按钮")

    }
}

extension LBFMFindController : LTAdvancedScrollViewDelegate {
    // 具体使用请参考以下
    private func advancedManagerConfig() {
        // 选中事件
        advancedManager.advancedDidSelectIndexHandle = {
            print("选中了 -> \($0)")
        }
    }
}

三、UITableViewCell的定义和高度的计算

1、Cell的布局

cell分为四个区域:
1.1 头像和名称
高度固定
1.2 发布的文本
计算文本的高度
1.3 CollectionView
每一行有三个图片,计算3的倍数,然后算出来CollectionView高度。
1.4 底部时间、点赞、留言数
高度固定
在viewModel中请求并计算数据。

import UIKit
import SwiftyJSON
import HandyJSON

class LBFMFindAttentionViewModel: NSObject {
    var eventInfos:[LBFMEventInfosModel]?
    // - 数据源更新
    typealias LBFMAddDataBlock = () ->Void
    var updataBlock:LBFMAddDataBlock?
}
// - 请求数据
extension LBFMFindAttentionViewModel {
    func refreshDataSource() {
        // 1. 获取json文件路径
        let path = Bundle.main.path(forResource: "FindAttention", ofType: "json")
        // 2. 获取json文件里面的内容,NSData格式
        let jsonData=NSData(contentsOfFile: path!)
        // 3. 解析json内容
        let json = JSON(jsonData!)
        if let mappedObject = JSONDeserializer.deserializeModelArrayFrom(json: json["data"]["eventInfos"].description) {
            self.eventInfos = mappedObject as? [LBFMEventInfosModel]
            self.updataBlock?()
        }
    }
}

extension LBFMFindAttentionViewModel {
    // 每个分区显示item数量
    func numberOfRowsInSection(section: NSInteger) -> NSInteger {
        return self.eventInfos?.count ?? 0
    }
    // 高度
    func heightForRowAt(indexPath: IndexPath) -> CGFloat {
        let picNum = self.eventInfos?[indexPath.row].contentInfo?.picInfos?.count ?? 0
        var num:CGFloat = 0
        //计算图片高度
        if picNum > 0 && picNum <= 3 {
            num = 1
        }else if picNum > 3 && picNum <= 6{
            num = 2
        }else if picNum > 6{
            num = 3
        }
        let OnePicHeight = CGFloat((LBFMScreenWidth - 30) / 3)
        let picHeight = num * OnePicHeight
        let textHeight:CGFloat = height(for: self.eventInfos?[indexPath.row].contentInfo)
        return 60+50+picHeight+textHeight
    }
    
    //计算文本高度
    func height(for commentModel: LBFMFindAContentInfo?) -> CGFloat {
        var height: CGFloat = 44
        guard let model = commentModel else { return height }
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 15)
        label.numberOfLines = 0
        label.text = model.text
        height += label.sizeThatFits(CGSize(width: LBFMScreenWidth - 30, height: CGFloat.infinity)).height + 10
        return height
    }
}

四、动画

1、浮动动画

1.1 首先旋转动画

        self.addSubview(self.animationView)
        self.animationView.layer.masksToBounds = true
        self.animationView.layer.cornerRadius = 10
        self.animationView.snp.makeConstraints { (make) in
            make.size.equalTo(CGSize(width: 120, height: 80))
            make.top.equalTo(120)
            make.right.equalTo(-20)
        }
        /// vip动画view的旋转角度
        self.animationView.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 12)

1.2 启动和关闭动画

    /// 开始动画
    func setAnimationViewAnimation(){
        let yorig:CGFloat = 100.0 + 64
        let opts: UIView.AnimationOptions = [.autoreverse , .repeat]
        UIView.animate(withDuration: 1, delay: 1, options: opts, animations: {
            self.animationView.center.y -= 20
        }) { _ in
            self.animationView.center.y = yorig
        }
    }
    // 停止动画
    func stopAnimationViewAnimation(){
        self.animationView.layer.removeAllAnimations()
    }
2、水波动画(我要录音)
import UIKit
class LBFMCVLayerView: UIView {
    var pulseLayer : CAShapeLayer!  //定义图层
    override init(frame: CGRect) {
        super.init(frame: frame)
        let width = self.bounds.size.width
        
        // 动画图层
        pulseLayer = CAShapeLayer()
        pulseLayer.bounds = CGRect(x: 0, y: 0, width: width, height: width)
        pulseLayer.position = CGPoint(x: width / 2, y: width / 2)
        pulseLayer.backgroundColor = UIColor.clear.cgColor
        // 用BezierPath画一个原型
        pulseLayer.path = UIBezierPath(ovalIn: pulseLayer.bounds).cgPath
        // 脉冲效果的颜色  (注释*1)
        pulseLayer.fillColor = UIColor.init(r: 213, g: 54, b: 13).cgColor
        pulseLayer.opacity = 0.0
        
        // 关键代码
        let replicatorLayer = CAReplicatorLayer()
        replicatorLayer.bounds = CGRect(x: 0, y: 0, width: width, height: width)
        replicatorLayer.position = CGPoint(x: width/2, y: width/2)
        // 三个复制图层
        replicatorLayer.instanceCount = 3
        // 频率
        replicatorLayer.instanceDelay = 1
        replicatorLayer.addSublayer(pulseLayer)
        self.layer.addSublayer(replicatorLayer)
        self.layer.insertSublayer(replicatorLayer, at: 0)
    }
    
    func starAnimation() {
        // 透明
        let opacityAnimation = CABasicAnimation(keyPath: "opacity")
        // 起始值
        opacityAnimation.fromValue = 1.0
        // 结束值
        opacityAnimation.toValue = 0
        
        // 扩散动画
        let scaleAnimation = CABasicAnimation(keyPath: "transform")
        let t = CATransform3DIdentity
        scaleAnimation.fromValue = NSValue(caTransform3D: CATransform3DScale(t, 0.0, 0.0, 0.0))
        scaleAnimation.toValue = NSValue(caTransform3D: CATransform3DScale(t, 1.0, 1.0, 0.0))
        
        // 给CAShapeLayer添加组合动画
        let groupAnimation = CAAnimationGroup()
        groupAnimation.animations = [opacityAnimation,scaleAnimation]
        // 持续时间
        groupAnimation.duration = 3
        // 循环效果
        groupAnimation.autoreverses = false
        groupAnimation.repeatCount = HUGE
        groupAnimation.isRemovedOnCompletion = false
        pulseLayer.add(groupAnimation, forKey: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}
image.png

五、自定义tabbar

ESTabBarController各种想要的功能以及lottie动画都可实现。

image.png

static func lottieSytle() -> ESTabBarController {
        let tabBarController = ESTabBarController()
        let v1 = ExampleViewController()
        let v2 = ExampleViewController()
        let v3 = ExampleViewController()
        let v4 = ExampleViewController()
        let v5 = ExampleViewController()
        
        v1.tabBarItem = ESTabBarItem.init(ExampleLottieAnimateBasicContentView(), title: nil, image: UIImage(named: "home"), selectedImage: UIImage(named: "home_1"))
        v2.tabBarItem = ESTabBarItem.init(ExampleLottieAnimateBasicContentView(), title: nil, image: UIImage(named: "find"), selectedImage: UIImage(named: "find_1"))
//ExampleLottieAnimateContentView内部引入了lottie文件以及播放动画
        v3.tabBarItem = ESTabBarItem.init(ExampleLottieAnimateContentView(), title: nil, image: nil, selectedImage: nil)
        v4.tabBarItem = ESTabBarItem.init(ExampleLottieAnimateBasicContentView(), title: nil, image: UIImage(named: "favor"), selectedImage: UIImage(named: "favor_1"))
        v5.tabBarItem = ESTabBarItem.init(ExampleLottieAnimateBasicContentView(), title: nil, image: UIImage(named: "me"), selectedImage: UIImage(named: "me_1"))
        
        tabBarController.viewControllers = [v1, v2, v3, v4, v5]
        
        return tabBarController
    }

引入动画,具体详见Demo

import UIKit
import ESTabBarController_swift

class LBFMIrregularityBasicContentView: LBFMBouncesContentView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        
        textColor = UIColor.init(white: 175.0 / 255.0, alpha: 1.0)
        highlightTextColor = UIColor.init(red: 254/255.0, green: 73/255.0, blue: 42/255.0, alpha: 1.0)
        iconColor = UIColor.init(white: 175.0 / 255.0, alpha: 1.0)
        highlightIconColor = UIColor.init(red: 254/255.0, green: 73/255.0, blue: 42/255.0, alpha: 1.0)
    }
    
    public required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}
class LBFMIrregularityContentView: ESTabBarItemContentView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.imageView.backgroundColor = UIColor.init(red: 250/255.0, green: 48/255.0, blue: 32/255.0, alpha: 1.0)
        self.imageView.layer.borderWidth = 2.0
        self.imageView.layer.borderColor = UIColor.init(white: 235 / 255.0, alpha: 1.0).cgColor
        self.imageView.layer.cornerRadius = 25
        self.insets = UIEdgeInsets.init(top: -23, left: 0, bottom: 0, right: 0)
        let transform = CGAffineTransform.identity
        self.imageView.transform = transform
        self.superview?.bringSubviewToFront(self)
        
        textColor = UIColor.init(white: 255.0 / 255.0, alpha: 1.0)
        highlightTextColor = UIColor.init(white: 255.0 / 255.0, alpha: 1.0)
        iconColor = UIColor.init(white: 255.0 / 255.0, alpha: 1.0)
        highlightIconColor = UIColor.init(white: 255.0 / 255.0, alpha: 1.0)
        backdropColor = .clear
        highlightBackdropColor = .clear
    }
    
    public required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let p = CGPoint.init(x: point.x - imageView.frame.origin.x, y: point.y - imageView.frame.origin.y)
        return sqrt(pow(imageView.bounds.size.width / 2.0 - p.x, 2) + pow(imageView.bounds.size.height / 2.0 - p.y, 2)) < imageView.bounds.size.width / 2.0
    }
    
    override func updateLayout() {
        super.updateLayout()
        self.imageView.sizeToFit()
        self.imageView.center = CGPoint.init(x: self.bounds.size.width / 2.0, y: self.bounds.size.height / 2.0)
    }
}

6、计算文字高度

// 计算文字的高度
    func height(for commentModel: LBFMFindRStreamList?) -> CGFloat {
        var height: CGFloat = 30
        guard let model = commentModel else { return height }
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 15)
        label.numberOfLines = 0
        label.text = model.content
        height += label.sizeThatFits(CGSize(width: LBFMScreenWidth - 30, height: CGFloat.infinity)).height //算出高度
        return height
    }

你可能感兴趣的:(swift项目总结)