效果图:
一共由五种模式 :
- 歌词模式
- 解锁模式从左到右
- 解锁模式从右到左
- 解锁模式从左右循环
- 整体闪烁
代码如下
//
// UIView+FQshimmeringView.swift
// FQUIKit
//
import Foundation
import UIKit
let kFQBackLabel: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQbackLabel".hashValue)
let kFQFrontLabel: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQfrontLabel".hashValue)
let kFQ_shimmeringText: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "FQ_shimmeringText".hashValue)
let kFQ_shimmeringTextAlignment: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQ_shimmeringTextAlignment".hashValue)
let kFQ_shimmeringBackColor: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQ_shimmeringBackColor".hashValue)
let kFQ_shimmeringForeColor: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQ_shimmeringForeColor".hashValue)
let kFQ_shimmeringTextfont: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQ_shimmeringTextfont".hashValue)
let kFQ_shimmeringTextEdgeInsets: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQ_shimmeringTextEdgeInsets".hashValue)
let kFQ_shimmeringStyle: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQ_shimmeringStyle".hashValue)
extension UIView{
enum FQshimmeringViewStyle:NSInteger {
case FQShimmeringViewStyleOverallFilling = 1 // 歌词模式
case FQShimmeringViewStyleFadeLeftToRight = 2 // 从左到右解锁模式
case FQShimmeringViewStyleFadeRightToLeft = 3 // 从右到左解锁模式
case FQShimmeringViewStyleFadeReverse = 4 // 从左右循环
case FQShimmeringViewStyleFadeAll = 5 // 整体闪烁
}
private var FQ_BackLabel:FQ_label?{
get{
return objc_getAssociatedObject(self,kFQBackLabel) as? FQ_label
}
set(newValue){
objc_setAssociatedObject(self, kFQBackLabel, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
private var FQ_FrontLabel:FQ_label?{
get{
return objc_getAssociatedObject(self,kFQFrontLabel) as? FQ_label
}
set(newValue){
objc_setAssociatedObject(self, kFQFrontLabel, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/**
* 准备shimmering的文字
*/
var FQ_shimmeringText:NSString?{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringText) as? NSString)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringText, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.FQ_FrontLabel?.text = newValue as String?
self.FQ_BackLabel?.text = newValue as String?
}
}
/**
* shimmering文字的对其方式
*/
var FQ_shimmeringTextAlignment:NSTextAlignment?{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringTextAlignment) as? NSTextAlignment)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringTextAlignment, newValue, .OBJC_ASSOCIATION_ASSIGN)
self.FQ_BackLabel?.textAlignment = newValue ?? NSTextAlignment.center
self.FQ_FrontLabel?.textAlignment = newValue ?? NSTextAlignment.center
}
}
/**
* shimmering文字的底层颜色
*/
var FQ_shimmeringBackColor:UIColor?{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringBackColor) as? UIColor)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringBackColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.FQ_BackLabel?.textColor = newValue
}
}
/**
* shimmering文字的闪动颜色
*/
var FQ_shimmeringForeColor:UIColor?{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringForeColor) as? UIColor)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringForeColor, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.FQ_FrontLabel?.textColor = newValue
}
}
/**
* shimmering文字的大小
*/
var FQ_shimmeringTextfont:UIFont?{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringTextfont) as? UIFont)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringTextfont, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
self.FQ_BackLabel?.font = newValue
self.FQ_FrontLabel?.font = newValue
}
}
/**
* shimmering文字的边距
*/
var FQ_shimmeringTextEdgeInsets:UIEdgeInsets?{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringTextEdgeInsets) as? UIEdgeInsets)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringTextEdgeInsets, newValue, .OBJC_ASSOCIATION_ASSIGN)
self.FQ_BackLabel?.FQ_textEdgeInsets = newValue
self.FQ_FrontLabel?.FQ_textEdgeInsets = newValue
}
}
/**
* shimmeringhh动画类型
*/
var FQ_shimmeringStyle:FQshimmeringViewStyle{
get{
return (objc_getAssociatedObject(self,kFQ_shimmeringStyle) as! FQshimmeringViewStyle)
}
set(newValue){
objc_setAssociatedObject(self, kFQ_shimmeringStyle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
convenience init(frame:CGRect,shimmeringStyle:FQshimmeringViewStyle) {
self.init(frame:frame)
self.FQ_BackLabel = FQ_label(frame: self.bounds)
self.addSubview(FQ_BackLabel!)
self.FQ_FrontLabel = FQ_label(frame: self.bounds)
self.addSubview(FQ_FrontLabel!)
self.FQ_shimmeringStyle = shimmeringStyle
}
func FQ_shimmeringBeginWith(duration:TimeInterval){
self.FQ_FrontLabel?.layer.removeAllAnimations()
if (self.FQ_shimmeringStyle == .FQShimmeringViewStyleOverallFilling) {
self.createFadeRightMask()
let basicAnimation:CABasicAnimation = CABasicAnimation()
basicAnimation.keyPath = "transform.translation.x"
basicAnimation.fromValue = 0
basicAnimation.toValue = self.bounds.size.width
basicAnimation.duration = duration
basicAnimation.repeatCount = Float(LONG_MAX)
basicAnimation.isRemovedOnCompletion = false
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
self.FQ_FrontLabel?.layer.mask?.add(basicAnimation, forKey: nil)
}else if (self.FQ_shimmeringStyle == .FQShimmeringViewStyleFadeLeftToRight) {
self.createiPhoneFadeMask()
let basicAnimation:CABasicAnimation = CABasicAnimation()
basicAnimation.keyPath = "transform.translation.x"
basicAnimation.fromValue = 0
basicAnimation.toValue = self.bounds.size.width + self.bounds.size.width/2.0
basicAnimation.duration = duration
basicAnimation.repeatCount = Float(LONG_MAX)
basicAnimation.isRemovedOnCompletion = false
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
self.FQ_FrontLabel?.layer.mask?.add(basicAnimation, forKey: nil)
}else if(self.FQ_shimmeringStyle == .FQShimmeringViewStyleFadeRightToLeft){
self.createiPhoneFadeMask()
let basicAnimation:CABasicAnimation = CABasicAnimation()
basicAnimation.keyPath = "transform.translation.x"
basicAnimation.fromValue = self.bounds.size.width + self.bounds.size.width/2.0
basicAnimation.toValue = 0
basicAnimation.duration = duration
basicAnimation.repeatCount = Float(LONG_MAX)
basicAnimation.isRemovedOnCompletion = false
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
self.FQ_FrontLabel?.layer.mask?.add(basicAnimation, forKey: nil)
}else if(self.FQ_shimmeringStyle == .FQShimmeringViewStyleFadeReverse){
self.createiPhoneFadeMask()
let basicAnimation:CABasicAnimation = CABasicAnimation()
basicAnimation.keyPath = "transform.translation.x"
basicAnimation.fromValue = 0
basicAnimation.toValue = self.bounds.size.width + self.bounds.size.width/2.0
basicAnimation.duration = duration
basicAnimation.repeatCount = Float(LONG_MAX)
basicAnimation.isRemovedOnCompletion = false
basicAnimation.autoreverses = true;
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
self.FQ_FrontLabel?.layer.mask?.add(basicAnimation, forKey: nil)
}else if(self.FQ_shimmeringStyle == .FQShimmeringViewStyleFadeAll){
self.createShimmerAllMask()
let basicAnimation:CABasicAnimation = CABasicAnimation(keyPath: "opacity")
basicAnimation.repeatCount = MAXFLOAT;
basicAnimation.autoreverses = true;
basicAnimation.fromValue = 0
basicAnimation.toValue = 1.0
basicAnimation.duration = duration
self.FQ_FrontLabel?.layer.add(basicAnimation, forKey: "start")
self.FQ_FrontLabel?.layer.mask?.add(basicAnimation, forKey: nil)
}
}
private func createFadeRightMask(){
self.FQ_FrontLabel?.layer.removeAllAnimations()
let layer:CAGradientLayer = CAGradientLayer()
layer.frame = self.bounds
layer.colors = [UIColor.clear.cgColor,UIColor.red.cgColor,UIColor.black.cgColor,UIColor.clear.cgColor]
layer.locations = [0.01,0.1,0.9,0.99]
self.FQ_FrontLabel?.layer.mask = layer
}
private func createShimmerAllMask(){
self.FQ_FrontLabel?.layer.removeAllAnimations()
let layer:CAGradientLayer = CAGradientLayer()
layer.frame = self.bounds
layer.colors = [UIColor.clear.cgColor,UIColor.red.cgColor,UIColor.black.cgColor,UIColor.clear.cgColor]
layer.transform = CATransform3DIdentity
self.FQ_FrontLabel?.layer.mask = layer
}
private func createiPhoneFadeMask(){
self.FQ_FrontLabel?.layer.removeAllAnimations()
let layer:CAGradientLayer = CAGradientLayer()
layer.frame = self.bounds
layer.colors = [UIColor.clear.cgColor,UIColor.red.cgColor,UIColor.clear.cgColor]
layer.locations = [0.25,0.5,0.75];
layer.startPoint = CGPoint(x: 0, y: 0);
layer.endPoint = CGPoint(x: 1, y: 0);
self.FQ_FrontLabel?.layer.mask = layer
layer.position = CGPoint(x: -self.bounds.size.width/4.0, y: self.bounds.size.height/2.0);
}
}
记录一下坑:
其中swift 扩展动态添加属性的方法为
let kFQBackLabel: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "kFQbackLabel".hashValue)
private var FQ_BackLabel:FQ_label?{
get{
return objc_getAssociatedObject(self,kFQBackLabel) as? FQ_label
}
set(newValue){
objc_setAssociatedObject(self, kFQBackLabel, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
项目地址:https://github.com/FORMAT-qi/FQUIkit
原本是OC写的,现在用swift重新优化写一遍。
后续会持续更新该项目其它扩展和控件。