想实现的demo效果:
新建工程
工程左侧新建一个Group,把Main.storyboard、Assets.xcassets、LaunchScreen.storyboard、Info.plist等文件放到新建的文件夹中
此时run工程会报错:Build input file cannot be found: '/Users/dongao/Desktop/TestQiushi/TestQiushi/Info.plist'
是因为Info.plist文件地址被修改了,需要重新设置,设置方式如下:
重新build即可
设置AppIcon图标
设置启动页
苹果审核新规
背景:WWDC在2019有session提出。到2020年4月,上架APP的启动页必须使用LaunchScreen.storyboard,不能再使用assert方式了。后面延迟到了2020年6月,现在6月已过,就来说下怎么用LaunchScreen.storyboard搭建启动图吧,由于篇幅较长,请移步另一篇文章,专门研究一下启动图的设置iOS LaunchScreen.storyboard 设置启动页的问题
创建TabbarController
-
整理左侧文件,先创建一个Main文件夹,把AppDelegate.swift和SceneDelegate.swift放到Main文件夹中,此步也可以省略,按照个人习惯来
-
因为要做的demo跟控制器是TabbarController而不是自带的ViewController,可以把Main.storyboard里的ViewController删除,换成TabbarController,再继续之后的操作
删除Main.storyboard里的ViewController如图:
新建Main.storyboard里的TabbarController如下图:
删除之后的状态如下图:
在左侧Main文件夹中新建TabbarController
Swift中新建文件不需要加前缀
原因:
oc中新建自己的文件需要加前缀是因为防止和其他第三方库中的文件有冲突,而Swift项目中,如果真的和其他的三方库名称有冲突,则可以库的名称.xxx文件名
来避免冲突,所以Swift新建文件时不需要加前缀
然后回到Main.storyboard文件中
代码:
TabbarViewController.swift
class TabbarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
setValue(TabBar(), forKeyPath: "tabBar")//系统自带的tabBar属性是只读的,用kvo把系统的tabBar替换为自己封装的TabBar,方便修改一些东西
// tabBar.tintColor = UIColor.black//设置tabbar的item的颜色
tabBar.barTintColor = UIColor.white//设置tabbar背景色
// print(tabBar)//<TestQiushi.TabBar: 0x7f920bf09680; baseClass = UITabBar; frame = (0 795; 390 49); autoresize = W+TM; layer = <CALayer: 0x600002385d40>> 说明更换成功
addChild("糗事", "btn", "btn_sel", HomeViewController.self)
addChild("动态", "btn", "btn_sel", TrendViewController.self)
addChild("直播", "btn", "btn_sel", ThreeViewController.self)
addChild("四页", "btn", "btn_sel", FourViewController.self)
addChild("五页", "btn", "btn_sel", FiveViewController.self)
}
func addChild(_ title:String,
_ image:String,
_ selectedImage:String,
_ type:UIViewController.Type) {
let child = UINavigationController(rootViewController: type.init())
child.title = title
child.tabBarItem.image = UIImage(named: image)
child.tabBarItem.selectedImage = UIImage(named: selectedImage)
child.tabBarItem.setTitleTextAttributes([
NSAttributedString.Key.foregroundColor:UIColor.black
], for: .selected)//设置文字被选中时的颜色
//图片在Assets里边直接设置,如果不设置,会默认为系统自动填充颜色为蓝色,可以设置原图色
addChild(child)
}
}
TabBar.swift
class TabBar: UITabBar {
override func layoutSubviews() {
super.layoutSubviews()
// print(subviews)
/*
[<_UIBarBackground: 0x7fb3d8409c10; frame = (0 0; 390 83); userInteractionEnabled = NO; layer = <CALayer: 0x600001416800>>, <UITabBarButton: 0x7fb3d850fca0; frame = (2 1; 74 48); opaque = NO; layer = <CALayer: 0x60000147a120>>, <UITabBarButton: 0x7fb3d841bdc0; frame = (80 1; 74 48); opaque = NO; layer = <CALayer: 0x60000147a560>>, <UITabBarButton: 0x7fb3d84286b0; frame = (158 1; 74 48); opaque = NO; layer = <CALayer: 0x60000147a860>>, <UITabBarButton: 0x7fb3d8429660; frame = (236 1; 74 48); opaque = NO; layer = <CALayer: 0x60000147ab60>>, <UITabBarButton: 0x7fb3d842a610; frame = (314 1; 74 48); opaque = NO; layer = <CALayer: 0x60000147ae60>>]
*/
/*把tabbar上的button和title向上移一点*/
for button in subviews where button is UIControl {//过滤掉UIBarBackground,只剩下UITabBarButton
var frame = button.frame
frame.origin.y = -2
button.frame = frame
}
}
}
API.swift:
struct API {
static let imgrank = "http://m2.qiushibaike.com/article/list/imgrank"
// func url(path:String) -> String {
//
// }//多个地址可以用方法去拼接“固定地址+域名”
}
Comment.swift
struct Comment:Convertible {
let floor:Int = 0
let created_at:Int = 0
let content:String = ""
let parentId:Int = 0
let likeCount:Int = 0
let user:User! = nil
func kj_modelKey(from property:Property) -> ModelPropertyKey {
return property.name.kj.underlineCased()
}
}
User.swift
struct User:Convertible {
let thumb:String = ""
let medium:String = ""
let age:Int = 0
let id:String = ""
let name:String = ""//对应后台字段login
func kj_modelKey(from property:Property) -> ModelPropertyKey {
if property.name == "name" {
return "login"//对应的服务器名字
}
return property.name
}
}
Item.swift
struct User:Convertible {
let thumb:String = ""
let medium:String = ""
let age:Int = 0
let id:String = ""
let name:String = ""//对应后台字段login
func kj_modelKey(from property:Property) -> ModelPropertyKey {
if property.name == "name" {
return "login"//对应的服务器名字
}
return property.name
}
}
HomeViewController.swift
class HomeViewController: UIViewController {
lazy var tableView:UITableView = UITableView()
lazy var items = [Item]()
static let ItemCellId = "item"
var page = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = view.bounds
tableView.delegate = self
tableView.dataSource = self
// tableView.register(UITableViewCell.self, forCellReuseIdentifier: Self.ItemCellId)
view.addSubview(tableView)
let header = MJRefreshNormalHeader(refreshingBlock: self.loadNewData)
header.beginRefreshing()
tableView.mj_header = header
tableView.mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: self.loadMoreData)
}
func loadNewData(){
request(API.imgrank,parameters: ["page":1]).responseJSON {[weak self]response in
guard let dict = response.result.value else {return}
let jsons = JSON(dict)["items"].arrayObject
let models = modelArray(from: jsons!, Item.self)
self?.items.removeAll()
self?.items.append(contentsOf: models)
self?.tableView.reloadData()
self?.tableView.mj_header?.endRefreshing()
self?.page = 1
}
}
func loadMoreData() {
request(API.imgrank,parameters: ["page":page + 1]).responseJSON {[weak self]response in
guard let dict = response.result.value else {return}
let jsons = JSON(dict)["items"].arrayObject
let models = modelArray(from: jsons!, Item.self)
self?.items.append(contentsOf: models)
self?.tableView.reloadData()
self?.tableView.mj_footer?.endRefreshing()
self?.page += 1
}
}
}
//同一个文件中的extension和写在class里边没什么区别
extension HomeViewController:UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
tableView.mj_footer?.isHidden = items.count == 0
//tableview底部上拉加载更多文字的字样
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var tmp = tableView.dequeueReusableCell(withIdentifier: Self.ItemCellId)
if tmp == nil {
tmp = UITableViewCell(style: .subtitle, reuseIdentifier: Self.ItemCellId)
}
let cell = tmp!
let item = items[indexPath.row]
cell.textLabel?.text = item.user.name
//为了简便,这里把webp格式的图片转为png图片
let url = item.user.thumb.replacingOccurrences(of: ".webp", with: ".png")
cell.imageView?.kf.setImage(with: URL(string: url))//(Kingfisher是不支持WebP格式的图片,需要用pod下载KingfisherWebP三方,但是KingfisherWebP下载的同时需要下载libwebp,libweb在googlecode.com/xxx,正常网速下载不下来)
return cell
}
}
extension HomeViewController:UITableViewDelegate{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
100
}
}
Swift引用三方,仿OC的pch文件:
在Bridging-Header中用#import<>
引入三方库的头文件即(项目中如果没有桥接文件,可随意新建一个oc文件,xcode会自动提示是否新建Bridging-Header文件)
TestQiushi-Bridging-Header.h
#import <UIKit/UIKit.h> //Swift文件
#import <KakaJSON/KakaJSON-swift.h> //Swift文件
#import <Alamofire/Alamofire-swift.h> //Swift文件
#import <Kingfisher/Kingfisher-swift.h> //Swift文件
#import <SwiftyJSON/SwiftyJSON-swift.h> //Swift文件
#import <MJRefresh.h> //OC文件
tabbarItem图片保持原样,不会系统自动填充色
常用Swift第三方库
- 网络请求:https://github.com/Alamofire/Alamofire
- 图片下载:https://github.com/onevcat/Kingfisher
- JSON访问:https://github.com/SwiftyJSON/SwiftyJSON
- JSON - Model转换:https://github.com/kakaopensource/KakaJSON
Kingfisher注意点:
- Kingfisher默认不支持WebP格式的图片,需要额外安装KingfisherWebP
pod 'KingfisherWebP'
iconView.kf.setImage(with:URL(string: user.thumb),options:[.processor(WebPProcessor.default),.cacheSerializer(WebPSerializer.default)])