##第三天
今天我们主要做访客视图的处理
1.因为每个界面都有一个tableView,我们就给BaseViewController添加一个tableView
1.1 添加并设置tableView
/// 表格视图 - 如果没有登录,就不创建
var tableView:UITableView?
// 设置表格视图
func setupTableView() {
tableView = UITableView(frame: view.bounds, style: .plain)
view.insertSubview(tableView!, belowSubview: navigationBar)
// 设置数据源和代理
tableView?.delegate = self
tableView?.dataSource = self
// 设置内容缩进
tableView?.contentInset = UIEdgeInsets(top: navigationBar.bounds.height, left: 0, bottom: tabBarController?.tabBar.bounds.height ?? 49, right: 0)
}
1.2 通过一个extension遵守tableView的协议,实现代理方法
// MARK: - tableView delegate
extension XQWBBaseViewController: UITableViewDelegate, UITableViewDataSource {
// 基类准备方法,子类具体实现
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
}
// 这里return 0 和 return UITableViewCell() 只是为了语法正确,具体的返回还需要子类重写实现
```
1.3 给tableView绑定假数据,添加上拉/下拉控件
- 创建 refreshControl
/// 刷新控件
var refreshControl: UIRefreshControl?
/// 区分上拉刷新标记
var isPullup = false
- 设置 refreshControl
// 设置刷新控件 refreshControl = UIRefreshControl() tableView?.addSubview(refreshControl!) refreshControl?.addTarget(self, action: #selector(loadData), for: .valueChanged)
- 在tableView的delegate方法中设置上拉刷新和下拉加载
// 在显示最后一行的时候上拉刷新 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // 1.判断是不是最后一行 let row = indexPath.row // 行 let section = tableView.numberOfSections - 1 // 最后一组 if row < 0 || section < 0 { return } let count = tableView.numberOfRows(inSection: section) // 最后一点组的的行数 if row == (count - 1) && !isPullup { isPullup = true loadData() } }
- 子类实现loadData()方法加载自己的数据
/// 加载数据 override func loadData() { // 异步延时加载数据 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
for i in 0..<10 {
if self.isPullup {
self.statusList.append("上拉\(i)")
}else {
self.statusList.insert(i.description, at: 0)
}
}
self.isPullup = false
self.refreshControl?.endRefreshing()
self.tableView?.reloadData()
}
}
PS:到这里,基类tableView就基本设置好了
### 2.设置用户未登录时的访客视图
2.1.这是一个用户标记,判断用户是否登录
/// 用户登录标记 var userLogon = false
2.2 抽取一个继承自UIView的VisitorView
- 声明需要的属性
// MARK: - 控件 // icon lazy var iconView:UIImageView = UIImageView(image: UIImage(named: "visitordiscover_feed_image_smallicon")) // maskview lazy var maskIconView:UIImageView = UIImageView(image: UIImage(named: "visitordiscover_feed_mask_smallicon")) // house lazy var houseView:UIImageView = UIImageView(image: UIImage(named: "visitordiscover_feed_image_house")) // label lazy var tipLabel:UILabel = UILabel.cz_label(withText: "关注一些人,什么东西,关注一些人,什么东西,关注一些人,什么东西", fontSize: 14, color: UIColor.darkGray) // leftBtn lazy var registorBtn:UIButton = UIButton.cz_textButton("注册", fontSize: 16, normalColor: UIColor.orange, highlightedColor: UIColor.black, backgroundImageName: "common_button_white_disable") // rightBtn lazy var loginBtn:UIButton = UIButton.cz_textButton("登录", fontSize: 16, normalColor: UIColor.darkGray, highlightedColor: UIColor.black, backgroundImageName: "common_button_white_disable")
- 取消autoresiziong,使用iOS原生的自动布局设置界面(这里只列出一个控件的代码)
// 2.取消autoresiziong for v in subviews { v.translatesAutoresizingMaskIntoConstraints = false } // 3.自动布局 let margin:CGFloat = 20; // iconView addConstraint(NSLayoutConstraint(item: iconView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0)) addConstraint(NSLayoutConstraint(item: iconView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: -60))
```
####PS: 对于iOS 原生的自动布局:
```
view1.attr1 = view2.attr2 * multiplier + constant
// view1的某个属性值 = view2的某个属性值的 multiplier 倍 + 偏移量 constant
// 在定义宽高属性的时候将 toItem 参数设置为 nil即可
```
- 用VFL来写的话,代码如下:
```
// maskIconView
// views 是VFL 中控件名字和实际控件的名字映射
// metrics 是VFL 中常数的映射关系
let viewDict = ["maskIconView":maskIconView,"registorBtn":registorBtn] as [String : AnyObject]
let metrics = ["spacing":20]
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[maskIconView]-0-|",
options: [],
metrics: nil,
views: viewDict))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[maskIconView]-(spacing)-[registorBtn]",
options: [],
metrics: metrics,
views: viewDict))
```
2.3 设置圆圈转动动画
```
// 旋转动画
private func startAnimation() {
let ani = CABasicAnimation(keyPath: "transform.rotation")
ani.toValue = 2 * M_PI
ani.repeatCount = MAXFLOAT
ani.duration = 15
ani.isRemovedOnCompletion = false
iconView.layer.add(ani, forKey: nil)
}
```
3.设置视图数据
3.1 声明一个字典属性,通过disSet方法实现对访客视图数据的加载
```
// MARK: - 设置访客视图信息
// 访客视图信息字典
var visitorInfo : [String:String]? {
didSet {
// 1. 取字典信息
guard let imageName = visitorInfo?["imageName"],
let message = visitorInfo?["message"] else {
return
}
// 2. 设置消息
tipLabel.text = message
// 3. 设置图片 (通过图片名字判断是否为主页)
if imageName == "" {
startAnimation()
return
}
iconView.image = UIImage(named: imageName)
houseView.isHidden = true
maskIconView.isHidden = true
}
}
```
3.2 修改创建每个视图时的字典信息,添加visitorView信息
```
// 首页
["clsName":"XQWBHomeViewController", "title":"首页", "imgName":"home", "visitorInfo":["imageName":"", "message":"关注一些人,回这里看看有什么惊喜"]]
```
3.3 参考淘宝等APP,tabbar图片在一些特殊的时间会变,修改tabbar信息的获取方式 ####大致流程图如下所示: - 建立AppDelegate的extension,获取服务器信息
```
private extension AppDelegate {
func loadAppInfo() {
// 1. 模拟异步
DispatchQueue.global().async {
// 1. url
let url = Bundle.main.url(forResource: "main.json", withExtension: nil)
// 2. data
let data = NSData(contentsOf: url!)
// 3. 写入磁盘
let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let jsonPath = (docDir as NSString).appendingPathComponent("main.json")
data?.write(toFile: jsonPath, atomically: true)
print("程序加载完毕\(jsonPath)")
}
}
}
```
- 修改主页面创建子控制器逻辑
```
// 设置所有字控制器
func setupChildControllers() {
// 获取沙盒路径
let docDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let jsonPath = (docDir as NSString).appendingPathComponent("main.json")
// 加载data
var data = NSData(contentsOfFile: jsonPath)
// 判断data是否为空
if data == nil {
let path = Bundle.main.path(forResource: "main.json", ofType: nil)
data = NSData(contentsOfFile: path!)
}
// 反序列化
// 从bundle加载json
guard let array = try?JSONSerialization.jsonObject(with: data as! Data, options: []) as! [[String:AnyObject]] else {
return
}
// 遍历数组,创建控制器
var arrayM = [UIViewController]()
for dict in array {
arrayM.append(controller(info: dict as [String : AnyObject]))
}
viewControllers = arrayM
}
```