Swift 开发 wanandroid 客户端——其他页面编写与总结

1,074 阅读6分钟

这是我参与更文挑战的第30天,活动详情查看: 更文挑战

6月的最后一更

本篇文章会对wanandroid客户端最后几个页面做简单的分析,因为源码已经附在文末,大家可以边看代码,边学习哈,记得给一颗star喔~

热词页面编写

IMG_52DF97A3348B-1.jpeg

这个页面是点击首页右侧的搜索按钮进入的。

接口使用的hotkey/json,返回的JSON模型如下:

struct HotKey : Codable {

    let id : Int?
    let link : String?
    let name : String?
    let order : Int?
    let visible : Int?

}

请求返回的是[HotKey]数组,然后通过SnapKit扩展分类进行Wrap布局基本上就可以完成这个页面的布局。

SnapKit的扩展代码与例子如下:

SnapKitExtensionDemo

输入框与右侧的搜索按钮通过Rx进行了绑定,当输入框的字符大于0时,搜索按钮才使能。

搜索结果页面编写

IMG_346AA985B72F-1.jpeg

这个页面是在热词页面输入框输入关键词,或者点击Wrap布局中的按钮后push过来的。

wanandroid的接口文档如下:

https://www.wanandroid.com/article/query/0/json

方法:POST
参数:
页码:拼接在链接上,从0开始。
k : 搜索关键词

这个页面结构和SingleTabListController一模一样,支持下拉与上拉,基本上只是接口不同罢了。返回的模型依旧是Info,之前已经写过这个模型了,这个就不在复述。

网页加载页编写

image.png

这个页面其实和之前账户管理模块有点联系的,具体说来,没有登录的时候,右侧没有收藏按钮,登录后,右侧是有收藏按钮的。

然后,有一个收藏与取消收藏的接口,就是这个这个按钮进行绑定的。

在之前的AccountInfo模型中有一个collectIds属性,是一个[Int]类型,可以通过它来判断该详细页中WebLoadInfo来判断账号中是否收藏过该页面,进而展示不同的收藏效果。

以上逻辑和代码稍有复杂,建议在源码中看WebViewController.swift文件。

其他页面

排名页面已经在最开始进行了独立讲解,详细可以看下面4篇文章进行了解:

积分排行列表页编写

积分排行列表页下拉与上拉刷新功能编写

使用RxSwift封装下拉与上拉刷新功能编写

ViewModel抽离积分排行列表页的逻辑

我的积分页面和排名页面结构基本一致,只是接口不同。

我的收藏页面和SingleTabListController页面结构一致,只是接口不同。

开源框架引用,这个页面更多的使用了第三方AcknowList

Api.My与MyService的注意事项

extension Api {
    /// 我的 取消收藏和点击收藏操作为post,其他为get
    enum My {
        static let coinRank = "coin/rank/"
        
        static let userCoinInfo = "lg/coin/userinfo/json"
        
        static let myCoinList = "lg/coin/list/"
        
        static let collectArticleList = "lg/collect/list/"
        
        static let collectArticle = "lg/collect/"

        static let unCollectArticle = "lg/uncollect_originId/"
    }
}

Api中以lg开头的接口必须登录才能有数据,而且必须在Moya中添加请求头才能请求成功!

还记这个段代码吗:

extension AccountManager {
    /// 已登录请求头处理
    var cookieHeaderValue: String {
        if let username = accountInfo?.username, let password = accountInfo?.password {
          return "loginUserName=\(username);loginUserPassword=\(password)";
        } else {
          return ""
        }
    }
}

我们先为Moya中的TargetType写一个分类:

extension TargetType {
    var loginHeader: [String : String]? {
        return AccountManager.shared.isLogin.value ? ["cookie": AccountManager.shared.cookieHeaderValue] : nil
    }
}

然后在MyService中直接调用即可:

enum MyService {
    case coinRank(_ page: Int)
    case userCoinInfo
    case myCoinList(_ page: Int)
    case collectArticleList(_ page: Int)
    case collectArticle(_ collectId: Int)
    case unCollectArticle(_ collectId: Int)
}

