1// Copyright 2019 Google LLC. 2// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 3 4#include "tools/skottie_ios_app/SkiaContext.h" 5#include "tools/skottie_ios_app/SkottieViewController.h" 6 7#include "include/core/SkTypes.h" 8 9#import <UIKit/UIKit.h> 10 11#include <cstdlib> 12 13@interface AppViewController : UIViewController 14 @property (strong) SkiaContext* skiaContext; 15 @property (strong) UIStackView* stackView; 16@end 17 18@implementation AppViewController 19 20- (void)loadView { 21 [self setView:[[UIView alloc] init]]; 22} 23 24- (void)viewDidLoad { 25 [super viewDidLoad]; 26 if (![self skiaContext]) { 27 #if (SK_SUPPORT_GPU && defined(SK_METAL) && !defined(SK_BUILD_FOR_GOOGLE3)) 28 [self setSkiaContext:MakeSkiaMetalContext()]; 29 #elif (SK_SUPPORT_GPU && defined(SK_GL) && !defined(SK_BUILD_FOR_GOOGLE3)) 30 [self setSkiaContext:MakeSkiaGLContext()]; 31 #else 32 [self setSkiaContext:MakeSkiaUIContext()]; 33 #endif 34 if (![self skiaContext]) { 35 NSLog(@"abort: failed to make skia context."); 36 std::abort(); 37 } 38 } 39 CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width; 40 41 UIStackView* stack = [[UIStackView alloc] init]; 42 [stack setAxis:UILayoutConstraintAxisVertical]; 43 [stack setDistribution:UIStackViewDistributionEqualSpacing]; 44 45 NSBundle* mainBundle = [NSBundle mainBundle]; 46 NSArray<NSString*>* paths = [mainBundle pathsForResourcesOfType:@"json" 47 inDirectory:@"data"]; 48 constexpr CGFloat kSpacing = 2; 49 CGFloat totalHeight = kSpacing; 50 for (NSUInteger i = 0; i < [paths count]; ++i) { 51 NSString* path = [paths objectAtIndex:i]; 52 NSData* content = [NSData dataWithContentsOfFile:path]; 53 if (!content) { 54 NSLog(@"'%@' not found", path); 55 continue; 56 } 57 SkottieViewController* controller = [[SkottieViewController alloc] init]; 58 if (![controller loadAnimation:content]) { 59 continue; 60 } 61 CGSize animSize = [controller size]; 62 CGFloat height = animSize.width ? (screenWidth * animSize.height / animSize.width) : 0; 63 CGRect frame = {{0, 0}, {screenWidth, height}}; 64 UIView* skiaView = [[self skiaContext] makeViewWithController:controller withFrame:frame]; 65 [[[skiaView heightAnchor] constraintEqualToConstant:height] setActive:true]; 66 [[[skiaView widthAnchor] constraintEqualToConstant:screenWidth] setActive:true]; 67 [skiaView setNeedsDisplay]; 68 [stack addArrangedSubview:skiaView]; 69 totalHeight += height + kSpacing; 70 } 71 [stack setFrame:{{0, 0}, {screenWidth, totalHeight}}]; 72 [stack setNeedsDisplay]; 73 74 CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height; 75 CGSize mainScreenSize = [[UIScreen mainScreen] bounds].size; 76 CGRect scrollViewBounds = {{0, statusBarHeight}, 77 {mainScreenSize.width, mainScreenSize.height - statusBarHeight}}; 78 UIScrollView* scrollView = [[UIScrollView alloc] initWithFrame:scrollViewBounds]; 79 [scrollView setContentSize:[stack frame].size]; 80 [scrollView addSubview:stack]; 81 [scrollView setBackgroundColor:[UIColor blackColor]]; 82 [scrollView setNeedsDisplay]; 83 84 [self setStackView:stack]; 85 86 UIView* mainView = [self view]; 87 [mainView setBounds:{{0, 0}, mainScreenSize}]; 88 [mainView setBackgroundColor:[UIColor whiteColor]]; 89 [mainView addSubview:scrollView]; 90 [mainView setNeedsDisplay]; 91 92 UITapGestureRecognizer* tapGestureRecognizer = [[UITapGestureRecognizer alloc] init]; 93 [tapGestureRecognizer addTarget:self action:@selector(handleTap:)]; 94 [mainView addGestureRecognizer:tapGestureRecognizer]; 95} 96 97- (void)handleTap:(UIGestureRecognizer*)sender { 98 if ([sender state] != UIGestureRecognizerStateEnded) { 99 return; 100 } 101 NSArray<UIView*>* subviews = [[self stackView] subviews]; 102 for (NSUInteger i = 0; i < [subviews count]; ++i) { 103 UIView* uIView = [subviews objectAtIndex:i]; 104 if (SkiaViewController* controller = [[self skiaContext] getViewController:uIView]) { 105 [controller togglePaused]; 106 [uIView setNeedsDisplay]; 107 } 108 } 109} 110@end 111 112@interface AppDelegate : UIResponder <UIApplicationDelegate> 113 @property (strong, nonatomic) UIWindow* window; 114@end 115 116@implementation AppDelegate 117 118- (BOOL)application:(UIApplication*)app didFinishLaunchingWithOptions:(NSDictionary*)ops { 119 [self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]]; 120 [[self window] setRootViewController:[[AppViewController alloc] init]]; 121 [[self window] makeKeyAndVisible]; 122 return YES; 123} 124@end 125 126int main(int argc, char* argv[]) { 127 @autoreleasepool { 128 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 129 } 130} 131