swift 项目实战演练

发现

  • 偶然间发现一个很好的手把手教学项目,swift直播教学技术,在这里奉献出来,都是很实用的项目实战技术,拿来练手学习非常棒
    网易云课堂

共同进步,爱生活,爱钻研,爱分享!

项目实战核心技术分享

注意: *本文不是简单的代码练习,而是在原项目实战的基础上添加流行的框架尤其是swift中让人头疼的网络解析 模型转换 *

  • 项目中使用的第三方框架

pod 'Alamofire'
pod 'SwiftyJSON'
pod 'Kingfisher'

  • 项目技术点
  1. UIcollectionView 的高级用法,
  2. 类似今日头条的横向菜单
  3. 无限轮播图复用实现
  4. xib 快速布局
  5. Alamofire 组建封装
  6. 三方库的使用
  7. MVVM 思想运用
  8. 算法小技巧

项目效果

QQ20180313-140323.gif
  • 项目地址:https://github.com/zyjian/DouYuZB/

开启代码之旅

横向菜单原理

  1. 标题部分PageTitleView 自定义UIview
代码请到github 中下载  https://github.com/zyjian/DouYuZB/
  • 这样写是不是很清爽,给类不断的扩展方法让我们的代码结构化方便管理


    swift 项目实战演练_第1张图片
    50BB7174-A400-4B02-9A1C-B1B16B4BB4B3.png
  1. 下面的content 也是一个自定义的UIView 的子类 PageContentView,上面放了一个UIcollectionView,这是横线滚动
  2. 让PageTitleView 与 PageContentView建立对一个逻辑关系
    这里有点需要注意的就是,慢慢滑动的时候 标题的颜色从orange 渐变到 gray
// MARK: - 对外暴露方法
extension PageTitleView {
    func setCurrentIndex(sourceIndex: Int, targetIndex: Int, process: CGFloat) {
        //1.取出sourceLabel targetLabel
        let sourceLabel: UILabel = titleLabels[sourceIndex]
        let targetLabel: UILabel = titleLabels[targetIndex]
        
        
        //2.改变下标值
        currentIndex = targetIndex
        
        //3.移动滑块逻辑
        let moveTotalX = targetLabel.frame.origin.x - sourceLabel.frame.origin.x
        let moveX = moveTotalX * process
        scrollLine.frame.origin.x = sourceLabel.frame.origin.x + moveX
        
        //4.颜色渐变33
        //4.1取出颜色变化范围
        let colorDelta = (kSelectedColor.0 - kNormalColor.0 , kSelectedColor.1 - kNormalColor.1 , kSelectedColor.2 - kNormalColor.2)
        //4.2变化sourceLabel
        sourceLabel.textColor = UIColor.init(r: kSelectedColor.0 - colorDelta.0*process, g: kSelectedColor.1 - colorDelta.1*process, b: kSelectedColor.2 - colorDelta.2 * process, a: 1)
        //4.3变化sourceLabel
        targetLabel.textColor = UIColor.init(r: kNormalColor.0 + colorDelta.0*process, g:kNormalColor.1 + colorDelta.1*process , b: kNormalColor.2 + colorDelta.2*process, a: 1)
        
    }
} 

PageContentView 监听collectionView滑动 这里有个小算法这样更简单

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if isForbidScrollDelegate { return }
        
        let nowOffsetX : CGFloat = scrollView.contentOffset.x
        
        
        var soureceIndex : Int
        var targetIndex :Int
        var process : CGFloat
        //左滑
        if nowOffsetX > beganOffsetX {
            
            //1.确定process
            process = (nowOffsetX/scrollView.frame.width - CGFloat((floor(nowOffsetX/scrollView.frame.width))))

            
            //2. 确定 soureceIndex,
            soureceIndex = Int(nowOffsetX/scrollView.frame.width)
            
            //3.确定  targetIndex
            targetIndex = soureceIndex + 1
            if targetIndex >= childVcs.count {
                targetIndex = childVcs.count - 1
            }
            
            //4.完全划过去
            if nowOffsetX - beganOffsetX == scrollView.frame.width {
                process = 1
                targetIndex = soureceIndex
            }
           
            
        }else{
            //右滑
            
            //1.确定process
            process = 1 - (nowOffsetX/scrollView.frame.width - CGFloat((floor(nowOffsetX/scrollView.frame.width))))

            //2.确定  targetIndex
            targetIndex = Int(nowOffsetX/scrollView.frame.width)
            
            //3. 确定 soureceIndex,
            soureceIndex = targetIndex + 1
            
            //4.完全划过去
            if soureceIndex >= childVcs.count {
                process = 1
                soureceIndex = targetIndex
            }
            
            
            
        }
        Log("soureceIndex:\(soureceIndex) ,targetIndex:\(targetIndex) process:\(process)")
        delegate?.pageContentView(source: soureceIndex, target: targetIndex, process: process)
    }

