本案例设计思路没什么难的地方,只要掌握了CAShapeLayer +
在vc中测试方式:
UIBezierPath
效果图如下:
与基本动画 的使用,设计出来完全没问题,直接奉送代码:
import UIKit
/// wegt结构体来控制提示文本的信息
struct TextTipsInfo {
var position : CGRect
var color : UIColor
var font : UIFont
var text : String
var fontSize : CGFloat
}
/// 类似安卓Toast对象
class ToastView: UIView {
lazy var textLayer : (TextTipsInfo) ->VerticalTextLayer = {(textInfo : TextTipsInfo) -> VerticalTextLayer in
let tmpLayer : VerticalTextLayer = VerticalTextLayer()
tmpLayer.frame = CGRect.init(x: textInfo.position.origin.x,
y: textInfo.position.origin.y,
width: textInfo.position.size.width,
height: textInfo.position.size.height)
tmpLayer.foregroundColor = textInfo.color.cgColor;
tmpLayer.alignmentMode = kCAAlignmentCenter;
tmpLayer.isWrapped = true;
tmpLayer.font = textInfo.font
tmpLayer.fontSize = textInfo.fontSize
tmpLayer.string = textInfo.text
tmpLayer.contentsScale = UIScreen.main.scale;
return tmpLayer
}
lazy var circleLayer : CAShapeLayer = CAShapeLayer()
lazy var successLayer : CAShapeLayer = CAShapeLayer()
lazy var failLayer : CAShapeLayer = CAShapeLayer()
lazy var centerPos : CGPoint = {[unowned self]() -> CGPoint in
return CGPoint.init(x: self.frame.width / 2, y: self.frame.height / 2 - 10)
}()
lazy var animate : CABasicAnimation = {() -> CABasicAnimation in
let anim : CABasicAnimation = CABasicAnimation.init(keyPath: "strokeEnd")
anim.duration = 0.7
anim.fromValue = 0.0
anim.toValue = 1.0
anim.fillMode = kCAFillModeForwards
anim.isRemovedOnCompletion = false
anim.delegate = self as CAAnimationDelegate
anim.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear)
return anim
}()
lazy var bIsSuccess : Bool = false //当使用动画模式时,是否播放成功动画
var bIsPureTypeModel : Bool = false //是否为纯文本模式
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func initAnimLayer(success : Bool) {
setCircleAttr(radius: 25, color: UIColor.green, strokWidth: 2.0)
guard success else {
setFailLayer(color: UIColor.green, strokWidth: 2.0)
return
}
setSuccessLayer(color: UIColor.green, strokWidth: 2.0)
}
func setCircleAttr(radius : CGFloat,color: UIColor,strokWidth : CGFloat){
let path : UIBezierPath = UIBezierPath.init()
path.addArc(withCenter: centerPos, radius: radius, startAngle: 0, endAngle: 3.1415926 * 2, clockwise: true)
circleLayer.lineWidth = strokWidth
circleLayer.path = path.cgPath
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.strokeColor = UIColor.green.cgColor
self.layer.addSublayer(circleLayer)
}
func setSuccessLayer(color : UIColor, strokWidth : CGFloat) {
let successPath : UIBezierPath = UIBezierPath.init()
successPath.move(to: CGPoint.init(x: centerPos.x - 15, y: centerPos.y - 10)) //线的表达式为: y = k *x + 5 其中 k = -1
successPath.addLine(to: CGPoint.init(x: centerPos.x - 2, y: centerPos.y + 3))
successPath.move(to: CGPoint.init(x: centerPos.x - 2, y: centerPos.y + 3)) //线的表达式为: y = -k * x 其中 k = -1
successPath.addLine(to: CGPoint.init(x: centerPos.x + 15, y: centerPos.y - 15))
successLayer.lineWidth = strokWidth
successLayer.path = successPath.cgPath
successLayer.fillColor = UIColor.clear.cgColor
successLayer.strokeColor = color.cgColor
successLayer.strokeEnd = 0.0
self.layer.addSublayer(successLayer)
}
func setFailLayer(color : UIColor, strokWidth : CGFloat) {
let failPath : UIBezierPath = UIBezierPath.init()
failPath.move(to: CGPoint.init(x: centerPos.x - 12.5, y: centerPos.y - 12.5)) //线的表达式为: y = k *x +
failPath.addLine(to: CGPoint.init(x: centerPos.x + 12.5, y: centerPos.y + 12.5)) //每一条线的斜率 = 1
failPath.move(to: CGPoint.init(x: centerPos.x - 12.5, y: centerPos.y + 12.5)) //线的表达式为: y = -k * x 其中 k = -1
failPath.addLine(to: CGPoint.init(x: centerPos.x + 12.5, y: centerPos.y - 12.5))
failLayer.lineWidth = strokWidth
failLayer.path = failPath.cgPath
failLayer.fillColor = UIColor.clear.cgColor
failLayer.strokeColor = color.cgColor
failLayer.strokeEnd = 0.0
self.layer.addSublayer(failLayer)
}
func setTextLayer(textInfo : TextTipsInfo){
self.layer.addSublayer(textLayer(textInfo))
}
func toast(success : Bool,withTitle : String) {
self.bIsSuccess = success
initAnimLayer(success:success)
circleLayer.add(animate, forKey: "circleAnim")
setTextLayer(textInfo: TextTipsInfo.init(position: CGRect.init(x: centerPos.x - self.frame.width / 2,
y: self.frame.height - 30,
width: self.frame.width,
height: 30),
color: UIColor.white,
font: UIFont.systemFont(ofSize: 2),
text: withTitle,
fontSize: 14))
}
/// 只显示文本模式
///
/// - Parameters:
/// - text: 文本内容
/// - color: 字体颜色
/// - font: 字体信息
/// - size: 画笔大小
func toastOnly(text : String) {
setTextLayer(textInfo: TextTipsInfo.init(position: CGRect.init(x: centerPos.x - self.frame.width / 2,
y: centerPos.y - 40 / 2,
width: self.frame.width,
height: 40),
color: UIColor.white,
font: UIFont.systemFont(ofSize: 2),
text: text,
fontSize: 14))
recycRes()
}
func recycRes() {
let time: TimeInterval = 1
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + time) {[unowned self] in
UIView.animate(withDuration: 0.5, animations: {
self.alpha = 0
}, completion: {(true) -> Void in
self.removeFromSuperview()
})
}
}
}
extension ToastView : CAAnimationDelegate{
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if(anim == circleLayer.animation(forKey: "circleAnim")){
guard self.bIsSuccess else {
failLayer.add(animate, forKey: "failAnim")
return
}
successLayer.add(animate, forKey: "successAnim")
}else if(anim == successLayer.animation(forKey: "successAnim") || anim == failLayer.animation(forKey: "failAnim")){
recycRes()
}
}
}
/// 本类使用CATextLayer文本垂直居中
class VerticalTextLayer : CATextLayer{
override func draw(in ctx: CGContext) {
let fontSize = self.fontSize
let height = self.bounds.size.height
let deltaY = (height-fontSize)/2 - fontSize/6
ctx.saveGState()
ctx.translateBy(x: 0.0, y: deltaY)
super.draw(in: ctx)
ctx.restoreGState()
}
}
在vc中测试方式:
override func viewDidLoad() {
initView()
let btnSuccessToast : UIButton = UIButton.init(frame: CGRect.init(x: 10, y: 400, width: 80, height: 40))
btnSuccessToast.backgroundColor = UIColor.gray
btnSuccessToast.tag = 41
btnSuccessToast.setTitle("加载成功", for: UIControlState.normal)
btnSuccessToast.addTarget(self, action: #selector(onClick), for: .touchUpInside)
self.view.addSubview(btnSuccessToast)
let btnFailToast : UIButton = UIButton.init(frame: CGRect.init(x: 100, y: 400, width: 80, height: 40))
btnFailToast.backgroundColor = UIColor.gray
btnFailToast.tag = 42
btnFailToast.setTitle("加载失败", for: UIControlState.normal)
btnFailToast.addTarget(self, action: #selector(onClick), for: .touchUpInside)
self.view.addSubview(btnFailToast)
let btnTextToast : UIButton = UIButton.init(frame: CGRect.init(x: 200, y: 400, width: 80, height: 40))
btnTextToast.backgroundColor = UIColor.gray
btnTextToast.tag = 43
btnTextToast.setTitle("文本模式", for: UIControlState.normal)
btnTextToast.addTarget(self, action: #selector(onClick), for: .touchUpInside)
self.view.addSubview(btnTextToast)
let btncd : UIButton = UIButton.init(frame: CGRect.init(x: 290, y: 400, width: 80, height: 40))
btncd.backgroundColor = UIColor.gray
btncd.tag = 44
btncd.setTitle("倒计时动画", for: UIControlState.normal)
btncd.addTarget(self, action: #selector(onClick), for: .touchUpInside)
self.view.addSubview(btncd)
}
func onClick(button: UIButton){
switch button.tag {
case 41:
//初始toast
let toast : ToastView = ToastView.init(frame: CGRect.init(x: getScreenSize().width / 2 - 50, y: getScreenSize().height / 2 - 50, width: 100, height: 100))
toast.backgroundColor = UIColor.gray
toast.toast(success: true,withTitle: "加载成功")
self.view.addSubview(toast)
break
case 42:
//初始toast
let toast : ToastView = ToastView.init(frame: CGRect.init(x: getScreenSize().width / 2 - 50, y: getScreenSize().height / 2 - 50, width: 100, height: 100))
toast.backgroundColor = UIColor.gray
toast.toast(success: false,withTitle: "加载失败")
self.view.addSubview(toast)
break;
case 43 :
//初始toast
let toast : ToastView = ToastView.init(frame: CGRect.init(x: getScreenSize().width / 2 - 150, y: getScreenSize().height / 2 - 150, width: 300, height: 300))
toast.backgroundColor = UIColor.gray
toast.toastOnly(text: "加载成功")
self.view.addSubview(toast)
break;
case 44:
let countDowm : CountDownView = CountDownView.init(frame: CGRect.init(x: self.getScreenSize().width / 2 - 100, y: self.getScreenSize().height / 2 - 100, width: 100, height: 100))
countDowm.setCircleAttr(radius: 25, color: UIColor.green, strokWidth: 2.0)
countDowm.setTextAttr(initText: "10",
color: UIColor.black,
font: UIFont.systemFont(ofSize: 10),
size: CGSize.init(width: 50, height: 50))
countDowm.countDownListener = self
countDowm.startCountDown(duration: 10)
countDowm.backgroundColor = UIColor.gray
self.view.addSubview(countDowm)
break;
default:
break;
}
}