从100 Days of Swift中学习,实践
最近中途因为一些事情停更了一会,并且自后的一些项目都会比较大, 不能再通过Day record来记录, 修改为project来记录。
PROJECT 14 - JUMPBAR
I learned how to:
- Sort an Array in alphabetical order
- Create an Indexed Table View
具体思路:
1.将数据源根据首字母排序,获取首字母Array,然后通过将对应字母的数据组成一个新的数组,按顺序加入新的数组中
2.UI上创建tableview 和对应索引栏,比较简单
PROJECT 20 - SAVE DATE, LOCATION & PHOTO
I learned how to:
- Create an Accessory Input View
- Use Core Location to retrieve Location
- Work with NSDate
- 使用imagepickerViewController
- 自适应cell高度
- 辅助栏跟随键盘上升和下降显示和隐藏的,有拍照和选择照片,定位等功能。
View需要监听键盘升起和降下两个通知, 并且判断是否有输入联想框(会影响View位置)
然后提供出来两个按钮的点击响应和一个LocationLabel,一个imageView
KeyBoardStatusView: UIView
首先监听键盘
//监听键盘上升
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(_:)), name:NSNotification.Name.UIKeyboardWillShow, object: nil)
//监听键盘下降
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(_:)), name:NSNotification.Name.UIKeyboardWillHide, object: nil)
根据监听获取键盘移动距离,动画时间
@objc fileprivate func keyBoardWillShow(_ notification:NSNotification){
let kbInfo = notification.userInfo
//获取键盘的size
let kbRect = (kbInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
//键盘的y偏移量
let changeY = kbRect.origin.y - UIScreen.main.bounds.height
//键盘弹出的时间
let duration = kbInfo?[UIKeyboardAnimationDurationUserInfoKey] as!Double
UIView.animate(withDuration: duration) {
self.isHidden = false
self.transform = CGAffineTransform(translationX: 0, y:changeY)
self.alpha = 1;
}
}
@objc fileprivate func keyBoardWillHide(_ notification:NSNotification){
let kbInfo = notification.userInfo
//获取键盘的size
let kbRect = (kbInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
//键盘的y偏移量
let changeY = kbRect.origin.y - UIScreen.main.bounds.height
//键盘弹出的时间
let duration = kbInfo?[UIKeyboardAnimationDurationUserInfoKey] as!Double
UIView.animate(withDuration: duration, animations: {
self.transform = CGAffineTransform(translationX: 0, y:changeY)
self.alpha = 0
}) { (isEnd) in
if isEnd {
self.isHidden = true
}
}
}
提供按钮点击响应,以闭包的形式进行回调
typealias BtnClickClouse = (_ index:NSInteger)->Void
private var btnClickBlock:BtnClickClouse?
convenience init(_ view:UIView,_ block:@escaping BtnClickClouse) {
self.init(frame: CGRect.init(x: 0, y: view.bounds.height-40, width: UIScreen.main.bounds.width, height: 40))
setup()
self.btnClickBlock = block
}
//点击方法
@objc private func cameraBtnClick(){
self.btnClickBlock!(0)
}
@objc private func locationBtnClick(){
self.btnClickBlock!(1)
}
ViewController中初始化KeyBoardStatusView
lazy var keystatusView: KeyBoardStatusView = {
let statusview = KeyBoardStatusView.init(self.view, { (index) in
if (index == 0 ){
self.addPhoto()
}
else if (index == 1) {
self.addLocate()
}
})
return statusview
}()
- CLLocation的使用以及经纬度反编码
import CoreLocation
private var location = CLLocationManager.init()
lazy var geoCoder: CLGeocoder = {
return CLGeocoder()
}()
//添加定位信息
private func addLocate(){
location.delegate = self
//定位方式
location.desiredAccuracy = kCLLocationAccuracyBest
//授权请求
location.requestWhenInUseAuthorization()
if (CLLocationManager.locationServicesEnabled()){
//允许使用定位服务的话,开始定位服务更新
location.startUpdatingLocation()
}
else
{
CLLocationManager.authorizationStatus()
}
}
extension ViewController:CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.EntryTextView.text = "\(String(describing: locations.first?.coordinate.latitude))"+"\n\(String(describing: locations.first?.coordinate.longitude))"
geoCoder.reverseGeocodeLocation(CLLocation.init(latitude: (locations.first?.coordinate.latitude)!, longitude: (locations.first?.coordinate.longitude)!)) { (pls: [CLPlacemark]?, error: Error?) in
if error == nil {
print("反地理编码成功")
guard let plsResult = pls else {return}
let firstPL = plsResult.first
self.keystatusView.locationLabel.text = firstPL?.name
}else {
print("错误")
}
}
manager.stopUpdatingLocation()
}
}
需要设置Privacy - Location When In Use Usage Description 请求获取定位权限的描述
- 设置照片,拍照, 以及actionsheet
private func addPhoto() {
let alertActionSheet = UIAlertController.init(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
let actionCamera = UIAlertAction.init(title: "拍照", style: UIAlertActionStyle.default) { _ in
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
UIImagePickerController.availableMediaTypes(for: UIImagePickerControllerSourceType.camera)
let pick = UIImagePickerController()
pick.delegate = self
self.present(pick, animated: true, completion: nil)
}
else{
print("不支持")
}
}
let actoionPhoto = UIAlertAction.init(title: "相册", style: UIAlertActionStyle.default) { (_) in
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary)
{
UIImagePickerController.availableMediaTypes(for: UIImagePickerControllerSourceType.photoLibrary)
let pick = UIImagePickerController()
pick.delegate = self
self.present(pick, animated: true, completion: nil)
}
else{
print("不支持")
}
}
let actionCancel = UIAlertAction.init(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)
alertActionSheet.addAction(actionCamera)
alertActionSheet.addAction(actoionPhoto)
alertActionSheet.addAction(actionCancel)
self.present(alertActionSheet, animated: true, completion: nil)
}
- NSDate
lazy var formatter: DateFormatter = {
let formatter1 = DateFormatter.init()
formatter1.locale = Locale.current
formatter1.dateFormat = "MM/dd/YYY"
return formatter1
}()
let date = Date.init()
TimeLabel.text = formatter.string(from: date)
- cell自适应高度
从设计图分析,每个控件之间间隔为10,并且允许什么都不输入,那么此时只有一个TimeLabel(15的高度),cell基础高度为15+10+10。
此时,需要分情况讨论 image和text以及location的高度关系
1.当只有image或者text和location总高度不如imageView时, imageView 与 TimeLabel同在一个origin.y,那么此时cell高度为50+10+10
2.text和location的总高度大于image的高度时,使用text和location的总高度。
在model中将高度计算完成
model.swift
struct Model{
var time:String!
var image:String!
var location:String = ""
var text:String = ""
private var _height:CGFloat = 35
var height: CGFloat {
get {
return _height
}
set {
_height = newValue
}
}
public mutating func calculteHeight(_ font:CGFloat, _ width:CGFloat) {
var locationH:CGFloat = 0
var textH:CGFloat = 0
let imageH:CGFloat = 50+20 - 35
if location.count > 0 {
locationH = 25
}
if text.count > 0 {
let textFont = UIFont.systemFont(ofSize: 14)
let textString = text
let textMaxSize = CGSize(width: width, height: CGFloat(MAXFLOAT))
let size = textSize(text: textString, font: textFont, maxSize: textMaxSize)
textH = size.height + 10
}
if image.count > 0 && imageH > locationH + textH{
height = height + imageH
}
else {
height = height + locationH + textH
}
_height = height
}
private func textSize(text : String , font : UIFont , maxSize : CGSize) -> CGSize{
return text.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], attributes: [NSAttributedStringKey.font : font], context: nil).size
}
}
ViewController.swift
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var model:Model = sourceArray[indexPath.row]
//重新计算
model.calculteHeight(14.0, Screen_Width-80-80)
return model.height
}
在实际项目中实践,在书写记录中巩固。
最近用swift重写现在的一些项目, 涉及很多库 记录一下
target '****_Swift' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
pod 'MJRefresh'
pod 'Moya'
pod 'Moya/RxSwift'
pod 'RxSwift', '~> 4.0'
pod 'RxCocoa', '~> 4.0'
pod 'CTMediator' //用于解耦
pod 'SDWebImage'
pod 'MBProgressHUD'
pod 'DZNEmptyDataSet' //优秀的空白展示页
pod 'SwiftyJSON'
# pod 'PermissionScope'
# pod 'EZSwiftExtensions', '~> 1.11'
pod 'SwiftyUserDefaults'
pod 'SnapKit'
pod 'Hero'
pod 'GDPerformanceView-Swift', '~> 1.3.2'
# Pods for ****_Swift
target '****_SwiftTests' do
inherit! :search_paths
# Pods for testing
end
target '****_SwiftUITests' do
inherit! :search_paths
# Pods for testing
end
end