一、簡要說明
- 使用MVVM去解耦model、view,提升複用的可能性,同時極大減輕了controller的負擔,經過中間件viewModel處理數據源、綁定UI、處理邏輯事件。這樣當各類業務冗雜在一塊兒的時候,各業務之間的代碼能夠徹底分離,使代碼清晰。
- 使用RxSwift,能夠替換掉原有的dataSource,delegate等代理方法,作到異步 Event(事件)序列的響應式編程,方便快捷,而且邏輯更加清晰。
- 代碼中使用了優秀的開源庫:Kingfisher,SnapKit。
二、運行效果
三、目錄結構
四、頁面代碼
//
// MainViewController.swift
// ss
//
// Created by WES319 on 11/7/18.
// Copyright © 2018年 周元素. All rights reserved.
//
import UIKit
import RxCocoa
import RxSwift
import SnapKit
class MainViewController: UIViewController {
var tableView = MainTableView()
var tableViewModel: MainTableViewModel!
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "遊戲"
tableViewModel = MainTableViewModel.init(target: self)
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
}
//
// ProductModel.swift
// ss
//
// Created by WES319 on 12/7/18.
// Copyright © 2018年 周元素. All rights reserved.
//
import UIKit
class ProductModel: NSObject {
var image: String
var title: String
var content: String
required init(image: String, title: String, content: String) {
self.image = image
self.title = title
self.content = content
super.init()
}
}
//
// MainTableView.swift
// ss
//
// Created by WES319 on 11/7/18.
// Copyright © 2018年 周元素. All rights reserved.
//
import UIKit
class MainTableView: UITableView {
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
self.tableFooterView = UIView()
self.estimatedRowHeight = 100
self.register(MainTableViewCell.self, forCellReuseIdentifier: MainTableViewCell.cellID)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// MainTableViewCell.swift
// ss
//
// Created by WES319 on 11/7/18.
// Copyright © 2018年 周元素. All rights reserved.
//
import UIKit
import Kingfisher
class MainTableViewCell: UITableViewCell {
static let cellID = NSStringFromClass(MainTableViewCell.self)
var mainImageView = UIImageView()
var titleLabel = UILabel()
var contentLabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.separatorInset = UIEdgeInsetsMake(0, 15, 0, 0)
contentView.addSubview(mainImageView)
mainImageView.snp.makeConstraints { (make) in
make.top.left.bottom.equalToSuperview().inset(15)
make.height.equalTo(80).priority(999)
make.width.equalTo(mainImageView.snp.height).multipliedBy(16.0/9.0)
}
titleLabel.font = UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.black)
contentView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { (make) in
make.left.equalTo(mainImageView.snp.right).offset(10)
make.top.equalTo(mainImageView)
make.right.lessThanOrEqualToSuperview().inset(10)
}
contentLabel.textColor = UIColor.gray
contentLabel.font = UIFont.systemFont(ofSize: 13, weight: UIFont.Weight.light)
contentLabel.numberOfLines = 2
contentView.addSubview(contentLabel)
contentLabel.snp.makeConstraints { (make) in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(5)
make.right.lessThanOrEqualToSuperview().inset(15)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(image: String, title: String, content: String) {
mainImageView.kf.setImage(with: URL.init(string: image))
titleLabel.text = title
contentLabel.text = content
}
}
//
// MainTableViewModel.swift
// ss
//
// Created by WES319 on 11/7/18.
// Copyright © 2018年 周元素. All rights reserved.
//
import UIKit
import RxSwift
class MainTableViewModel: NSObject {
var dataSource = Observable.just([ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。")
,ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "仙途", content: "一萬年前,妖星蔽日,須彌山中的魔界封印失效。魔帝伺機率領魔軍涌入人界,在須彌山頂創建天幻城。一時之間生靈塗炭,火光沖天。濃重的妖魔鬼氣蔓延至高高在上的仙佛二界。衆仙家佛祖意識到如若人間淪陷,仙、佛二界也不免血光之災,故如來佛祖與太上老君,聯合仙佛二界高手與魔軍會戰於人間。這場戰爭最終以魔帝的失敗了結,魔帝、魔軍、天幻城被打回魔界,魔界入口被從新封印。")])
weak var target: MainViewController!
let disposeBag = DisposeBag()
required init(target: MainViewController) {
self.target = target
super.init()
// 綁定數據
self.dataSource.bind(to: target.tableView.rx.items(cellIdentifier: MainTableViewCell.cellID)) { (_, model, cell: MainTableViewCell) in
cell.update(image: model.image, title: model.title, content: model.content)
}.disposed(by: disposeBag)
// tableView點擊事件
self.target.tableView.rx.modelSelected(ProductModel.self).subscribe(onNext: { (model) in
print(model.title)
}).disposed(by: disposeBag)
self.target.tableView.rx.itemSelected.subscribe(onNext: { (indexPath) in
print(indexPath.row)
self.target.tableView.deselectRow(at: indexPath, animated: true)
}).disposed(by: disposeBag)
}
}