preface

As the saying goes, “If you want to do a good job, you have to do a good job first.” iOS Core Animation is very powerful, which can make very cool animations. However, it is still difficult to write in practice, and the code is not intuitive, and it needs to change parameters, Build and run repeatedly. This paper takes the famous QuartzCode as an example to quickly realize a star animation with collection function, and the final effect is as follows:

GitHub address: github.com/zekunyan/Qu…

QuartzCode profile

QuartzCode is a software specially designed to create iOS/macOS Animation. It basically moves the content of the whole Core Animation framework into the software, such as various layers, masks and properties that can be used for Animation, which are basically consistent with the code. Can be completely used as a “visual animation programming” tool, and after the production can export code + resource file, can be directly called in the code, convenient custom modification.

Take QuartzCode 1.54.0 as an example, the main interface is as follows:

Just a quick word:

  • A: Layers, used for animation, are shown here. The sequence and hierarchy are similar to StoryBoard
  • B: Inspector. The currently selected element, such as Layer attribute editing, basically corresponds to the attribute of the corresponding CALayer class
  • C: Animations, animation groups. You can have multiple animation groups, each independent of the other
  • D: Timeline, animation Timeline. Animation of each Layer will be marked on the Timeline
  • E: Keyframe inspector, which is used to edit the properties of Animation keyframes, is consistent with the properties of CAAnimation class and subclasses of Core Animation
  • F: Canvas, Layer edit area

In general, QuartzCode’s interface is very similar to XIB and StoryBoard, and it’s easy to get started. See www.quartzcodeapp.com/ for more tutorials

To compose

First, sort out the ideas:

In general, it can be divided into two parts, one is the animation part, which uses QuartzCode to achieve visual editing and creation; The other is the function and code API setting part, which needs to be added, modified and packaged into a simple control library on the basis of QuartzCode finally exported code.

QuartzCode implements animation

Let’s take a look at the implementation of animation first. This section only lists the main steps and processes. For detailed parameters and Settings, please refer to the QuartzCode file on GitHub.

Show star animation

The animation of stars is composed of three parts: solid stars appear from small to large, hollow stars appear from large to small and their transparency decreases and disappears. Finally, the stars flash round dots and short lines.

Solid stars appear from small to large

  1. Drag an image onto the middle canvas and the software automatically creates a layer that can be resized and positioned using the Inspector
  2. Rename layer automatically generated in Layers
  3. Click the “+” button for Animations to add an animation group called Show
  4. Select the current layer, click the “+” button of the corresponding layer under Timeline, and add a Bounds frame animation
  5. Each line in the Timeline corresponds to the Timeline of the animation frame. You can double click or right click on the Timeline to add a Keyframe, which is fine by default. Select key points on both ends of the Bounds animation Timeline, and set the Size value in the right Keyframe inspector, starting with (0,0). The end size is the original size

Hollow stars go from large to small, their transparency decreases and disappear

Basically as in the previous step, you can hide the solid layer for easy observation.

  1. Add hollow star image material
  2. Named layer
  3. Add Bounds and Opacity animations to the hollow layer, and modify the start and end values of the animation respectively
  4. Drag the timeline to see the effect

All around flashing short lines, dots

The short lines and dots are arranged repeatedly around the star, so this can be implemented with CAReplicatorLayer, which corresponds to the “Replicator” Layer in the toolbar in QuartzCode. CAReplicatorLayer can repeatedly draw the internal sub-layer according to certain rules, here only need to change according to the rotation Angle.

  1. Click “Replicator” and drag a layer on the center Replicator canvas. Then select the rounded rectangle in “Shape” and drag a small rounded rectangle on the corner of the star to make sure the star_layer is inside the Replicator layer
  2. Set replicator properties to repeat the internal layer of the replicator. Here, set the “instance count” to 5 and the “Rotation” to 72 (360/5=72), and you can repeat the drawing according to the five angles of the star
  3. The last step is to add animations, including Opacity from 0 to 1, Position from inside to outside, and Transform

The remaining dots, and the short line creation method is consistent, will not repeat the explanation ~

At this point, the animation for display is created.

Hidden Star animation

Now look at the animation of the hidden star. With the foundation of the previous section, the animation of the hidden star is much easier. The basic steps are the same, as follows:

  1. Add a new animation group hide
  2. Set the animation of each layer separately. The solid star changes from large to small and the transparency decreases, while the hollow replicator layer stays hidden

Export animation code

And once you’ve done that, you can export your code.

Ordinal File – > Export Code… , you can open the preview screen of exported code:

The option on the right can be selected as required. The default option basically meets the requirements. You’d better select Export Image Assets to Export Image resources. Options that see documentation: www.quartzcodeapp.com/code-genera…

At this point, the most complex part of the animation is complete, without writing a line of code, all visual editing ~

Adjust and encapsulate code

The next step is to encapsulate the exported code for easy use.

API design

The first is the design of the entire animation API. In order to make it easy to add animation to any UIView instance, it is designed as a UIView Category, as follows:

// UIView+TTGStarAnimation. h@interface UIView (TTGStarAnimation) // Initializes the animation - (void)ttg_setupStarAnimation; / / initialize the animation, at the same time can adjust an inset - (void) ttg_setupStarAnimationWithEdgeInset (UIEdgeInsets) an inset; // show star animation - (void)ttg_showStarAnimated:(BOOL)animated complete:(void (^)())complete; // animated - (void)ttg_hideStarAnimated:(BOOL)animated complete:(void (^)())complete; - (BOOL)ttg_getStarIsShow; @endCopy the code

