xCode Paper Onboarding effect - objective-c

How can we implement Paper Onboarding effect. I have one containerview and 3viewconroller inside that. can we implemented same below thing?
this is snapchat chat camera moving effect

I think you have to read this issue.
https://www.objc.io/issues/12-animations/custom-container-view-controller-transitions/
Understand the first two stages first.
Then download Stage 3: Shrink-Wrapping code from github. Under that code replace "PrivateAnimatedTransition" implementation at last with following code.
#implementation PrivateAnimatedTransition
static CGFloat const kChildViewPadding = 16;
static CGFloat const kDamping = 0.75;
static CGFloat const kInitialSpringVelocity = 0.5;
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.3;
}
/// Slide views horizontally, with a bit of space between, while fading out and in.
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//UIButton *button = fromViewController.button;
[containerView addSubview:toViewController.view];
CGRect buttonFrame = CGRectMake(300, 450, 10, 10);
UIBezierPath *circleMaskPathInitial = [UIBezierPath bezierPathWithOvalInRect:buttonFrame];
CGPoint extremePoint = CGPointMake(305, 455);
CGFloat radius = sqrt((extremePoint.x * extremePoint.x) + (extremePoint.y * extremePoint.y));
UIBezierPath *circleMaskPathFinal = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(buttonFrame, -radius, -radius)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.path = circleMaskPathFinal.CGPath;
toViewController.view.layer.mask = maskLayer;
CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:#"path"];
maskLayerAnimation.fromValue = (__bridge id _Nullable)(circleMaskPathInitial.CGPath);
maskLayerAnimation.toValue = (__bridge id _Nullable)(circleMaskPathFinal.CGPath);
maskLayerAnimation.duration = [self transitionDuration:transitionContext];
[maskLayer addAnimation:maskLayerAnimation forKey:#"path"];
[self performSelector:#selector(finishTransition:) withObject:transitionContext afterDelay:[self transitionDuration:transitionContext]];
}
- (void)finishTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
}
and "BINGO" you have done. Just replace buttonFrame with actual selected index button's frame. Feel free to ask any query

Related

How do you infinitely loop all property modifications within UIView animation blocks

