1
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deploymentTarget": "12"
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
// import UniversalBlurHelper from 'uts.sdk.modules.utsXdBlur.UniversalBlurHelper';
|
||||
|
||||
import { hexToRgb } from '../libs/color.uts'
|
||||
import {XDANIMATION_FLIP3D_OPTIONS,XDANIMATION_TRANSLATE_OPTIONS,XDANIMATION_ROTATE_OPTIONS,XDANIMATION_SCALE_OPTIONS} from "../interface.uts"
|
||||
import { UIView } from 'UIKit';
|
||||
import { CGFloat } from 'CoreFoundation';
|
||||
import { CABasicAnimation } from "QuartzCore";
|
||||
|
||||
export class xAnimationS {
|
||||
public static translate(opts:XDANIMATION_TRANSLATE_OPTIONS){
|
||||
if(opts.ele == null) return
|
||||
let view = (opts.ele as UniElement).getIOSView()! as UIView
|
||||
let duration_s = ((opts.duration==null?1000:(opts.duration!))/1000).toDouble()
|
||||
let delay_s = ((opts.delay==null?0:(opts.delay!))/1000).toDouble()
|
||||
let translation_s = (opts.translation==null?0:(opts.translation!)).toInt()
|
||||
let from_s = new CGFloat((opts.from==null?0:(opts.from!)))
|
||||
let len_s = new CGFloat(opts.len==null?0:(opts.len!))
|
||||
let loop_s = (opts.loop==null?0:(opts.loop!)).toInt()
|
||||
|
||||
|
||||
xdAnimation.translate(
|
||||
view=view,
|
||||
duration=duration_s,
|
||||
delay=delay_s,
|
||||
translation=translation_s,
|
||||
fromLen=from_s,
|
||||
len=len_s,
|
||||
loop=loop_s,
|
||||
start=opts.start,
|
||||
end=opts.end
|
||||
)
|
||||
}
|
||||
public static rotate(opts:XDANIMATION_ROTATE_OPTIONS){
|
||||
if(opts.ele == null) return
|
||||
let view = (opts.ele as UniElement).getIOSView()! as UIView
|
||||
let duration_s = ((opts.duration==null?1000:(opts.duration!))/1000).toDouble()
|
||||
let delay_s = ((opts.delay==null?0:(opts.delay!))/1000).toDouble()
|
||||
let from_s = new CGFloat((opts.from==null?0:(opts.from!)))
|
||||
let deg_s = new CGFloat(opts.deg==null?360:(opts.deg!))
|
||||
let loop_s = (opts.loop==null?0:(opts.loop!)).toInt()
|
||||
|
||||
xdAnimation.rotate(
|
||||
view=view,
|
||||
duration=duration_s,
|
||||
delay=delay_s,
|
||||
fromDeg=from_s,
|
||||
deg=deg_s,
|
||||
loop=loop_s,
|
||||
start=opts.start,
|
||||
end=opts.end
|
||||
)
|
||||
}
|
||||
public static scale(opts:XDANIMATION_SCALE_OPTIONS){
|
||||
if(opts.ele == null) return
|
||||
let view = (opts.ele as UniElement).getIOSView()! as UIView
|
||||
let duration_s = ((opts.duration==null?1000:(opts.duration!))/1000).toDouble()
|
||||
let delay_s = ((opts.delay==null?0:(opts.delay!))/1000).toDouble()
|
||||
let direction_s = (opts.direction==null?2:(opts.direction!)).toInt()
|
||||
let from_s = new CGFloat((opts.from==null?0:(opts.from!)))
|
||||
let scale_s = new CGFloat(opts.scale==null?1:(opts.scale!))
|
||||
let loop_s = (opts.loop==null?0:(opts.loop!)).toInt()
|
||||
|
||||
xdAnimation.scale(
|
||||
view=view,
|
||||
duration=duration_s,
|
||||
delay=delay_s,
|
||||
direction = direction_s,
|
||||
fromScale=from_s,
|
||||
scale=scale_s,
|
||||
loop=loop_s,
|
||||
start=opts.start,
|
||||
end=opts.end
|
||||
)
|
||||
|
||||
}
|
||||
public static flip3D(opts:XDANIMATION_FLIP3D_OPTIONS){
|
||||
if(opts.ele == null) return
|
||||
let view = (opts.ele as UniElement).getIOSView()! as UIView
|
||||
let duration_s = ((opts.duration==null?1000:(opts.duration!))/1000).toDouble()
|
||||
let delay_s = ((opts.delay==null?0:(opts.delay!))/1000).toDouble()
|
||||
let axis_s = (opts.axis==null?1:(opts.axis!)).toInt()
|
||||
let from_s = new CGFloat((opts.from==null?0:(opts.from!)))
|
||||
let deg_s = new CGFloat(opts.deg==null?360:(opts.deg!))
|
||||
let cameraDistance_s = new CGFloat((opts.cameraDistance==null?12:(opts.cameraDistance!)))
|
||||
let scaleZ_s = new CGFloat(opts.scaleZ==null?0.5:(opts.scaleZ!))
|
||||
let loop_s = (opts.loop==null?0:(opts.loop!)).toInt()
|
||||
|
||||
|
||||
xdAnimation.flip3D(
|
||||
view=view,
|
||||
duration=duration_s,
|
||||
delay=delay_s,
|
||||
axis = axis_s,
|
||||
fromDeg=from_s,
|
||||
deg=deg_s,
|
||||
loop=loop_s,
|
||||
cameraDistance=cameraDistance_s,
|
||||
scaleZ=scaleZ_s,
|
||||
start=opts.start,
|
||||
end=opts.end
|
||||
)
|
||||
|
||||
}
|
||||
public static clearAnimations(ele:UniElement|null,reset:boolean = true){
|
||||
if(ele == null) return
|
||||
let view = (ele as UniElement).getIOSView()! as UIView
|
||||
// xdAnimation.clearAnimations(view,reset)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
import UIKit
|
||||
import QuartzCore
|
||||
|
||||
// 动画代理类,用于回调
|
||||
class AnimationDelegate: NSObject, CAAnimationDelegate {
|
||||
var start: (() -> Void)?
|
||||
var end: (() -> Void)?
|
||||
|
||||
init(start: (() -> Void)?, end: (() -> Void)?) {
|
||||
self.start = start
|
||||
self.end = end
|
||||
}
|
||||
|
||||
func animationDidStart(_ anim: CAAnimation) {
|
||||
start?()
|
||||
}
|
||||
|
||||
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
|
||||
end?()
|
||||
}
|
||||
}
|
||||
|
||||
// 扩展CGFloat以支持角度到弧度的转换
|
||||
extension CGFloat {
|
||||
func toRadians() -> CGFloat {
|
||||
return self * .pi / 180.0
|
||||
}
|
||||
}
|
||||
|
||||
class xdAnimation {
|
||||
// 平移动画
|
||||
static func translate(
|
||||
view: UIView,
|
||||
duration: TimeInterval = 1.0,
|
||||
delay: TimeInterval = 0,
|
||||
translation: Int = 0, // 0平行移x,1平移y,2平移x,y
|
||||
fromLen: CGFloat = 0,
|
||||
len: CGFloat = 0,
|
||||
loop: Int = 0,
|
||||
start: (() -> Void)? = nil,
|
||||
end: (() -> Void)? = nil
|
||||
) {
|
||||
let timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
|
||||
// 创建动画
|
||||
let animation: CAPropertyAnimation
|
||||
|
||||
switch translation {
|
||||
case 1: // Y轴平移
|
||||
let basicAnimation = CABasicAnimation(keyPath: "transform.translation.y")
|
||||
basicAnimation.fromValue = fromLen
|
||||
basicAnimation.toValue = len
|
||||
animation = basicAnimation
|
||||
|
||||
case 2: // XY轴同时平移
|
||||
let keyframeAnimation = CAKeyframeAnimation(keyPath: "position")
|
||||
let path = CGMutablePath()
|
||||
let startPoint = CGPoint(x: view.frame.origin.x + fromLen, y: view.frame.origin.y + fromLen)
|
||||
let endPoint = CGPoint(x: view.frame.origin.x + len, y: view.frame.origin.y + len)
|
||||
path.move(to: startPoint)
|
||||
path.addLine(to: endPoint)
|
||||
keyframeAnimation.path = path
|
||||
animation = keyframeAnimation
|
||||
|
||||
default: // X轴平移
|
||||
let basicAnimation = CABasicAnimation(keyPath: "transform.translation.x")
|
||||
basicAnimation.fromValue = fromLen
|
||||
basicAnimation.toValue = len
|
||||
animation = basicAnimation
|
||||
}
|
||||
|
||||
// 设置基本属性
|
||||
animation.duration = duration
|
||||
animation.beginTime = CACurrentMediaTime() + delay
|
||||
animation.timingFunction = timingFunction // 设置时间曲线
|
||||
animation.isRemovedOnCompletion = false // 动画结束后不要移除
|
||||
animation.fillMode = .forwards // 保持动画最后一帧
|
||||
|
||||
// 设置循环
|
||||
if loop == -1 {
|
||||
animation.repeatCount = .infinity
|
||||
} else {
|
||||
animation.repeatCount = Float(loop)
|
||||
}
|
||||
|
||||
// 添加动画
|
||||
CATransaction.begin()
|
||||
CATransaction.setCompletionBlock {
|
||||
end?()
|
||||
}
|
||||
start?()
|
||||
view.layer.add(animation, forKey: "translation")
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
static func rotate(view: UIView,
|
||||
duration: TimeInterval = 1.0,
|
||||
delay: TimeInterval = 0.0,
|
||||
fromDeg: CGFloat = 0.0,
|
||||
deg: CGFloat = 360.0,
|
||||
loop: Int = 0,
|
||||
start: (() -> Void)? = nil,
|
||||
end: (() -> Void)? = nil) {
|
||||
|
||||
// 创建旋转动画
|
||||
let timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: .linear)
|
||||
let rotation = CABasicAnimation(keyPath: "transform.rotation")
|
||||
rotation.fromValue = fromDeg * .pi / 180.0 // 将度数转为弧度
|
||||
rotation.toValue = deg * .pi / 180.0 // 将度数转为弧度
|
||||
rotation.duration = duration
|
||||
rotation.beginTime = CACurrentMediaTime() + delay
|
||||
rotation.isCumulative = true
|
||||
rotation.timingFunction = timingFunction // 设置时间曲线
|
||||
rotation.isRemovedOnCompletion = false // 动画结束后不要移除
|
||||
rotation.fillMode = .forwards // 保持动画最后一帧
|
||||
|
||||
// 设置循环次数
|
||||
if loop == -1 {
|
||||
rotation.repeatCount = .infinity
|
||||
} else {
|
||||
rotation.repeatCount = Float(loop)
|
||||
}
|
||||
|
||||
// 开始时的回调
|
||||
if let startAction = start {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
startAction()
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 CATransaction 来处理动画完成后的回调
|
||||
CATransaction.begin()
|
||||
|
||||
// 设置动画完成时的回调
|
||||
CATransaction.setCompletionBlock {
|
||||
end?()
|
||||
}
|
||||
|
||||
// 添加动画到视图的层上
|
||||
view.layer.add(rotation, forKey: "rotationAnimation")
|
||||
|
||||
// 提交事务
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
// 缩放动画
|
||||
static func scale(view: UIView,
|
||||
duration: TimeInterval = 1.0,
|
||||
delay: TimeInterval = 0.0,
|
||||
direction: Int = 0,
|
||||
fromScale: CGFloat = 0.0,
|
||||
scale: CGFloat = 1.0,
|
||||
loop: Int = 0,
|
||||
start: (() -> Void)? = nil,
|
||||
end: (() -> Void)? = nil) {
|
||||
|
||||
// 创建动画集合
|
||||
var scaleAnimations = [CABasicAnimation]()
|
||||
|
||||
switch direction {
|
||||
case 1: // 竖直缩放 (Y轴)
|
||||
let scaleY = CABasicAnimation(keyPath: "transform.scale.y")
|
||||
scaleY.fromValue = fromScale
|
||||
scaleY.toValue = scale
|
||||
scaleAnimations = [scaleY]
|
||||
|
||||
case 2: // XY轴同时缩放
|
||||
let scaleX = CABasicAnimation(keyPath: "transform.scale.x")
|
||||
scaleX.fromValue = fromScale
|
||||
scaleX.toValue = scale
|
||||
|
||||
let scaleY = CABasicAnimation(keyPath: "transform.scale.y")
|
||||
scaleY.fromValue = fromScale
|
||||
scaleY.toValue = scale
|
||||
|
||||
scaleAnimations = [scaleX, scaleY]
|
||||
|
||||
default: // 水平缩放 (X轴)
|
||||
let scaleX = CABasicAnimation(keyPath: "transform.scale.x")
|
||||
scaleX.fromValue = fromScale
|
||||
scaleX.toValue = scale
|
||||
scaleAnimations = [scaleX]
|
||||
}
|
||||
|
||||
// 设置动画属性
|
||||
for animation in scaleAnimations {
|
||||
animation.duration = duration
|
||||
animation.beginTime = CACurrentMediaTime() + delay
|
||||
animation.isCumulative = true
|
||||
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) // 设置时间曲线
|
||||
animation.isRemovedOnCompletion = false // 动画结束后不要移除
|
||||
animation.fillMode = .forwards // 保持动画最后一帧
|
||||
|
||||
if loop == -1 {
|
||||
animation.repeatCount = .infinity
|
||||
} else {
|
||||
animation.repeatCount = Float(loop)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 使用 CATransaction 来管理动画的开始和结束
|
||||
CATransaction.begin()
|
||||
|
||||
// 动画开始时的回调
|
||||
if let startAction = start {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
startAction()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置动画完成时的回调
|
||||
CATransaction.setCompletionBlock {
|
||||
end?()
|
||||
}
|
||||
|
||||
// 添加动画到视图的层上
|
||||
var i=0
|
||||
for animation in scaleAnimations {
|
||||
view.layer.add(animation, forKey: "scaleAnimation"+i.toString())
|
||||
i+=1;
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
CATransaction.commit()
|
||||
}
|
||||
private func deg2rad(_ degree: CGFloat) -> CGFloat {
|
||||
return degree * .pi / 180
|
||||
}
|
||||
|
||||
// 3D翻转动画
|
||||
static func flip3D(
|
||||
view: UIView,
|
||||
duration: TimeInterval = 1.0,
|
||||
delay: TimeInterval = 0.0,
|
||||
axis: Int = 1,
|
||||
fromDeg: CGFloat = 0.0, // 旋转角度
|
||||
deg: CGFloat = 180.0, // 旋转角度
|
||||
loop: Int = 0,
|
||||
cameraDistance: CGFloat = 8.0,
|
||||
scaleZ: CGFloat = 0.8,
|
||||
start: (() -> Void)? = nil,
|
||||
end: (() -> Void)? = nil) {
|
||||
|
||||
let adjustedDeg: CGFloat = deg
|
||||
// 设置3D透视效果
|
||||
var transform = CATransform3DIdentity
|
||||
transform.m34 = -1.0 / cameraDistance
|
||||
view.layer.transform = transform
|
||||
|
||||
// 根据旋转轴选择旋转方式
|
||||
var rotationTransform: CATransform3D
|
||||
if axis == 1 { // 绕Y轴旋转
|
||||
rotationTransform = CATransform3DMakeRotation(fromDeg.toRadians(), 0, 1, 0)
|
||||
} else { // 绕X轴旋转
|
||||
rotationTransform = CATransform3DMakeRotation(fromDeg.toRadians(), 1, 0, 0)
|
||||
}
|
||||
|
||||
// 设置初始角度
|
||||
view.layer.transform = rotationTransform
|
||||
|
||||
// 执行动画
|
||||
UIView.animate(
|
||||
withDuration: duration,
|
||||
delay: delay,
|
||||
options: [.curveLinear],
|
||||
animations: {
|
||||
start?() // 执行开始时的回调
|
||||
// 计算目标角度
|
||||
let finalTransform: CATransform3D
|
||||
if axis == 1 { // 绕Y轴旋转
|
||||
finalTransform = CATransform3DMakeRotation(adjustedDeg.toRadians(), 0, 1, 0)
|
||||
} else { // 绕X轴旋转
|
||||
finalTransform = CATransform3DMakeRotation(adjustedDeg.toRadians(), 1, 0, 0)
|
||||
}
|
||||
|
||||
// 添加Z轴缩放效果
|
||||
let scaleTransform = CATransform3DScale(finalTransform, 1, 1, scaleZ)
|
||||
view.layer.transform = scaleTransform
|
||||
},
|
||||
completion: { finished in
|
||||
if loop > 1 {
|
||||
// 如果需要循环,递归调用
|
||||
flip3D(
|
||||
view: view,
|
||||
duration: duration,
|
||||
delay: delay,
|
||||
axis: axis,
|
||||
fromDeg: adjustedDeg,
|
||||
deg: fromDeg,
|
||||
loop: loop - 1,
|
||||
cameraDistance: cameraDistance,
|
||||
scaleZ: scaleZ,
|
||||
start: start,
|
||||
end: end
|
||||
)
|
||||
} else {
|
||||
end?() // 执行结束时的回调
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user