Core Animation으로 사용자 지정 완화 기능을 만드는 방법은 무엇입니까?
나는 애니메이션을 하고 있습니다.CALayer
를 CGPath
(QuadCurve) iOS에서 꽤 잘 작동합니다.하지만 애플에서 제공하는 몇 가지 기능(EaseIn/EaseOut 등)보다 더 흥미로운 완화 기능을 사용하고 싶습니다.예를 들어, 바운스 또는 탄성 함수입니다.
미디어 타이밍 기능(베지어)을 사용하면 다음과 같은 작업을 수행할 수 있습니다.
하지만 저는 좀 더 복잡한 타이밍 함수를 만들고 싶습니다.문제는 미디어 타이밍이 다음과 같은 효과를 낼 만큼 강력하지 않은 큐빅 베젤을 필요로 한다는 것입니다.
(출처: sparrow-framework.org )
위의 코드를 만드는 것은 다른 프레임워크에서 충분히 간단하기 때문에 매우 실망스럽습니다.곡선은 시간 위치 곡선이 아니라 입력 시간을 출력 시간에 매핑하는 것입니다(T-t 곡선).예를 들어 easyOutBounce(T) = t는 새 t를 반환합니다.그런 다음 이동(또는 애니메이션으로 만들어야 하는 속성)을 플롯하는 데 사용됩니다.
사용자 정의를 CAMediaTimingFunction
어떻게 해야 할지 전혀 모르겠어요, 아니면 가능한 일인지도요?대안이 있습니까?
편집:
다음은 단계의 구체적인 예입니다.매우 교육적입니다 :)
점 a에서 b까지의 선을 따라 객체를 애니메이션화하고 싶지만 위의 easyOutBounce 곡선을 사용하여 선을 따라 객체의 움직임을 "반동"하고 싶습니다.즉, a에서 b까지의 정확한 선을 따르지만, 현재의 베지어 기반의 CAMedia Timing Function을 사용하는 것보다 더 복잡한 방식으로 가속과 감속을 하게 됩니다.
이 선을 CGPath로 지정된 임의의 원곡선 이동으로 만들 수 있습니다.곡선을 따라 계속 이동해야 하지만 라인 예제와 동일한 방식으로 가속 및 감속해야 합니다.
이론적으로는 다음과 같이 작동해야 한다고 생각합니다.
이동 곡선을 키 프레임 애니메이션 이동(t) = p로 설명합니다. 여기서 t는 시간 [0..1], p는 시간 t에서 계산된 위치입니다.따라서 이동(0)은 곡선의 시작 부분에서 위치를 반환하고, 정확한 중간 부분을 이동(0.5)하고 끝 부분에서 이동(1)합니다.타이밍 함수 시간(T) = t를 사용하여 이동에 대한 t 값을 제공하면 원하는 것을 얻을 수 있습니다.바운스 효과의 경우 타이밍 함수는 시간(0.8)과 시간(0.8)에 대해 동일한 t 값을 반환해야 합니다(단, 예).다른 효과를 얻기 위해서는 타이밍 기능을 교체하기만 하면 됩니다.
(예, 앞뒤로 가는 네 개의 라인 세그먼트를 만들고 결합하여 라인 바운딩을 수행할 수 있지만 그럴 필요는 없습니다.결국, 그것은 시간 값을 위치에 매핑하는 단순한 선형 함수일 뿐입니다.
제 말이 일리가 있기를 바랍니다.
다음을 찾았습니다.
Cocoa with Love - 코어 애니메이션의 파라메트릭 가속도 곡선
하지만 블록을 사용하면 조금 더 간단하고 읽기 쉽게 만들 수 있다고 생각합니다.따라서 CAKeyframe Animation에서 다음과 같은 범주를 정의할 수 있습니다.
CAKeyframe Animation+Parametric.h:
// this should be a function that takes a time value between
// 0.0 and 1.0 (where 0.0 is the beginning of the animation
// and 1.0 is the end) and returns a scale factor where 0.0
// would produce the starting value and 1.0 would produce the
// ending value
typedef double (^KeyframeParametricBlock)(double);
@interface CAKeyframeAnimation (Parametric)
+ (id)animationWithKeyPath:(NSString *)path
function:(KeyframeParametricBlock)block
fromValue:(double)fromValue
toValue:(double)toValue;
CAKeyframeAnimation+Parametric.m:
@implementation CAKeyframeAnimation (Parametric)
+ (id)animationWithKeyPath:(NSString *)path
function:(KeyframeParametricBlock)block
fromValue:(double)fromValue
toValue:(double)toValue {
// get a keyframe animation to set up
CAKeyframeAnimation *animation =
[CAKeyframeAnimation animationWithKeyPath:path];
// break the time into steps
// (the more steps, the smoother the animation)
NSUInteger steps = 100;
NSMutableArray *values = [NSMutableArray arrayWithCapacity:steps];
double time = 0.0;
double timeStep = 1.0 / (double)(steps - 1);
for(NSUInteger i = 0; i < steps; i++) {
double value = fromValue + (block(time) * (toValue - fromValue));
[values addObject:[NSNumber numberWithDouble:value]];
time += timeStep;
}
// we want linear animation between keyframes, with equal time steps
animation.calculationMode = kCAAnimationLinear;
// set keyframes and we're done
[animation setValues:values];
return(animation);
}
@end
이제 사용 방법은 다음과 같습니다.
// define a parametric function
KeyframeParametricBlock function = ^double(double time) {
return(1.0 - pow((1.0 - time), 2.0));
};
if (layer) {
[CATransaction begin];
[CATransaction
setValue:[NSNumber numberWithFloat:2.5]
forKey:kCATransactionAnimationDuration];
// make an animation
CAAnimation *drop = [CAKeyframeAnimation
animationWithKeyPath:@"position.y"
function:function fromValue:30.0 toValue:450.0];
// use it
[layer addAnimation:drop forKey:@"position"];
[CATransaction commit];
}
당신이 원했던 것만큼 간단하지 않을 수도 있다는 것을 알지만, 그것은 시작입니다.
iOS 10부터는 두 개의 새로운 타이밍 객체를 사용하여 보다 쉽게 커스텀 타이밍 기능을 만들 수 있게 되었습니다.
유이큐빅 Timing Parameters를 사용하면 입방 베지어 곡선을 완화 함수로 정의할 수 있습니다.
let cubicTimingParameters = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.25, y: 0.1), controlPoint2: CGPoint(x: 0.25, y: 1))
let animator = UIViewPropertyAnimator(duration: 0.3, timingParameters: cubicTimingParameters)
또는 단순히 애니메이터 초기화에 제어점을 사용합니다.
let controlPoint1 = CGPoint(x: 0.25, y: 0.1)
let controlPoint2 = CGPoint(x: 0.25, y: 1)
let animator = UIViewPropertyAnimator(duration: 0.3, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
이 멋진 서비스는 곡선에 대한 제어 지점을 선택하는 데 도움이 될 것입니다.
개발자는 UISpringTimingParameters를 사용하여 댐핑 비율, 질량, 강성 및 초기 속도를 조작하여 원하는 스프링 동작을 생성할 수 있습니다.
let velocity = CGVector(dx: 1, dy: 0)
let springParameters = UISpringTimingParameters(mass: 1.8, stiffness: 330, damping: 33, initialVelocity: velocity)
let springAnimator = UIViewPropertyAnimator(duration: 0.0, timingParameters: springParameters)
지속 시간 매개 변수는 애니메이터에 계속 표시되지만 스프링 타이밍에 대해서는 무시됩니다.
이 두 가지 옵션으로 충분하지 않은 경우에는 UITimingCurveProvider 프로토콜을 확인하여 자체 타이밍 곡선을 구현할 수도 있습니다.
다양한 타이밍 매개 변수로 애니메이션을 만드는 방법에 대한 자세한 내용은 설명서에서 확인할 수 있습니다.
또한 WWDC 2016의 UIKit 애니메이션 및 전환 발전 프레젠테이션을 참조하십시오.
사용자 지정 타이밍 기능을 만드는 방법은 이 기능을 사용하는 것입니다.CAMediaTimingFunction에 ControlPoints::: 공장 메서드 포함(해당하는 initWithControlPoints::: init 메서드도 있음).이렇게 하면 타이밍 함수에 대한 베지어 곡선을 만들 수 있습니다.임의의 곡선은 아니지만 베지에 곡선은 매우 강력하고 유연합니다.통제 지점의 요령을 터득하는 데는 약간의 연습이 필요합니다.팁: 대부분의 드로잉 프로그램은 베지어 곡선을 만들 수 있습니다.컨트롤 포인트를 사용하여 표시하는 곡선에 대한 시각적 피드백을 제공합니다.
이 링크는 Apple의 설명서를 가리킵니다.빌드 전 함수가 곡선에서 구성되는 방법에 대한 짧지만 유용한 섹션이 있습니다.
편집: 다음 코드는 간단한 바운스 애니메이션을 보여줍니다.이를 위해 합성 타이밍 함수(값 및 타이밍 NSArray 속성)를 만들고 애니메이션의 각 세그먼트에 다른 시간 길이(키타임 속성)를 지정했습니다.이러한 방식으로 베지어 곡선을 구성하여 애니메이션에 대한 보다 정교한 타이밍을 구성할 수 있습니다.이것은 좋은 샘플 코드를 가진 이런 종류의 애니메이션에 대한 좋은 기사입니다.
- (void)viewDidLoad {
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 50.0)];
v.backgroundColor = [UIColor redColor];
CGFloat y = self.view.bounds.size.height;
v.center = CGPointMake(self.view.bounds.size.width/2.0, 50.0/2.0);
[self.view addSubview:v];
//[CATransaction begin];
CAKeyframeAnimation * animation;
animation = [CAKeyframeAnimation animationWithKeyPath:@"position.y"];
animation.duration = 3.0;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
NSMutableArray *values = [NSMutableArray array];
NSMutableArray *timings = [NSMutableArray array];
NSMutableArray *keytimes = [NSMutableArray array];
//Start
[values addObject:[NSNumber numberWithFloat:25.0]];
[timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
[keytimes addObject:[NSNumber numberWithFloat:0.0]];
//Drop down
[values addObject:[NSNumber numberWithFloat:y]];
[timings addObject:GetTiming(kCAMediaTimingFunctionEaseOut)];
[keytimes addObject:[NSNumber numberWithFloat:0.6]];
// bounce up
[values addObject:[NSNumber numberWithFloat:0.7 * y]];
[timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
[keytimes addObject:[NSNumber numberWithFloat:0.8]];
// fihish down
[values addObject:[NSNumber numberWithFloat:y]];
[keytimes addObject:[NSNumber numberWithFloat:1.0]];
//[timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
animation.values = values;
animation.timingFunctions = timings;
animation.keyTimes = keytimes;
[v.layer addAnimation:animation forKey:nil];
//[CATransaction commit];
}
아직 찾고 있는지는 모르겠지만, PRTween은 Core Animation이 제공하는 기능, 특히 사용자 지정 타이밍 기능을 뛰어넘는 기능을 제공한다는 점에서 상당히 인상적으로 보입니다.또한 다양한 웹 프레임워크가 제공하는 일반적인 완화 곡선이 모두는 아니더라도 여러 가지가 함께 제공됩니다.
신속한 버전 구현은 TFA 애니메이션입니다.데모는 싱커브 애니메이션입니다.사용하다TFBasicAnimation
같은CABasicAnimation
할당 제외timeFunction
이외의 블록으로timingFunction
.
핵심은 하위 클래스입니다.CAKeyframeAnimation
프레임 위치를 계산합니다.timeFunction
에1 / 60fps
간격결국 계산된 값을 모두 에 추가합니다.values
의CAKeyframeAnimation
그리고 간격별 시간keyTimes
너무.
저는 여러 애니메이션으로 애니메이션 그룹을 생성하는 블록 기반 접근법을 만들었습니다.
각 애니메이션은 속성당 33개의 파라미터 곡선 중 1개, 초기 속도의 감쇠 타이밍 기능 또는 필요에 따라 구성된 사용자 지정 스프링을 사용할 수 있습니다.
그룹이 생성되면 그룹이 보기에 캐시되며 애니메이션 키를 사용하여 애니메이션 유무에 관계없이 트리거할 수 있습니다.트리거되면 애니메이션이 프레젠테이션 계층의 값에 따라 동기화되고 그에 따라 적용됩니다.
프레임워크는 Flight Animator에서 찾을 수 있습니다.
다음은 예입니다.
struct AnimationKeys {
static let StageOneAnimationKey = "StageOneAnimationKey"
static let StageTwoAnimationKey = "StageTwoAnimationKey"
}
...
view.registerAnimation(forKey: AnimationKeys.StageOneAnimationKey, maker: { (maker) in
maker.animateBounds(toValue: newBounds,
duration: 0.5,
easingFunction: .EaseOutCubic)
maker.animatePosition(toValue: newPosition,
duration: 0.5,
easingFunction: .EaseOutCubic)
maker.triggerTimedAnimation(forKey: AnimationKeys.StageTwoAnimationKey,
onView: self.secondaryView,
atProgress: 0.5,
maker: { (makerStageTwo) in
makerStageTwo.animateBounds(withDuration: 0.5,
easingFunction: .EaseOutCubic,
toValue: newSecondaryBounds)
makerStageTwo.animatePosition(withDuration: 0.5,
easingFunction: .EaseOutCubic,
toValue: newSecondaryCenter)
})
})
애니메이션 트리거 방법
view.applyAnimation(forKey: AnimationKeys.StageOneAnimationKey)
언급URL : https://stackoverflow.com/questions/5161465/how-to-create-custom-easing-function-with-core-animation
'programing' 카테고리의 다른 글
git 로컬 버전을 원격 버전으로 교체 (0) | 2023.07.06 |
---|---|
해결 방법: 오류: Firebase 프로젝트를 나열하지 못했습니다.자세한 내용은 firebase-debug.log를 참조하십시오. (0) | 2023.07.06 |
연속 어레이와 비연속 어레이의 차이점은 무엇입니까? (0) | 2023.07.06 |
data.table vs dplyr: 한 쪽이 다른 쪽이 할 수 없는 것을 잘 할 수 있습니까, 아니면 잘 할 수 없습니까? (0) | 2023.07.06 |
유성에서 mongodb skip()와 limit()를 사용하는 방법은 무엇입니까? (0) | 2023.07.06 |