I'm having an issue with making a glowing animation for UIView elements infinitely increase the size and opacity of the object shadow that I'm using to create the glow.
I've tried using different animation options, but none result in the shadow properties changing infinitely, only the animation that increases the size of the buttons infinitely loops.
- (void)addGlow:(UIView *)element withColor:(UIColor *)color
{
element.layer.shadowColor = color.CGColor;
element.layer.shadowOpacity = 0;
element.layer.shadowOffset = CGSizeZero;
element.layer.shadowRadius = 0;
[UIView animateWithDuration:0.6 delay:0 options: UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse | UIViewAnimationCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
animations:^
{
element.transform = CGAffineTransformMakeScale(1.02, 1.02);
element.layer.shadowOpacity = 0.5;
element.layer.shadowRadius = 5;
}
completion:NULL];
}
I basically just want the shadowOpacity and shadowRadius to also increase and decrease infinitely, alongside the UIView object's pulsing effect (due to the transform).
I'd use CoreAnimation's CABasicAnimation + CAAnimationGroup, here's an example or what I think you're attempting:
#interface ViewController ()
#property (strong, nullable) IBOutlet UIButton *buttonToGlow;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.buttonToGlow.backgroundColor = [UIColor lightGrayColor];
self.buttonToGlow.layer.cornerRadius = 10.0f;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self addGlow:self.buttonToGlow withColor:[UIColor redColor]];
}
- (void)addGlow:(UIView *)element withColor:(UIColor *)color {
[element.layer removeAnimationForKey:#"glowAnimation"];
element.layer.shadowColor = color.CGColor;
element.layer.shadowOffset = CGSizeZero;
CABasicAnimation *shadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:#"shadowOpacity"];
shadowOpacityAnimation.fromValue = #(0);
shadowOpacityAnimation.toValue = #(0.5);
CABasicAnimation *shadowRadiusAnimation = [CABasicAnimation animationWithKeyPath:#"shadowRadius"];
shadowRadiusAnimation.fromValue = #(0);
shadowRadiusAnimation.toValue = #(5);
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.fromValue = #(1.0);
scaleAnimation.toValue = #(1.02);
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.autoreverses = YES;
animationGroup.repeatCount = CGFLOAT_MAX;
animationGroup.duration = 0.6f;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animationGroup.animations = #[shadowOpacityAnimation, shadowRadiusAnimation, scaleAnimation];
[element.layer addAnimation:animationGroup forKey:#"glowAnimation"];
}
#end
Here's the result:
References:
CoreAnimation programming guide: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html?language=objc#//apple_ref/doc/uid/TP40004514
CABasicAnimation: https://developer.apple.com/documentation/quartzcore/cabasicanimation?language=objc
CAAnimationGroup: https://developer.apple.com/documentation/quartzcore/caanimationgroup?language=objc

CALayer shadow while scrolling UITableView

I have added a shadow to a UITableView (which covers a third of the screen sfrom the bottom - see attached screenshot) using the following in a UIView Category:
- (void) addShadow {
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
self.layer.masksToBounds = NO;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 1;
self.layer.shadowOffset = CGSizeMake(-5,-5);
self.layer.shadowRadius = 20;
self.layer.shadowPath = path.CGPath;
self.layer.shouldRasterize = YES;
}
It appears as expected, but when I scroll it up, the shadow scrolls up too. Also, the table scrolls beyond its upper bound. Can you suggest what is wrong here? if I comment self.layer.masksToBounds = NO;, the shadow disappears, but the table scrolling is as expected. Hence, the problem lies somewhere around masksToBounds perhaps.
I solved it by putting an identical view underneath, just for the shadow. Not a clean solution ... hence I am still open to answers. My code is as follows:
- (UIView*) addShadow {
UIView* backView = [[UIView alloc] initWithFrame:self.frame];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:backView.bounds];
backView.layer.masksToBounds = NO;
backView.layer.shadowColor = [UIColor blackColor].CGColor;
backView.layer.shadowOpacity = 1;
backView.layer.shadowOffset = CGSizeMake(-5,-5);
backView.layer.shadowRadius = 20;
backView.layer.shadowPath = path.CGPath;
backView.layer.shouldRasterize = YES;
[self.superview addSubview:backView];
[self.superview bringSubviewToFront:self];
return backView;
}
(void) removeShadow {
self.layer.masksToBounds = YES;
self.layer.shadowColor = nil;
self.layer.shadowOpacity = 0;
self.layer.shadowOffset = CGSizeMake(0,0);
self.layer.shadowRadius = 0;
}

how to set the frame rate for CABasicAnimation when animation begins in iPhone sdk

I am having multiple Imageview's where I am dividing the 360 degrees/no.of.Imageviews to get an angle to rotate each Imageview.
#define angle ((2*M_PI)/13.0)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
mainView.backgroundColor = [UIColor blackColor];
for(currentIndex = 0; currentIndex < 13; currentIndex++)
{
UIImageView *imageView = [self getCardsWithAngle:(currentIndex*angle)];
[mainView addSubview:imageView];
}
}
-(UIImageView *)getCardsWithAngle:(float)aAngle
{
CGRect frame = CGRectMake(mainView.center.x+50, mainView.center.y-100, 250,200);
CGPoint anchorPoint = CGPointMake(0.5,1.5);
imgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"card_1.png"]];
imgView.frame = frame;
imgView.backgroundColor = [UIColor clearColor];
if(aAngle == 0.0)
{
imgView.layer.anchorPoint = anchorPoint;
return imgView;
}
imgView.layer.anchorPoint = anchorPoint;
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat:aAngle];
rotationAnimation.duration = 3.0;
rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.delegate = self;
[rotationAnimation setValue:[NSNumber numberWithFloat:aAngle] forKey:#"finalAngle"];
[imgView.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
return imgView;
}
Here My problem is all the imageviews start animating at a time. I want to rotate the image views to an angle one after another.
Any ideas will be appreciated,
Thanks all

Why images are not showing in UIScrollView?

I am using this code to show scrolling images but I am only getting a white screen. I drag drop uiscrollview, created the iboutlet, synthesized it and rest of the code is here
#synthesize scrollView1;
const CGFloat kScrollObjHeight = 199.0;
const CGFloat kScrollObjWidth = 280.0;
const NSUInteger kNumImages = 5;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
scrollView1 = [[UIScrollView alloc]init];
bgArray = [NSArray arrayWithObjects:#"Bg", #"Bg1.png", #"Bg2.png", #"Bg3.png", #"Bg4.png", #"Bg5.png", #"Bg6.png", #"Bg7.png", #"Bg8.png", nil];
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 0; i < [bgArray count]; i++)
{
NSString *imageName = [NSString stringWithFormat:#"%#", [bgArray objectAtIndex:i]];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = 199.0;
rect.size.width = 280.0;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[scrollView1 setShowsHorizontalScrollIndicator:NO];
[scrollView1 setShowsVerticalScrollIndicator:NO];
}
[self layoutScrollImages];
}
I think if you are create UIScrollView from code
scrollView1 = [[UIScrollView alloc]init];
then please add the scrollView1 in view
Example:-[self.view addSubview:scrollView1];
if you are create UIScrollView from nib then
not use this code
scrollView1 = [[UIScrollView alloc]init];
solve your probem

loading screen not centered on second launch

I have a UIView which is my loading view. All it does is display the circular loading circle(lol to much "circle" for one sentence).
It works fine the first time but after that the circle is not centered. It moves to the left and down some. How can I get it to always be centered, take in mind I have limited the app to only display in the landscape modes (landscape left, landscape right) in all views so the issue is not coming from the device being rotated.
call to load the view:
loadingViewController = [LoadingViewController loadSpinnerIntoView:self.view];
LoadingViewController.h:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "CrestronClient.h"
#interface LoadingViewController : UIView
{
CrestronClient *cClient;
}
+(LoadingViewController *)loadSpinnerIntoView:(UIView *)superView;
-(void)removeLoadingView;
- (UIImage *)addBackground;
#end
LoadingView.m:
#import "LoadingViewController.h"
#import "RootViewController.h"
#implementation LoadingViewController
CGRect priorFrameSettings;
UIView *parentView;
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||interfaceOrientation == UIInterfaceOrientationLandscapeRight ) {
return YES;
}else{
return NO;
}
}
-(void)removeLoadingView
{
// [parentView setFrame:priorFrameSettings];
CATransition *animation = [CATransition animation];
[animation setType:kCATransitionFade];
[[[self superview] layer] addAnimation:animation forKey:#"layerAnimation"];
[self removeFromSuperview];
}
+(LoadingViewController *)loadSpinnerIntoView:(UIView *)superView
{
priorFrameSettings = superView.frame;
parentView = superView;
// [superView setFrame:CGRectMake(0, 0, 1024, 1024)];
// Create a new view with the same frame size as the superView
LoadingViewController *loadingViewController = [[LoadingViewController alloc] initWithFrame:superView.frame];
loadingViewController.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// If something's gone wrong, abort!
if(!loadingViewController){ return nil; }
[superView addSubview:loadingViewController];
if(!loadingViewController){ return nil; }
// This is the new stuff here ;)
UIActivityIndicatorView *indicator =
[[[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge] autorelease];
// Set the resizing mask so it's not stretched
UIImageView *background = [[UIImageView alloc] initWithImage:[loadingViewController addBackground]];
// Make a little bit of the superView show through
background.alpha = 0.7;
[loadingViewController addSubview:background];
indicator.autoresizingMask =
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleLeftMargin;
// Place it in the middle of the view
indicator.center = superView.center;
// Add it into the spinnerView
[loadingViewController addSubview:indicator];
// Start it spinning! Don't miss this step
[indicator startAnimating];
// Create a new animation
CATransition *animation = [CATransition animation];
// Set the type to a nice wee fade
[animation setType:kCATransitionFade];
// Add it to the superView
[[superView layer] addAnimation:animation forKey:#"layerAnimation"];
return loadingViewController;
}
- (UIImage *)addBackground{
cClient = [CrestronClient sharedManager];
if (cClient.isConnected == FALSE) {
[cClient connect];
}
// Create an image context (think of this as a canvas for our masterpiece) the same size as the view
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 1);
// Our gradient only has two locations - start and finish. More complex gradients might have more colours
size_t num_locations = 2;
// The location of the colors is at the start and end
CGFloat locations[2] = { 0.0, 1.0 };
// These are the colors! That's two RBGA values
CGFloat components[8] = {
0.4,0.4,0.4, 0.8,
0.1,0.1,0.1, 0.5 };
// Create a color space
CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
// Create a gradient with the values we've set up
CGGradientRef myGradient = CGGradientCreateWithColorComponents (myColorspace, components, locations, num_locations);
// Set the radius to a nice size, 80% of the width. You can adjust this
float myRadius = (self.bounds.size.width*.8)/2;
// Now we draw the gradient into the context. Think painting onto the canvas
CGContextDrawRadialGradient (UIGraphicsGetCurrentContext(), myGradient, self.center, 0, self.center, myRadius, kCGGradientDrawsAfterEndLocation);
// Rip the 'canvas' into a UIImage object
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// And release memory
CGColorSpaceRelease(myColorspace);
CGGradientRelease(myGradient);
UIGraphicsEndImageContext();
// … obvious.
return image;
}
- (void)dealloc {
[super dealloc];
}
#end
Make sure the loading view is set to its parents frame and has the proper autoresizingMask set. This would likely by UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight.
fixed the background by adding
[background setFrame:CGRectMake(0, 0, 1024, 768 )];
and fixed the centering of the circle with:
indicator.center = background.center;