extension MyService: TargetType {
    var baseURL: URL {
        return URL(string: Api.baseUrl)!
    }
    
    var path: String {
        switch self {
        case .coinRank(let page):
            return Api.My.coinRank + page.toString + "/json"
        case .userCoinInfo:
            return Api.My.userCoinInfo
        case .myCoinList(let page):
            return Api.My.myCoinList + page.toString + "/json"
        case .collectArticleList(let page):
            return Api.My.collectArticleList + page.toString + "/json"
        case .collectArticle(let collectId):
            return Api.My.collectArticle + collectId.toString + "/json"
        case .unCollectArticle(let collectId):
            return Api.My.unCollectArticle + collectId.toString + "/json"
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .coinRank, .userCoinInfo, .myCoinList, .collectArticleList:
            return .get
        case .collectArticle, .unCollectArticle:
            return .post
        }
    }
    
    var sampleData: Data {
        return Data()
    }
    
    var task: Task {
        return .requestParameters(parameters: Dictionary.empty, encoding: URLEncoding.default)
    }
    
    /// 就是这里调用处理后的请求头
    var headers: [String : String]? {
        return loginHeader
    }
}

我们需要将这个请求头放进MyService中就可以了。

每日更文收到的反馈

  • 收到最多的反馈就是觉得我之前的标题《Swift:玩安卓App——XXX》非常容易误导人,甚至被吐槽为标题党。

    • 自己在取文章标题的时候并没有考虑读的人感受,只是觉得我懂是什么意思,大家应该就明明是什么意思,目前已经改了标题,后续会对6月更文的一些文章进行自我勘校,把标题也统一改了。
  • 收到大佬指出的在写基类控制器BaseViewController、BaseTableViewController的错误,目前文章已经更新,感谢大佬的指点。

  • 收到大佬对于SnapKit中remakeConstraintsupdateConstraints的区别留言,一句话真的是醍醐灌顶,后面会把两者的区别直接更新到项目的代码中。

每日更文的感受

我在更文第一天就闹了一个笑话:

QQ20210624-155923@2x.png

因为6月的更文活动是5月底发的,我晚上在家想如何连续更文30天苦恼了很久,结果没睡好,问了运营小姐姐一个很傻的问题。

我是一边学习RxSwift,一边写代码,一边更文的,压力非常的大,有点时候真的是不知所措,特别的一开始接口调试的时候,因为RxSwift的序列不太懂,所以困在这里很久。

Xnip2021-06-29_12-04-35.jpg

看看我的提交记录,其实就是撸代码最真实的写照。

有压力也会有动力,所以代码撸的特别用心,一点点啃下了RxSwift。

另外,还有就是为了大家能看明白我写的啥,我在文章中备注的代码注释,逐行逐句,这可能是我写的最用心最详细的代码注释了。

最后,我想说我没有存稿连续更了30天的,太太太难了!!!

项目地址,三倍快乐

我最先一开始是使用Flutter编写了wanandroid客户端,然后是Vue,接着是RxSwift。

我将三个项目地址都附上,也算是三倍快乐,喜欢的话记得给个Star喔~

使用Flutter编写wanandroid客户端,由于写的比较早,状态管理乱七八糟:playAndroid

uni-app下的Vuewanandroid客户端:UniAppPlayAndroid

使用RxStudy编写wanandroid客户端,记得切换到paly_android分支上:RxStudy

代码和优化还有很多要改进的地方,还望大家海涵。

明日休息

转眼七月,掘金又又又有新的更文活动,不过目前我已经榨干,想好好休息一下。

后续有打算参加掘金七月的活动,可能会从理解RxSwift中的序列入手吧。

大家加油,让我躺平一会。

由于每天都在更文,导致我直接上掘金上看文的时间大幅度减少,我错过的这些风景,也需要在下个月补回来。

喔,对了,不知不觉我已经在掘金iOS端霸榜一段时间了,纪念一下吧,虽然我不是技术能力最厉害的那个一个人,不过我也算是比较勤奋的那个人吧,^_^

IMG_D934777AF03E-1.jpeg