OC--UIView基础
2017-03-14 本文已影响34人
啊哈呵
基本属性方法
@interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, CALayerDelegate>
@property(class, nonatomic, readonly) Class layerClass; // 默认是[CALayer class],重载这个方法,可以返回自定义的LayerClass.
//init方法
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
//NSCoding协议,实例化从序列化
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
// 默认YES,设置NO是用户事件(触摸键)被忽略和从事件队列中删除
@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled;
// 标记tag,默认=0
@property(nonatomic) NSInteger tag;
// 返回view的layer(非空)
@property(nonatomic,readonly,strong) CALayer *layer;
// 可成为焦点,默认为no
@property(nonatomic,readonly) BOOL canBecomeFocused NS_AVAILABLE_IOS(9_0);
// 是否是焦点
@property (readonly, nonatomic, getter=isFocused) BOOL focused NS_AVAILABLE_IOS(9_0);
布局Geometry
@interface UIView(UIViewGeometry)
// 当前视图的边界,包括大小和原点,这里是在父视图的坐标系下
@property(nonatomic) CGRect frame;
// 当前视图的边界,包括大小和原点,这里是在自己的坐标系下
@property(nonatomic) CGRect bounds;
// 当前视图的中心,并制定是在父视图的坐标系下
@property(nonatomic) CGPoint center;
// 形变属性(平移/缩放/旋转)--默认是CGAffineTransformIdentity。可以做成动画
/*
CGAffineTransform结构体,有六个值,分别是:
CGFloat a, b, c, d;
CGFloat tx, ty;
*/
@property(nonatomic) CGAffineTransform transform;
// 应用到当前视图的比例Scale
@property(nonatomic) CGFloat contentScaleFactor NS_AVAILABLE_IOS(4_0);
// 是否支持多点触控,默认是NO
@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled ;
// 决定当前视图是否是处理触摸事件的唯一对象,默认为NO
@property(nonatomic,getter=isExclusiveTouch) BOOL exclusiveTouch ;
//点击链的处理判断方法
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
// 这个函数的用处是判断当前的点击或者触摸事件的点是否在当前的View中
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
// 把本视图(调用者)下的point(第一参数)转换为指定View(第二参数)的point(返回值)
- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
// 把指定View(第二参数)下的point(第一参数)转化为本视图(调用者)的point(返回值)
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
// 把本视图(调用者)下的rect(第一参数)转换为指定View(第二参数)的rect(返回值)
- (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;
// 把指定View(第二参数)下的rect(第一参数)转化为本视图(调用者)的rect(返回值)
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;
// 这个属性是决定当视图大小边界发生改变时,其子视图是否也跟着自动调整大小,默认为YES
@property(nonatomic) BOOL autoresizesSubviews;
// 决定当当前视图的父视图大小发生变化时,当前视图该怎么调整自己的size
@property(nonatomic) UIViewAutoresizing autoresizingMask;
//UIViewAutoresizing枚举值:
/*
UIViewAutoresizingNone //视图将不进行自动尺寸调整。
UIViewAutoresizingFlexibleHeight //视图的高度将和父视图的高度一起成比例变化。否则,视图的高度将保持不变
UIViewAutoresizingFlexibleWidth //视图的宽度将和父视图的宽度一起成比例变化。否则,视图的宽度将保持不变
UIViewAutoresizingFlexibleLeftMargin //视图的左边界将随着父视图宽度的变化而按比例进行调整。否则,视图和其父视图的左边界的相对位置将保持不变。
UIViewAutoresizingFlexibleRightMargin //视图的右边界将随着父视图宽度的变化而按比例进行调整。否则,视图和其父视图的右边界的相对位置将保持不变。
UIViewAutoresizingFlexibleBottomMargin //视图的底边界将随着父视图高度的变化而按比例进行调整。否则,视图和其父视图的底边界的相对位置将保持不变。
UIViewAutoresizingFlexibleTopMargin //视图的上边界将随着父视图高度的变化而按比例进行调整。否则,视图和其父视图的上边界的相对位置将保持不变。
*/
//// 返回最符合其子视图的大小。返回最佳尺寸,默认返回self.frame.size
- (CGSize)sizeThatFits:(CGSize)size;
//移动并调整子视图的大小,先调用sizeThatFits:,然后设置view.size
- (void)sizeToFit;
@end
层次结构 UIView(UIViewHierarchy)
@interface UIView(UIViewHierarchy)
// 获取父视图,只读属性
@property(nullable, nonatomic,readonly) UIView *superview;
// 当前视图的所有子视图,只读属性
@property(nonatomic,readonly,copy) NSArray<__kindof UIView *> *subviews;
// 当前视图上的UIWindow对象,只读属性
@property(nullable, nonatomic,readonly) UIWindow *window;
// 从父视图移除
- (void)removeFromSuperview;
// 在索引位置插入一个视图
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
// 用索引值交换两个视图
- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;
// 向当前视图上添加子视图
- (void)addSubview:(UIView *)view;
// 在某个视图下插入一个视图
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;
// 在某个视图上插入一个视图
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;
// 把这个View放到最前面
- (void)bringSubviewToFront:(UIView *)view;
// 把这个View放到最后面
- (void)sendSubviewToBack:(UIView *)view;
// 告诉视图添加子视图
- (void)didAddSubview:(UIView *)subview;
// 即将移除子视图
- (void)willRemoveSubview:(UIView *)subview;
// 在一个子视图将要被添加到另一个视图的时候发送此消息
- (void)willMoveToSuperview:(nullable UIView *)newSuperview;
// 已经移除,父视图改变
- (void)didMoveToSuperview;
// 在一个视图(或者它的超视图)将要被添加到window的时候发送
- (void)willMoveToWindow:(nullable UIWindow *)newWindow;
// 已经语出窗体对象
- (void)didMoveToWindow;
// 判定一个视图是否在其父视图的视图层中(系统自动调用)
- (BOOL)isDescendantOfView:(UIView *)view;
// 返回指定tag的View
- (nullable __kindof UIView *)viewWithTag:(NSInteger)tag;
#pragma mark - 布局
// 标记视图需要重新布局,会调用layoutSubviews
- (void)setNeedsLayout;
// 当调用了setNeedsLayout并不会马上调用layoutSubViews,这时会调用该方法,可以强制发生重新布局
- (void)layoutIfNeeded;
#pragma mark - 系统自动调用(留给子类去实现)
/**
* 控件的frame,约束发生改变的时候就会调用,一般在这里重写布局子控件的位置和尺寸
* 重写了这个方法后一定要调用[super layoutSubviews]
*/
- (void)layoutSubviews; // 对子视图布局
/*
layoutSubviews在以下情况下会被调用:
1、init初始化不会触发layoutSubviews , 但 initWithFrame 进行初始化时,当rect的值不为CGRectZero时,也会触发.
2、addSubview会触发layoutSubviews.
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化.
4、滚动一个UIScrollView会触发layoutSubviews.
5、旋转Screen会触发父UIView上的layoutSubviews事件.
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件.
[1]、layoutSubviews对subviews重新布局
[2]、layoutSubviews方法调用先于drawRect
[3]、setNeedsLayout在receiver标上一个需要被重新布局的标记,在系统runloop的下一个周期自动调用layoutSubviews
[4]、layoutIfNeeded方法如其名,UIKit会判断该receiver是否需要layout
[5]、layoutIfNeeded遍历的不是superview链,应该是subviews链
*/
// 布局视图,距离父视图的上左下右的距离
@property (nonatomic) UIEdgeInsets layoutMargins;
// 这个属性默认是NO,如果把它设为YES,layoutMargins会根据屏幕中相关View的布局而改变
@property (nonatomic) BOOL preservesSuperviewLayoutMargins;
// 在我们改变View的layoutMargins这个属性时,会触发这个方法。我们在自己的View里面可以重写这个方法来捕获layoutMargins的变化。在大多数情况下,我们可以在这个方法里触发drawing和layout的Update
- (void)layoutMarginsDidChange;
// 相对于View Layout Margins创建的约束,在其view的边缘会留下一些空白的距离
@property(readonly,strong) UILayoutGuide *layoutMarginsGuide NS_AVAILABLE_IOS(9_0);
// 会根据size class来调整大小,这样会在边缘添加空白的距离,来跟适合阅读
@property (nonatomic, readonly, strong) UILayoutGuide *readableContentGuide NS_AVAILABLE_IOS(9_0);
//UILayoutGuide类定义了可以通过自动布局交互的矩形区域。使用布局指南来替换可能已创建的虚拟视图,以在用户界面中表示视图间间距或封装
//UILayoutGuide可以虚拟View帮助的事情都可以交给UILayoutGuide来做。它更轻量、更快速、更高效。UILayoutGuide并没有真正的创建一个View,只是创建了一个矩形空间,只在进行auto layout时参与进来计算
@end
绘制--UIView(UIViewRendering)
@interface UIView(UIViewRendering)
/**
* drawRect是对receiver的重绘
* setNeedDisplay在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘,iphone device的刷新频率是60hz,也就是1/60秒后重绘
*/
// 渲染 重写此方法 执行重绘
- (void)drawRect:(CGRect)rect;
// 需要重新渲染 标记为需要重绘 一步调用drawRect
- (void)setNeedsDisplay;
// 需要重新渲染某一块区域
- (void)setNeedsDisplayInRect:(CGRect)rect;
// 决定了子视图的显示范围。具体来说,当取值为YES时,裁剪超出父视图范围的子视图范围
@property(nonatomic) BOOL clipsToBounds;
// 设置背景颜色
@property(nullable, nonatomic,copy) UIColor *backgroundColor;
// 透明度,0.0-1.0的数值,0为全透明,1为不透明
@property(nonatomic) CGFloat alpha;
// 是否透明,默认为YES==不透明
@property(nonatomic,getter=isOpaque) BOOL opaque;
/*
决定该消息接收者(UIView instance)是否让其视图不透明,用处在于给绘图系统提供一个性能优化开关。
myView.opaque = NO;
该值为YES, 那么绘图在绘制该视图的时候把整个视图当作不透明对待。优化绘图过程并提升系统性能;为了性能方面的考量,默认被置为YES。
该值为NO,,不去做优化操作。
一个不透明视图需要整个边界里面的内容都是不透明。基于这个原因,opaque设置为YES,要求对应的alpha必须为1.0。如果一个UIView实例opaque被设置为YES, 而同时它又没有完全填充它的边界(bounds),或者它包含了整个或部分的透明的内容视图,那么将会导致未知的结果。
因此,如果视图部分或全部支持透明,那么你必须把opaque这个值设置为NO.
*/
// 决定在子视图重画之前是否先清理视图以前的内容
@property(nonatomic) BOOL clearsContextBeforeDrawing;
// 是否隐藏,默认为NO
@property(nonatomic,getter=isHidden) BOOL hidden;
// 决定当视图边界变时呈现视图
@property(nonatomic) UIViewContentMode contentMode;
//设置图片的显示方式
typedef NS_ENUM(NSInteger, UIViewContentMode) {
UIViewContentModeScaleToFill, // 填充 根据视图的比例去拉伸图片内容
UIViewContentModeScaleAspectFit, // 缩放填充 保持图片内容的纵横比例,来适应视图的大小
UIViewContentModeScaleAspectFill, // 用图片内容来填充视图的大小,多余的部分可以被修剪掉来填充整个视图边界
UIViewContentModeRedraw, // 重绘边界 这个选项是单视图的尺寸位置发生变化的时候通过调用setNeedsDisplay方法来重新显示
UIViewContentModeCenter, // 保持图片原比例,居中
UIViewContentModeTop, // 保持图片原比例,居上
UIViewContentModeBottom, // 保持图片原比例,居下
UIViewContentModeLeft, // 保持图片原比例,居左
UIViewContentModeRight, // 保持图片原比例,居右
UIViewContentModeTopLeft, // 保持图片原比例,居左上
UIViewContentModeTopRight, // 保持图片原比例,居右上
UIViewContentModeBottomLeft, // 保持图片原比例,居左下
UIViewContentModeBottomRight, // 保持图片原比例,居右下
};
// 用于制定那部分是可拉伸的,取值在0.0~1.0之间
@property(nonatomic) CGRect contentStretch;
/*
[imageView setContentStretch:CGRectMake(150.0/300.0, 100.0/200.0, 10.0/300.0, 10.0/200.0)];
image.png的大小是 200 x 150 ;
mageView的frame是(0,0,300,200);
150.0/300.0表示x轴上,前150个像素不进行拉伸。
100.0/200.0表示y轴上,前100个像素不进行拉伸。
10.0/300.0表示x轴上150后的10个像素(151-160)进行拉伸,直到image.png铺满imageView。
10.0/200.0表示y轴上100后的10个像素(101-110)进行拉伸,直到image.png铺满imageView。
*/
@property(nullable, nonatomic,strong) UIView *maskView; // 模具视图
@property(null_resettable, nonatomic, strong) UIColor *tintColor; // 视图控件的颜色
@property(nonatomic) UIViewTintAdjustmentMode tintAdjustmentMode; // 视图的色彩模式
/*
枚举值:
UIViewTintAdjustmentModeAutomatic, //自动的
UIViewTintAdjustmentModeNormal, //正常的
UIViewTintAdjustmentModeDimmed, //暗淡的
*/
- (void)tintColorDidChange; // 视图颜色属性发生变化时,由系统调用
@end
手势-- UIView (UIViewGestureRecognizers)
@interface UIView (UIViewGestureRecognizers)
@property(nullable, nonatomic,copy) NSArray<__kindof UIGestureRecognizer *> *gestureRecognizers; // 访问手势集合
- (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer; // 添加手势
- (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer; // 移除手势
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer; // 通过返回值决定是否识别此手势
@end
动画相关--UIView(UIViewAnimationWithBlocks)
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
//1.常规动画属性设置(可以同时选择多个进行设置)
UIViewAnimationOptionLayoutSubviews = 1 << 0,//动画过程中保证子视图跟随运动
UIViewAnimationOptionAllowUserInteraction = 1 << 1, // 动画过程中允许用户交互
UIViewAnimationOptionBeginFromCurrentState = 1 << 2, // 所有视图从当前状态开始运行
UIViewAnimationOptionRepeat = 1 << 3, // 重复运行动画
UIViewAnimationOptionAutoreverse = 1 << 4, // 如果重复,动画运行到结束点后仍然以动画方式回到初始点
UIViewAnimationOptionOverrideInheritedDuration = 1 << 5, // 忽略嵌套动画时间设置
UIViewAnimationOptionOverrideInheritedCurve = 1 << 6, // 忽略嵌套动画速度设置
UIViewAnimationOptionAllowAnimatedContent = 1 << 7, // 动画过程中重绘视图(注意仅仅适用于转场动画)
UIViewAnimationOptionShowHideTransitionViews = 1 << 8, // 视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画)
UIViewAnimationOptionOverrideInheritedOptions = 1 << 9, // 不继承父动画设置或动画类型
//2.动画速度控制(单选)
UIViewAnimationOptionCurveEaseInOut = 0 << 16, // 开始慢-中间块-结束慢
UIViewAnimationOptionCurveEaseIn = 1 << 16, // 开始慢-结束快
UIViewAnimationOptionCurveEaseOut = 2 << 16, // 开始快-结束慢
UIViewAnimationOptionCurveLinear = 3 << 16, // 线性
//3.转场类型(单选)
UIViewAnimationOptionTransitionNone = 0 << 20, // 没有转场动画效果
UIViewAnimationOptionTransitionFlipFromLeft = 1 << 20, // 从左侧翻转效果
UIViewAnimationOptionTransitionFlipFromRight = 2 << 20, // 从右侧翻转效果
UIViewAnimationOptionTransitionCurlUp = 3 << 20, // 向后翻页的动画过渡效果
UIViewAnimationOptionTransitionCurlDown = 4 << 20, // 向前翻页的动画过渡效果
UIViewAnimationOptionTransitionCrossDissolve = 5 << 20, // 旧视图溶解消失显示下一个新视图的效果
UIViewAnimationOptionTransitionFlipFromTop = 6 << 20, // 从上方翻转效果
UIViewAnimationOptionTransitionFlipFromBottom = 7 << 20, // 从底部翻转效果
};
@interface UIView(UIViewAnimationWithBlocks)
/**
view的一些动画一般使用这个就够了
@param duration 动画时长
@param delay 延时执行时间
@param options 动画类型
@param animations 动画最后的状态block
@param completion 动画执行完成的block
*/
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion ;
// delay = 0.0, options = 0
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion ;
// delay = 0.0, options = 0, completion = NULL
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;
/**
Spring Animation弹簧动画 系统操作很多这种动画
@param dampingRatio 0.0f-1.0f,数值越小「弹簧」的振动效果越明显
@param velocity 初始的速度,数值越大一开始移动越快
*/
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
/**
转场动画
@param view 需要进行转场动画的视图
*/
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
/**
转场动画
// 添加toView到父视图
[fromView.superview addSubview:toView];
// 把fromView从父视图中移除
[fromView.superview removeFromSuperview];
*/
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
//在一组视图上执行指定的系统动画,并可以并行自定义的动画
//其中parallelAnimations就是与系统动画并行的自定义动画--只有UISystemAnimationDelete
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
简单使用
[UIView animateWithDuration:3.0 animations:^{
//直接写最后的view状态
} completion:^(BOOL finished) {
//动画结束
}];
关键帧动画--UIView (UIViewKeyframeAnimations)
typedef NS_OPTIONS(NSUInteger, UIViewKeyframeAnimationOptions) {
UIViewKeyframeAnimationOptionLayoutSubviews = UIViewAnimationOptionLayoutSubviews,//动画过程中保证子视图跟随运动
UIViewKeyframeAnimationOptionAllowUserInteraction = UIViewAnimationOptionAllowUserInteraction, // 动画过程中允许用户交互
UIViewKeyframeAnimationOptionBeginFromCurrentState = UIViewAnimationOptionBeginFromCurrentState, // 所有视图从当前状态开始运行
UIViewKeyframeAnimationOptionRepeat = UIViewAnimationOptionRepeat, // 重复运行动画
UIViewKeyframeAnimationOptionAutoreverse = UIViewAnimationOptionAutoreverse, // 如果重复,动画运行到结束点后仍然以动画方式回到初始点
UIViewKeyframeAnimationOptionOverrideInheritedDuration = UIViewAnimationOptionOverrideInheritedDuration, // 忽略嵌套动画时间设置
UIViewKeyframeAnimationOptionOverrideInheritedOptions = UIViewAnimationOptionOverrideInheritedOptions, // 不继承父动画设置或动画类型
UIViewKeyframeAnimationOptionCalculationModeLinear = 0 << 10, // default线性
UIViewKeyframeAnimationOptionCalculationModeDiscrete = 1 << 10, // 离散的
UIViewKeyframeAnimationOptionCalculationModePaced = 2 << 10, // 均匀执行运算模式
UIViewKeyframeAnimationOptionCalculationModeCubic = 3 << 10, // 平滑运算模式
UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10 // 平滑均匀运算模式
};
@interface UIView (UIViewKeyframeAnimations)
/**
关键帧动画
*/
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion ;
/**
add帧动画
@param frameStartTime 倍数从0到1,假设一个动画持续的时间是2秒,设置frameStartTime为0.5,那么后面设置的动画,将会在整体动画执行1秒后开始执行
@param frameDuration 也是一个倍数,都是相对总的duration来设置
*/
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations ;
简单使用
- (void)runAnimateKeyframes {
/**
* relativeDuration 动画在什么时候开始
* relativeStartTime 动画所持续的时间
*/
[UIView animateKeyframesWithDuration:6.f
delay:0.0
options:UIViewKeyframeAnimationOptionCalculationModeLinear
animations:^{
//第一个帧动画
[UIView addKeyframeWithRelativeStartTime:0.0 // 相对于6秒所开始的时间(第0秒开始动画)
relativeDuration:1/3.0 // 相对于6秒动画的持续时间(动画持续2秒)
animations:^{
self.view.backgroundColor = [UIColor redColor];
}];
//第二个帧动画
[UIView addKeyframeWithRelativeStartTime:1/3.0 // 相对于6秒所开始的时间(第2秒开始动画)
relativeDuration:1/3.0 // 相对于6秒动画的持续时间(动画持续2秒)
animations:^{
self.view.backgroundColor = [UIColor yellowColor];
}];
//第三个帧动画
[UIView addKeyframeWithRelativeStartTime:2/3.0 // 相对于6秒所开始的时间(第4秒开始动画)
relativeDuration:1/3.0 // 相对于6秒动画的持续时间(动画持续2秒)
animations:^{
self.view.backgroundColor = [UIColor greenColor]; }];
}
completion:^(BOOL finished) {
//重复,可以设置options=UIViewKeyframeAnimationOptionRepeat
[self runAnimateKeyframes];
}];
}