网络请求工具类封装

import UIKit
import Alamofire

enum MethodType {
    case get
    case post
}

extension Dictionary {
    func dic2urlString() -> String {
        let muStr:NSMutableString = NSMutableString()
        
        for (k,v) in self {
            let temp : String = "\(k)=\(v)&"
            muStr.append(temp)        }
        
        return String(muStr.substring(to: muStr.length-1))
    }
}

class NetworkTools {
    class func requestData(type :MethodType, URLString: String , parameters: [String : Any]? = nil ,finishedCallback:@escaping ( _ result : AnyObject) -> ()) {
        
        //1.获取类型
        let method = type == .get ? HTTPMethod.get : HTTPMethod.post
        
        // 请求头
        var headers: [String : String]? {
            return ["Content-type" : "application/json"]
        }
        //2.发送网络请求
        Alamofire.request(URLString, method: method, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON { (response) in
            
            //3.获取结果
            guard let result = response.result.value else {
                Log("请求错误\(String(describing: response.result.error))")
                return
            }
            
            if parameters != nil {
                Log("\(URLString)?\n\(parameters!.dic2urlString()) \n \(String(describing: response.result.value))")
            }
            //4.将结果返回
            finishedCallback(result as AnyObject)
        }
    }
}

// 扩展方法
private extension String {
    var utf8Encoded: Data {
        return data(using: .utf8)!
    }
}

使用方法

 //3.请求第一部分推荐数据
        NetworkTools.requestData(type: .get, URLString: "http://capi.douyucdn.cn/api/v1/getbigDataRoom", parameters: ["time" : Date.getCurrentTime()]) { (result) in
            let json = JSON(result)
            let data = json["data"].arrayValue

            for dic in data{
                let model = RoomModel.init(jsonData: dic)
                self.bigDataGroup.room_list.append(model)
            }
            self.bigDataGroup.tag_name = "热门"
            self.bigDataGroup.icon_name = "home_header_hot"

        }

SwiftyJSON 的使用 model 类构建

import UIKit
import SwiftyJSON

struct RoomModel {
    var specific_catalog:String?
    var vertical_src:String?
    var nickname :String?
    var game_name:String?
    var room_name:String?
    var anchor_city:String?
    var icon_url:String?
    var tag_name:String?

    var room_id:Int?
    var show_time:Int?
    var isVertical:Int?
    var owner_uid:Int?
    var online:Int?
    
    
    init() {
        
    }
    init(jsonData:JSON) {
        specific_catalog = jsonData["specific_catalog"].stringValue
        vertical_src = jsonData["vertical_src"].stringValue
        nickname = jsonData["nickname"].stringValue
        game_name = jsonData["game_name"].stringValue
        room_name = jsonData["room_name"].stringValue
        anchor_city = jsonData["anchor_city"].stringValue
        icon_url = jsonData["icon_url"].stringValue
        tag_name = jsonData["tag_name"].stringValue

        
        online = jsonData["online"].intValue
        room_id = jsonData["room_id"].intValue
        show_time = jsonData["show_time"].intValue
        isVertical = jsonData["isVertical"].intValue
        owner_uid = jsonData["owner_uid"].intValue

    }
}

什么是MVVM ?

swift 项目实战演练_第2张图片
87E7B604-2232-4C8F-BE4B-CF54A8BDA4C7.jpeg

看明白了吗?看不懂没关系直接上代码


swift 项目实战演练_第3张图片
26C8049F-FB42-4DD0-AD90-D6F93C540512.png

MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。modelView 它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。本项目中的Viewmodel 负责处理 网络请求的,这样我们的控制器中更加简单。

是不是很简单呢

更多代码详情技巧 请到 Demo 中查看,欢迎留下足迹,共同进步!

你可能感兴趣的:(swift 项目实战演练)