AssociatedObject Saves the animated View instance

QuartzCode exports all the animation code on a View, so in order to add any UIView instance in a Category to the Property of the animation View, Bool of whether the star is currently displayed, you use AssociatedObject, The corresponding set and get methods are as follows:

//  UIView+TTGStarAnimation.m
- (TTGStarAnimationView *)ttg_getStarAnimationView {
    return objc_getAssociatedObject(self, &kTTGButtonStarAnimationViewKey);
}
- (BOOL)ttg_getStarIsShow {
    return [objc_getAssociatedObject(self, &kTTGButtonStarAnimationStateKey) boolValue];
}
- (void)ttg_setStarIsShow:(BOOL)isShow {
    objc_setAssociatedObject(self, &kTTGButtonStarAnimationStateKey, @(isShow), OBJC_ASSOCIATION_COPY_NONATOMIC);
}Copy the code

Modify QuartzCode export code – expose internal Layer instance

QuartzCode export code, the internal animation Layer is not visible, in order to “manually” control the animation View of the actual display state, it is necessary to modify the export code, expose the internal animation Layer instance.

All layers are in the NSMutableDictionary * layers dictionary, obtained by key. Add three properties to ttgStarAnimationView.h:

//  TTGStarAnimationView.h
@interface TTGStarAnimationView : UIView
@property (nonatomic, strong, readonly) CALayer *fillLayer;
@property (nonatomic, strong, readonly) CALayer *emptyLayer;
@property (nonatomic, strong, readonly) CALayer *replicatedLayer;
// ...
@endCopy the code

Then implement the getter method:

//  TTGStarAnimationView.m
- (CALayer *)fillLayer {
    return _layers[@"star_animation_fill"];
}
- (CALayer *)emptyLayer {
    return _layers[@"star_animation_empty"];
}
- (CALayer *)replicatedLayer {
    return _layers[@"replicator"];
}Copy the code

Initialize the

Ttg_setupStarAnimation and ttg_setupStarAnimationWithEdgeInset: method, used to initialize the animation, including the creation of TTGStarAnimationView instance, add, save in the current view, Set the state of each animation layer and other operations:

// TTGStarAnimationView.m - (void)ttg_setupStarAnimation { [self ttg_setupStarAnimationWithEdgeInset:UIEdgeInsetsZero]; } - (void) ttg_setupStarAnimationWithEdgeInset: (an inset UIEdgeInsets) {/ / get the current instance of animation starAnimationView TTGStarAnimationView *starAnimationView = [self ttg_getStarAnimationView]; if (! StarAnimationView) {// Does not exist, Create a new starAnimationView = [[TTGStarAnimationView alloc] initWithFrame: UIEdgeInsetsInsetRect (self. Bounds, an inset)]; / / set the unacceptable interaction events, to prevent blocking the parent view starAnimationView. UserInteractionEnabled = NO; / / set AutoSizingMask starAnimationView. AutoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; / / add [self addSubview: starAnimationView]; / / AssociatedObject saved instance objc_setAssociatedObject (self, & kTTGButtonStarAnimationViewKey, starAnimationView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } // removeAllAnimations [starAnimationView removeAllAnimations]; / / set the layer to initialize state starAnimationView fillLayer. Hidden = YES; starAnimationView.emptyLayer.hidden = NO; starAnimationView.replicatedLayer.hidden = YES; // Set the initialization state value [self ttg_setStarIsShow:NO]; }Copy the code

The animation control

Finally, it is to realize the control of animation. The key here is to control each Layer of animation. The initial and final state of each Layer should be set to ensure that the final display is consistent regardless of whether the animation is executed or not.

// TTGStarAnimationView.m - (void)ttg_showStarAnimated:(BOOL)animated complete:(void (^)())complete { // TTGStarAnimationView *starAnimationView = [self ttg_getStarAnimationView]; // Show if (! [self ttg_getStarIsShow]) {// Set the status value [self ttg_setStarIsShow:YES]; // first removeAllAnimations [starAnimationView removeAllAnimations]; / / set the final Block of the hidden Layer value under the void (^ completionBlock) () = ^ {starAnimationView. FillLayer. Hidden = NO. starAnimationView.emptyLayer.hidden = YES; starAnimationView.replicatedLayer.hidden = YES; // Execute the callback if (complete) {complete(); }}; If (animated) {/ / if you want to perform the animation, then set the animation Layer before the hidden value of starAnimationView. FillLayer. Hidden = NO; starAnimationView.emptyLayer.hidden = NO; starAnimationView.replicatedLayer.hidden = NO; / / execution animation [starAnimationView addShowAnimationCompletionBlock: ^ (BOOL finished) {completionBlock ();}]. } else {// Execute the final state completionBlock() without animation; }}}Copy the code

The hidden code is basically the same as the display, and the various states and hidden values can be reversed. See Github for all code.

There’s only so much code to write, isn’t it very simple!

conclusion

“To do a good job, you must first sharpen its tools”, with the help of a variety of powerful tools and software, the efficiency of animation is literally dozens of times ~