通知-###
/// 通知名
let notificationName = "XMNotification"
/// 自定义通知
NotificationCenter.default.addObserver(self,selector: #selector(notificationAction),name: NSNotification.Name(rawValue: notificationName),object: nil)
/// 接受到通知后的方法回调
@objc private func notificationAction(noti: Notification) {
/// 获取键盘的位置/高度/时间间隔...
print("___________________________________输出通知信息:")
print(noti)
}
/// 析构函数.类似于OC的 dealloc
deinit {
/// 移除通知
NotificationCenter.default.removeObserver(self)
}
/*
其他页面调用
*/
/// 发送简单数据
NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "XMNotification"),object: "Hello 2017")
/// 发送额外数据
let info = ["name":"Eric","age":21] as [String : Any]
NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "XMNotification"),object: "GoodBye 2016",userInfo: info)
代理-###
- 自定义一个选择时间控件,使用代理返回选取的时间
//DateTimePickerView文件中创建一个代理
@objc protocol DateTimePickerViewDelegate: NSObjectProtocol{
@objc optional func returnDataDelegate(selectData:String)
}
class DateTimePickerView: UIView {
weak var delegate: DateTimePickerViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor(hex:"#000000").alpha(0.4)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
/**
用户操作触发代理事件
*/
@objc func returnData(){
let dateComponents = picker.dateComponents
let date = dateComponents.date
print(date, formatter.string(from: date))
print(dateComponents)
if self.delegate!.responds(to: #selector(DateTimePickerViewDelegate.returnDataDelegate)){
self.delegate!.returnDataDelegate?(selectData: formatter.string(from: date))
}
}
//调用的页面
import UIKit
class SelectTimeViewControllerOne: BaseViewController,DateTimePickerViewDelegate{
//MARK: - DateTimePickerViewDelegate
func returnDataDelegate(selectData: String) {
//获取到代理返回的数据
}
lazy var timePickerView : DateTimePickerView = {
let view = DateTimePickerView()
view.delegate = self
return view
}()
}
闭包的逆向传值-###
A页面:
vc.selectCallBack = { () -> Void in
//闭包返回后的操作
}
B页面:
//闭包创建
typealias callSelectBlock = () -> Void
var selectCallBack : callSelectBlock!
//闭包调用
selectCallBack()
结构体类型单例-###
import UIKit
class ShareManage: NSObject {
var tValue = "df"
class var shareOnce : ShareManage {
struct tOnce {
static let instance = ShareManage()
}
return tOnce.instance
}
}
/**
验证结构体类型单例
*/
let share = ShareManage.shareOnce
share.tValue = "测试数据"
print(ShareManage.shareOnce.tValue)
根据汉字获取首字母-###
func getLetter(strInput:String?) -> String {
if strInput != nil && strInput != "" {
var ms:NSMutableString? = NSMutableString.init(string: strInput!)
CFStringTransform(ms, UnsafeMutablePointer.init(bitPattern: 0), kCFStringTransformMandarinLatin, false)
CFStringTransform(ms, UnsafeMutablePointer.init(bitPattern: 0), kCFStringTransformStripDiacritics, false)
var pyArr:[String]? = ms?.components(separatedBy: " ")
if pyArr != nil && (pyArr?.count)! > 0 {
let strResult = (pyArr![0] as NSString).substring(to: 1)
//数字
let pattern = "^[0-9]*$"
//替换后的
let str = strResult.pregReplace(pattern: pattern, with: "#")
return str.uppercased()
}
ms = nil
pyArr = nil
}
return strInput!;
}
数字转中文 最高 9999-###
// 数字转中文
func eachSection(num: Int) -> String {
var intNum = num
let chineseNumberArr = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
let chinesePositionArr = ["", "十", "百", "千"]
// 输出的中文
var chineseNum = ""
// 千位以下只有一个中文"零"
var isZero = true
for index in 0..<5 {
// 获取末尾值(取出个位)
let end = intNum % 10
// 判断该数字是否为0, 若不是0, 就直接拼接权位, 若是0, 则判断是否已经出现过中文"零"
if end == 0 {
if !isZero { // 上一位数不为0, 执行补0
isZero = true
chineseNum = chineseNumberArr[0] + chineseNum
}
}else {
isZero = false
chineseNum = chineseNumberArr[end] + chinesePositionArr[index] + chineseNum // 数字 + 权位
}
intNum = intNum / 10; // 去除原来的个位
}
if chineseNum.count >= 3 && chineseNum.prefix(3) == "零一十"{
chineseNum = String(chineseNum.suffix(chineseNum.count - 2))
}else{
chineseNum = String(chineseNum.suffix(chineseNum.count - 1))
}
return chineseNum
}
Controller 中加入自定义View-###
- xib View
lazy var headerView: SideMenuHeaderView = {
let headerView = Bundle.main.loadNibNamed("SideMenuHeaderView", owner: nil, options: nil)!.last as! SideMenuHeaderView
return headerView
}()
- 非 xib View
lazy var previewImgView:PreviewImgView = {
let _view = PreviewImgView.init(frame:CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height))
return _view
}()
渐变图层-###
let layerView = UIView()
layerView.frame = CGRect(x: 0, y: 300, width: ScreenWidth, height: 100)
// fillCode
let bgLayer1 = CAGradientLayer()
bgLayer1.colors = [UIColor(red: 1, green: 0.76, blue: 0.72, alpha: 1).cgColor, UIColor(red: 0.99, green: 0.18, blue: 0.04, alpha: 1).cgColor]
bgLayer1.locations = [0, 1]
bgLayer1.frame = layerView.bounds
bgLayer1.startPoint = CGPoint(x: 0, y: 0.5)
bgLayer1.endPoint = CGPoint(x: 1, y: 0.5)
layerView.layer.addSublayer(bgLayer1)
self.view.addSubview(layerView)
拨打电话-###
// phoneStr: 电话号码
let phone = "telprompt://" + phoneStr
if UIApplication.shared.canOpenURL(URL(string: phone)!) {
UIApplication.shared.openURL(URL(string: phone)!)
}
传入颜色返回一张纯色图片-###
func creatImageWithColor(color:UIColor)->UIImage{
let rect = CGRect(x:0,y:0,width:1,height:1)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context!.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
截屏-###
- 截取指定view
//截取屏幕
func screenSnapshot(view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0.0)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//截取指定范围
return UIImage.init(data: image?.jpegData(compressionQuality: 0.5) ?? Data()) //image
}
- 截window全屏
//截取整个屏幕
func screenSnapScreen() -> UIImage? {
//截取整个屏幕
guard let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first else { return nil }
// 用下面这行而不是UIGraphicsBeginImageContext(),因为前者支持Retina
UIGraphicsBeginImageContextWithOptions(window.bounds.size, false, 0.0)
window.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIImage.init(data: image?.jpegData(compressionQuality: 0.5) ?? Data()) //image
}
- 截屏并保存到系统相册
前提:plist文件
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要你的同意才能保存图片到本地</string>
@objc func takeScreenshotAndSave(){
UIGraphicsBeginImageContextWithOptions(CGSize(width: self.testView.frame.size.width,height: self.testView.frame.size.height ), false, 0.0); //currentView 当前的view 创建一个基于位图的图形上下文并指定大小为
self.testView.layer.render(in: UIGraphicsGetCurrentContext()!)//renderInContext呈现接受者及其子范围到指定的上下文
let viewImage = UIGraphicsGetImageFromCurrentImageContext()!//返回一个基于当前图形上下文的图片
UIGraphicsEndImageContext();//移除栈顶的基于当前位图的图形上下文
UIImageWriteToSavedPhotosAlbum(viewImage, self, #selector(saveError), nil);//然后将该图片保存到图片图
}
@objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if error != nil {
print("错误")
return
}
print("Save finished!")
}
延迟加载-###
- GCD
1.普通实现
//GCD 主线程/子线程
DispatchQueue.main.asyncAfter(deadline: .now()+5, execute:{
})
DispatchQueue.global().asyncAfter(deadline: .now()+5, execute:{
})
2.如果需要取消正在等待执行的Block操作,我们可以先将这个Block封装到DispatchWorkItem对象中,然后对其发送cancle,来取消一个正在等待执行的block。
//将要执行的操作封装到DispatchWorkItem中
let task = DispatchWorkItem { print("after!") }
//延时2秒执行
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: task)
//取消任务
task.cancel()
3.封装全局方法
import Foundation
/// 代码延迟运行
///
/// - Parameters:
/// - delayTime: 延时时间。比如:.seconds(5)、.milliseconds(500)
/// - qosClass: 要使用的全局QOS类(默认为 nil,表示主线程)
/// - closure: 延迟运行的代码
public func delay(by delayTime: TimeInterval, qosClass: DispatchQoS.QoSClass? = nil,
_ closure: @escaping () -> Void) {
let dispatchQueue = qosClass != nil ? DispatchQueue.global(qos: qosClass!) : .main
dispatchQueue.asyncAfter(deadline: DispatchTime.now() + delayTime, execute: closure)
}
///使用
//延迟5秒执行(在主线程上)
delay(by: 5) {
print("时间1:", Date())
}
//延迟5秒执行(在全局队列上,且优先级高)
delay(by: 5, qosClass: .userInitiated) {
print("时间2:", Date())
}
- timer(必须在主线程中执行)
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(someAction), userInfo: nil, repeats: false)
@objc func someAction(){
}
- Thread (在主线程会卡主界面)
Thread.sleep(forTimeInterval: 3)
//三秒后执行方法
self.xxx()
- perform(必须在主线程中执行)
self.perform(#selector(xxx), with: nil, afterDelay: 3)
// 取消
NSObject.cancelPreviousPerformRequests(withTarget: self)
系统提示框-###
let alertController = UIAlertController(title: "警告", message: "警告内容", preferredStyle: .alert)
//设置 Actions 点击出发的响应事件都写在相应的代码块里
let noAction = UIAlertAction(title: "确定", style: .cancel){ (action) -> Void in
}
let yesAction = UIAlertAction(title: "取消", style: .default){ (action) -> Void in
}
//添加 Actions,添加的先后和显示的先后顺序是有关系的
alertController.addAction(noAction)
alertController.addAction(yesAction)
//展示Alert Controller
self.present(alertController, animated: true, completion: nil)
多线程-###
- GCD简单使用
1.A、B、C任务执行完毕,再执行某方法
//获取系统存在的全局队列
let queue = DispatchQueue.global(qos: .default)
//定义一个group
let group = DispatchGroup()
//并发任务,顺序执行
queue.async(group: group) {
sleep(2)
print("block1")
}
queue.async(group: group) {
print("block2")
}
queue.async(group: group) {
print("block3")
}
//1,所有任务执行结束汇总,不阻塞当前线程
group.notify(queue: .global(), execute: {
print("group done")
})
//2,永久等待,直到所有任务执行结束,中途不能取消,阻塞当前线程
//group.wait()
print("任务全部执行完成")
2.异步加载适应于加载图片
//获取系统存在的全局队列
let queue = DispatchQueue.global(qos: .default)
//定义一个异步步代码块
queue.async {
//通过concurrentPerform,循环变量数组
DispatchQueue.concurrentPerform(iterations: 6) {(index) -> Void in
print(index)
}
//执行完毕,主线程更新
DispatchQueue.main.async {
print("done")
}
}
例:
//异步加载
//原图
var originalImage = #imageLiteral(resourceName: "007")
lazy var context: CIContext = {
return CIContext()
}()
DispatchQueue.global().async {
//获取原始图片
let inputImage = CIImage(image: self.originalImage)
//使用高斯模糊滤镜
let filter = CIFilter(name: "CIGaussianBlur")!
filter.setValue(inputImage, forKey:kCIInputImageKey)
//设置模糊半径值(越大越模糊)
filter.setValue(15, forKey: kCIInputRadiusKey)
let outputCIImage = filter.outputImage!
var rect = CGRect.init()
rect = CGRect(origin: CGPoint(x: 0, y: 200), size: CGSize(width: UIScreen.main.bounds.width * 1.5 , height: UIScreen.main.bounds.height * 1.5))
let cgImage = self.context.createCGImage(outputCIImage, from: rect)
//执行完毕,主线程更新
DispatchQueue.main.async {
self.ImgView.image = UIImage(cgImage: cgImage!)
}
}
定时器-###
///定义时间源
var codeTimer: DispatchSourceTimer?
/// 2.初始化时间源timer
func setTime(){
// 在global线程里创建一个时间源
codeTimer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
// 设定这个时间源是每秒循环一次,立即开始
codeTimer?.schedule(deadline: .now(), repeating: .seconds(1))
// 设定时间源的触发事件
codeTimer?.setEventHandler(handler: {
// 每秒计时一次
// 返回主线程处理一些事件,更新UI等等
DispatchQueue.main.async {
/**
self.lab_countDown.text = "三秒后将自动交卷(\(self.useTime))"
if(self.useTime == 0){
self.codeTimer?.cancel()
if self.confirmAction != nil{
self.confirmAction!()
}
self.dismiss(animated: true, completion: nil)
}
*/
}
})
// 启动时间源
codeTimer?.resume()
}
/// 3.退出页面时调用销毁时间源
func destructionTimer(){
self.codeTimer?.cancel()
self.codeTimer = nil
}
高斯模糊-###
- 图片整体模糊
传入图片,设置模糊值
func createGaussianBlurImage(_ image: UIImage) -> UIImage? {
guard let ciImage = CIImage(image: image) else { return nil }
// 创建高斯模糊滤镜类
guard let blurFilter = CIFilter(name: "CIGaussianBlur") else { return nil }
// key 可以在控制台打印 po blurFilter.inputKeys
// 设置图片
blurFilter.setValue(ciImage, forKey: "inputImage")
// 设置模糊值
blurFilter.setValue(3, forKey: "inputRadius")
// 从滤镜中 取出图片
guard let outputImage = blurFilter.outputImage else { return nil }
// 创建上下文
let context = CIContext(options: nil)
// 根据滤镜中的图片 创建CGImage
guard let cgImage = context.createCGImage(outputImage, from: ciImage.extent) else { return nil }
return UIImage(cgImage: cgImage)
}
- 图片圆形向外扩散模糊渐变
生成二维码-###
/// 生成二维码
func generateQRCode(_ content: String, size: CGFloat, avatar: UIImage?, foregroundColor: UIColor = .black, backgroundColor: UIColor = .white) -> UIImage? {
guard let generateFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
// 设置二维码内容
generateFilter.setValue(content.data(using: .utf8), forKey: "inputMessage")
// 设置二维码的级别(纠错率) L: 7% M(默认): 15% Q: 25% H: 30%
generateFilter.setValue("H", forKeyPath: "inputCorrectionLevel")
// 直接返回 UIImage(ciImage: outputImage) 会是模糊的二维码
guard let outputImage = generateFilter.outputImage else { return nil }
// 转化为 清晰的图像
guard let clearImage = generateNonInterpolatedQRCode(outputImage, size: size) else { return nil }
// 设置二维码 颜色
guard let colorsImage = setQRCodeColors(clearImage, foregroundColor: foregroundColor, backgroundColor: backgroundColor) else { return nil}
// 返回插入头像的二维码
return insertAvatarToQRCode(avatar, qrCodeImage: colorsImage)
}
/// 生成清晰的 二维码
func generateNonInterpolatedQRCode(_ ciImage: CIImage, size: CGFloat) -> UIImage? {
// 调整图片大小及位置(小数跳转为整数)位置值向下调整,大小只向上调整
let extent = ciImage.extent.integral
// 获取图片大小
let scale = min(size / extent.width, size / extent.height)
let outputImageWidth = extent.width * scale
let outputImageHeight = extent.height * scale
// 创建依赖于设备的灰度颜色通道
let space = CGColorSpaceCreateDeviceGray()
// 创建图形上下文
let bitmapContext = CGContext(data: nil, width: Int(outputImageWidth), height: Int(outputImageHeight), bitsPerComponent: 8, bytesPerRow: 0, space: space, bitmapInfo: 0)
// 设置缩放
bitmapContext?.scaleBy(x: scale, y: scale)
// 设置上下文渲染等级
bitmapContext?.interpolationQuality = .none
// 上下文
let context = CIContext(options: nil)
// 创建 cgImage
guard let cgImage = context.createCGImage(ciImage, from: extent) else { return nil }
// 绘图
bitmapContext?.draw(cgImage, in: extent)
// 从图形上下文中创建图片
guard let scaledImage = bitmapContext?.makeImage() else { return nil }
// 返回UIImage
return UIImage(cgImage: scaledImage)
}
/// 设置二维码前景色 和背景色
func setQRCodeColors(_ image: UIImage, foregroundColor: UIColor, backgroundColor: UIColor) -> UIImage? {
guard let colorFilter = CIFilter(name: "CIFalseColor") else { return nil }
let ciImage = CIImage(image: image)
// 设置图片
colorFilter.setValue(ciImage, forKey: "inputImage")
// 设置前景色
colorFilter.setValue(CIColor(color: foregroundColor), forKey: "inputColor0")
// 设置背景色
colorFilter.setValue(CIColor(color: backgroundColor), forKey: "inputColor1")
// 输出图片
guard let outputImage = colorFilter.outputImage else { return nil }
return UIImage(ciImage: outputImage)
}
/// 往 二维码中 插入头像
func insertAvatarToQRCode(_ avatar: UIImage?, qrCodeImage: UIImage) -> UIImage? {
guard let avatarSize = avatar?.size else { return qrCodeImage }
let qrCodeSize = qrCodeImage.size
// 开启上下文
UIGraphicsBeginImageContext(qrCodeSize)
// 设置头像的最大值
var maxAvatarSize = min(avatarSize.width, avatarSize.height)
maxAvatarSize = min(qrCodeSize.width / 3, maxAvatarSize)
// 绘制二维码图片
qrCodeImage.draw(in: CGRect(origin: .zero, size: qrCodeSize))
// 绘制头像
avatar?.draw(in: CGRect(x: (qrCodeSize.width - maxAvatarSize) / 2, y: (qrCodeSize.height - maxAvatarSize) / 2, width: maxAvatarSize, height: maxAvatarSize))
// 获取图片
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
// 关闭上下文
UIGraphicsEndImageContext()
return outputImage
}
圆形向外渐变扩散动画效果-###
lazy var btn1 : UIButton = {
let _btn = UIButton.init(frame: CGRect(x: 20, y: 260, width: 50, height: 50))
_btn.layer.cornerRadius = 25
_btn.backgroundColor = UIColor.cyan
return _btn
}()
func cycleAnimation(){
let scaleAnimation=CABasicAnimation(keyPath: "transform.scale.xy")//动画属性
scaleAnimation.fromValue=0.1//开始的大小
scaleAnimation.toValue=1.1//最后的大小
scaleAnimation.duration=3
let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity")
opacityAnimation.duration=3
opacityAnimation.keyTimes=[0, 0.4 ,0.9, 1]
opacityAnimation.values=[0.05, 0.45, 0, 0]
opacityAnimation.isRemovedOnCompletion=false
let defaultCurve = CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue: "easeIn"))
let animationGroup = CAAnimationGroup()
animationGroup.duration=3
animationGroup.repeatCount = HUGE //重复无限次
animationGroup.isRemovedOnCompletion=false
animationGroup.timingFunction = defaultCurve
animationGroup.animations=[scaleAnimation, opacityAnimation]
let spreadLayer = CALayer()
let diameter = 100 //扩散的大小
spreadLayer.bounds = CGRect(x: 0,y: 0, width: diameter, height: diameter)
spreadLayer.cornerRadius = 50 //设置圆角变为圆形
spreadLayer.position = CGPoint(x:btn1.frame.width/2,y:btn1.frame.height/2)
spreadLayer.backgroundColor = UIColor.gray.cgColor
spreadLayer.masksToBounds=true
btn1.layer.insertSublayer(spreadLayer, above: btn1.layer)//把扩散层放到按钮下面
btn1.layer.masksToBounds=true
//对层执行动画
spreadLayer.add(animationGroup, forKey: "pulse")
}
获取文本宽度-###
func getWidthForString(strTitle:String,txtFont:UIFont) -> CGFloat {
var w = CGFloat.init(0)
let size = NSString.init(string: strTitle).size(attributes: [
NSFontAttributeName:txtFont
])
w= size.width
return w
}
UITextField输入限制-###
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
// 只允许输入数字和两位小数
let expression = "^[0-9]*((\\.|,)[0-9]{0,2})?$"
// let expression = "^[0-9]*([0-9])?$" 只允许输入纯数字
// let expression = "^[A-Za-z0-9]+$" //允许输入数字和字母
let regex = try! NSRegularExpression(pattern: expression, options: .allowCommentsAndWhitespace)
let numberOfMatches = regex.numberOfMatches(in: newString, options:.reportProgress, range:NSMakeRange(0, newString.count))
if numberOfMatches == 0{
print("请输入数字")
return false
}
return true
}