想要在几个视图控制器中使用下面的代码(UIImageView淡入/淡出),但不想让它在许多位置编码。我一直在研究使用类别,协议和扩展。我知道这里已经讨论了这些概念,但还没有找到一个更通用的答案。
如果我要使用一个类别,它将以哪个类为基础? UIView的? NSObject的?
Apple的Working with Protocols似乎是一种可能的解决方案,其中就是这句话:
在对象的类未知或需要保持隐藏的情况下,协议也很有用。
请建议为什么要使用另一个。
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.8 delay:0.5 options:0 animations: ^{
self.statusImageView.alpha = 1.0f;
}
completion: ^(BOOL finished) {
[UIView animateWithDuration:0.8 delay:2.5 options:0 animations: ^{
self.statusImageView.alpha = 0.0f;
}
completion: ^(BOOL finished) {
self.statusImageView.hidden = YES;
}];
}];
});
答案 0 :(得分:4)
在这种情况下,我不会使用类别或子类,但使用composition over inheritance:将动画代码放在类Animator
中,将其作为属性添加到视图控制器或一个UIView子类。当动画发生时,在动画师上调用一个方法,该方法将为给定视图设置动画。
您现在可以针对不同情况配置动画师,并在需要时重复使用它。您也可以对所需的动画师进行子类化。
Animator.h
@protocol Animator <NSObject>
-(void)animate;
@end
@interface Animator : NSObject <Animator>
-(instancetype)initWithView:(UIView *)view;
@end
@interface FadeInAndOutAnimator : Animator
-(instancetype)initWithView:(UIView *)view
fadeInDuration:(CGFloat)fadeInDuration
fadeOutDuration:(CGFloat)fadeOutDuration;
-(instancetype)initWithView:(UIView *)view
fadeInDuration:(CGFloat)fadeInDuration
fadeOutDuration:(CGFloat)fadeOutDuration
fadeInDelay:(CGFloat) fadeInDelay
fadeOuDelay:(CGFloat) fadeOutDelay;
@end
Animator.m
#import "Animator.h"
@interface Animator ()
@property(nonatomic, weak) UIView *view;
@end
@implementation Animator
-(instancetype)initWithView:(UIView *)view
{
self = [super init];
if (self){
self.view = view;
}
return self;
}
-(void)animate {
NSAssert(NO, @"%@ must be overwritten in a subclass", NSStringFromSelector(_cmd));
}
@end
@interface FadeInAndOutAnimator ()
@property CGFloat fadeOutDuration;
@property CGFloat fadeInDuration;
@property CGFloat fadeInDelay;
@property CGFloat fadeOutDelay;
@end
@implementation FadeInAndOutAnimator
-(instancetype)initWithView:(UIView *)view
fadeInDuration:(CGFloat)fadeInDuration
fadeOutDuration:(CGFloat)fadeOutDuration
{
return [self initWithView:view
fadeInDuration:fadeInDuration
fadeOutDuration:fadeOutDuration
fadeInDelay:.8
fadeOuDelay:2.5];
}
-(instancetype)initWithView:(UIView *)view
fadeInDuration:(CGFloat)fadeInDuration
fadeOutDuration:(CGFloat)fadeOutDuration
fadeInDelay:(CGFloat)fadeInDelay
fadeOuDelay:(CGFloat)fadeOutDelay
{
self = [super initWithView:view];
if(self){
self.fadeOutDuration = fadeOutDuration;
self.fadeInDuration = fadeInDuration;
self.fadeInDelay = fadeInDelay;
self.fadeOutDelay = fadeOutDelay;
}
return self;
}
-(void)animate
{
[UIView animateWithDuration:self.fadeInDuration delay:self.fadeInDelay options:0 animations: ^{
self.view.alpha = 1.0f;
}
completion: ^(BOOL finished) {
[UIView animateWithDuration:self.fadeOutDuration delay:self.fadeOutDelay options:0 animations: ^{
self.view.alpha = 0.0f;
}
completion: ^(BOOL finished) {
}];
}];
}
@end
ViewController.m
#import "ViewController.h"
#import "Animator.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *statusView;
@property (strong, nonatomic) id<Animator> animator;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)animateTapped:(id)sender {
self.animator = [[FadeInAndOutAnimator alloc] initWithView:self.statusView
fadeInDuration:.8
fadeOutDuration:.5];
[self.animator animate];
}
- (IBAction)animateFastTapped:(id)sender {
self.animator = [[FadeInAndOutAnimator alloc] initWithView:self.statusView
fadeInDuration:.8
fadeOutDuration:.5
fadeInDelay:0
fadeOuDelay:0];
[self.animator animate];
}
@end
我在GitLab
发布了一个完整的项目请注意,Animator
也是一种协议。视图控制器接受实现此协议的任何对象。类Animator
现在是抽象的,animate
必须被覆盖。
答案 1 :(得分:1)
当您为视图控制器设置自定义属性statusImageView时,协议扩展和包含实际动画代码的默认实现可能是一个很好的组合,以便重用动画代码。
示例协议可能如下所示,您是否定义了符合类型中需要存在的所有变量以及将在默认实现中提供的动画函数的签名:
protocol StatusAnimatable {
var statusView: UIView { get }
func animateStatusView()
}
我是默认实现,然后我们可以添加实际的动画代码:
extension StatusAnimatable {
func animateStatusView() {
UIView.animateWithDuration(0.3) {
// Perform all animations using statusView
self.statusView.alpha = 1
}
}
}
现在我们能够将任何具有statusView属性的UIViewController符合我们的协议并在其上调用animateStatusView。
编辑:您似乎想要在任何UIView上执行此特定淡入淡出动画 如果是这种情况,您只需在UIView上添加一个包含您要执行的特定淡入淡出动画代码的扩展名:
extension UIView {
func fadeIn(duration: NSTimeInterval = 0.5, delay: NSTimeInterval = 0, completion: (() -> Void)? = nil) {
UIView.animateWithDuration(duration, delay: delay, options: [], animations: { () -> Void in
self.alpha = 1.0
},
completion: { _ in
completion?()
})
}
func fadeOut(duration: NSTimeInterval = 0.5, delay: NSTimeInterval = 0, completion: (() -> Void)? = nil) {
UIView.animateWithDuration(duration, delay: delay, options: [], animations: { () -> Void in
self.alpha = 0
},
completion: { _ in
self.hidden = true
completion?()
})
}
}
然后将两个函数链接起来:
let someView = UIView()
someView.fadeIn {
someView.fadeOut()
}
答案 2 :(得分:1)
UIView上的类别。 创建一个新文件(File \ New \ New File)并选择iOS \ Cocoa Touch \ Objective-C类别模板。为类别输入“Animation”,为Category打开“UIView”,然后完成创建文件。类别允许我们向现有类添加一些方法(在本例中为UIView),而不对其进行子类化:扩展对象功能的非常简洁和强大的方法。我们将把所有动画代码都放在这个类别中。
在UIView + Animation.h中:
- (void) moveTo:(CGPoint)destination duration:(float)duration delay:(float)delay option:(UIViewAnimationOptions)option;
然后在UIView + Animation.m中添加实现,如下所示:
- (void) moveTo:(CGPoint)destination duration:(float)duration delay:(float)delay option:(UIViewAnimationOptions)option
{
[UIView animateWithDuration:duration delay:delay options:option
animations:^{
self.frame = CGRectMake(destination.x,destination.y, self.frame.size.width, self.frame.size.height);
}
completion:nil];
}
<强>用途:强>
#import "UIView+Animation.h"
您决定拥有动画的代码中的某个地方:
UIButton* movingButton= //initialization code of button or UIView or say any subclass of UIView
[movingButton moveTo:
CGPointMake(button.center.x - (movingButton.frame.size.width/2),
button.frame.origin.y - (movingButton.frame.size.height + 5.0))
duration:1.0 option:0]; // above the tapped button
希望这有助于您了解基本流程。
除了基本概念之外,还有一个很好的类别UIView+Animation