I create my custom loading indicator. So, I update my view like this
#property (nonatomic, readonly) CAShapeLayer *progressLayer;
#property (nonatomic, readwrite) BOOL isAnimating;
- (void)layoutSubviews {
[super layoutSubviews];
self.progressLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
[self updatePath];
}
- (void)updatePath {
CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
CGFloat radius = MIN(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2) - self.progressLayer.lineWidth / 2;
CGFloat startAngle = 3 * M_PI_2;
CGFloat endAngle = self.endAngle;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
self.progressLayer.path = path.CGPath;
}
Animation starts here
- (void)startAnimating {
if (self.isAnimating)
return;
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = #"transform.rotation";
animation.duration = 1.0f;
animation.fromValue = #(0.0f);
animation.toValue = #(2 * M_PI);
animation.repeatCount = INFINITY;
[self.progressLayer addAnimation:animation forKey:kLLARingSpinnerAnimationKey];
self.isAnimating = true;
}
- (void)stopAnimating {
if (!self.isAnimating)
return;
[self.progressLayer removeAnimationForKey:kLLARingSpinnerAnimationKey];
self.isAnimating = false;
}
- (CAShapeLayer *)progressLayer {
if (!_progressLayer) {
_progressLayer = [CAShapeLayer layer];
_progressLayer.strokeColor = self.tintColor.CGColor;
_progressLayer.fillColor = nil;
_progressLayer.lineWidth = 1.5f;
}
return _progressLayer;
}
I have a tab bar app, so the problem is when animation start, I click to another tab and then return to first view, my custom indicator doesn't animate. Also this bug(feature) appear in collection view cells if I add my indicator to cells.
I add my indicator by calling simple method addSubview:
[view addSubview:indicator];
[indicator startAnimating];
How can I prevent stop animating after navigation?
Thanks in advance.
Here you go,
//I have used a BOOL viewChange to check if spinner was running or not while user tapped to different view in tabBar.
- (void)viewWillAppear:(BOOL)animated{ //On initial run the viewChange will be false and the condition in if won't run but as spinnerView start animating u could change the viewChange flag to true.
//So when user will be back from second view then this flag would be true and it will start animating.
//As your work is complete then just stop animating and remove from view.
if(viewChange){
[spinnerView stopAnimating];
[spinnerView removeFromSuperview];
spinnerView = nil;
spinnerView = [[LLARingSpinnerView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 40, 40)];
[self.view addSubview:spinnerView];
[spinnerView startAnimating];
}
}
- (void)viewWillDisappear:(BOOL)animated{
//This is called when user move from current view to another and at that point we user won't be seeing the spinnerView so remove it and release it only if it's animating.
if(spinnerView.isAnimating){
viewChange = YES;
[spinnerView stopAnimating];
[spinnerView removeFromSuperview];
spinnerView = nil;
}
else{
viewChange = NO;
}
}
- (IBAction)stopBtn:(id)sender{ //Spinner is stop animating with tap on button and is removed from the view.
if(spinnerView.isAnimating){
[spinnerView stopAnimating];
[spinnerView removeFromSuperview];
spinnerView = nil; //release the obj of spinnerView.
}
}
- (IBAction)btnTap:(id)sender{ //Spinner is start animating with tap on button
if(!spinnerView)
spinnerView = [[LLARingSpinnerView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 40, 40)];
spinnerView.lineWidth = 1.5f;
spinnerView.tintColor = [UIColor redColor];
[self.view addSubview:spinnerView];
[spinnerView startAnimating];
}
Hope this helps out and if any doubt do let me know. Also if possible u should avoid user to move to another view when spinnerView is running as it indicates that some sort of service or update is running and at that point user should move to another view till it's finish.
Related
I have code to draw the rectangle as
- (void)drawRect:(CGRect)frame {
UIBezierPath* rectanglePath = [UIBezierPath
bezierPathWithRect:CGRectMake(67, 50, 2, _height)];
[UIColor.grayColor setFill];
[rectanglePath fill];
}
where the _height value will change continuously on click
i have a code like this
- (void)initialize {
self.userInteractionEnabled = YES;
_displayLink = [CADisplayLink displayLinkWithTarget:self
selector:#selector(redrawView:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop]forMode:NSDefaultRunLoopMode];
NSMutableArray *array = [[NSMutableArray alloc]init];
[array addObjectsFromArray:#[#“10”,#“20”,#“30”,#“40”]];
}
- (void)dealloc {
[_displayLink invalidate];
[_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
_displayLink = nil;
}
- (void)setInteractionState:(InteractionState)interactionState {
if (_interactionState == Idle && interactionState != Idle) {
_displayLink.paused = NO;
}
_interactionState = interactionState;
}
- (void)redrawView:(CADisplayLink *)displayLink {
if (_interactionState == start) {
_height = [array firstObject];
[array removeObjectAtIndex:0];
[array addObject:_height];
}
}
how to change the height whenever the interaction state is playing?
Try to do this through Core Animation:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(67, 50, 2, _height) cornerRadius:0.0];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
UIBezierPath *newPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(67, 50, 2, _height) cornerRadius:0.0];
CABasicAnimation* pathAnim = [CABasicAnimation animationWithKeyPath:#"path"];
pathAnim.fromValue = (id)self.shapeLayer.path;
pathAnim.toValue = (id)newPath.CGPath;
pathAnim.duration = 2.0f;
[self.circle addAnimation:pathAnim forKey:#"redraw"];
self.shapeLayer.path = newPath.CGPath;
There are two methods in UIView class to redraw the view
- (void)setNeedsDisplay; to redraw the entire view
- (void)setNeedsDisplayInRect:(CGRect)rect; to redraw the given area
For example
- (void)changeHeightTo:(CGFloat)height {
_height = height;
[self setNeedsDisplay]; //this method will notify the system
//to call `drawRect` in next drawing cycle
}
I have added CABasicAnimation on a layer which is added as sublayer to a custom view.Custom view is then added to collection view cell content view as subview. I want to show indefinite progress like bar moving from left to right until download completes(please refer the attachments). Everything is fine except, once download is completed,For removing the custom view with layer animation, i cannot access that view using the tag. The compiler crashes and throws 'could not load any Objective-C class information. This will significantly reduce the quality of type information available'
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableDictionary *attachDetail = [self getManagedObjectForIndexPath:indexPath];
ZCRMMailAttachmentCollectionViewCell *cell = (ZCRMMailAttachmentCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"cellId" forIndexPath:indexPath];
[self setVisibilityOfRemoveButtonInCell:cell inObj:attachDetail];
[self setVisibilityOfSizeInCell:cell inObj:attachDetail];
cell.attachDetails = attachDetail;
[self addLoadingViewIfNotDownloaded:cell managedObject:attachDetail];
[cell redraw];
return cell;
}
-(void)addLoadingViewIfNotDownloaded:(ZCRMMailAttachmentCollectionViewCell*)cell managedObject:(NSDictionary*)attachDict
{
NSNumber *progress = attachDict[MAIL_ATTACH_DOWNLOAD_PROGRESS];
if(!ZV_IsEmpty(progress))
{
if (isinf([progress floatValue]))
{
[cell addLinearInfiniteProgress];
}
else
{
[cell removeLinearProgress];
}
}
}
-(void)addLinearInfiniteProgress
{
UIView* view = [zTvContentView viewWithTag:1234];
if(!view)
{
UIView *progressView = [UIView new];
progressView.tag = 1234;
progressView.layer.masksToBounds = YES;
[zTvContentView addSubview:progressView];
[progressView setBottom:-1];
[progressView alignTo:VTLayoutAlignLeft|VTLayoutAlignRight];
[progressView setHeight:2];
//ProgressLayer
CGRect frame = self.contentView.bounds;
CALayer * indeterminateLayer = [CALayer layer];
indeterminateLayer.delegate = self;
indeterminateLayer.name = #"progresslayer";
indeterminateLayer.frame = CGRectMake(0, 0, 0.4*CGRectGetWidth(frame), 3);
indeterminateLayer.backgroundColor = [CurTheme() themeActionItemColor].CGColor;
indeterminateLayer.opacity = 1;
[progressView.layer addSublayer:indeterminateLayer];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position"];
animation.duration = 1;
animation.repeatCount = HUGE_VALF;
animation.removedOnCompletion = YES;
animation.fromValue = [NSValue valueWithCGPoint:CGPointMake( CGRectGetMinX(frame) - indeterminateLayer.frame.size.width + OFFSET, 0)];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(frame) + indeterminateLayer.frame.size.width - OFFSET, 0)];
[indeterminateLayer addAnimation:animation forKey:#"position"];
}
}
(void)removeLinearInfiniteProgress
{
UIView* progressView = [zTvContentView viewWithTag:1234];
if(progressView)
{
if ([progressView superview])
{
[progressView removeFromSuperview];
}
}
}
Any help would be appreciated.
I have this scenario: when I click on a UITextView, it will either expand or shrink. But every time the UITextView shrinks, the content scroll down to the bottom.
I've tried
[textView setContentOffset:CGPointZero animated:YES];
textView.scrollsToTop = YES;
But none of them works.
Here is the screenshot:
Here is the code:
- (IBAction)tapText:(id)sender {
NSLog(#"tap text view");
[self addBoundsSpringAnimationToView:self.movieTextView];
}
- (void) addBoundsSpringAnimationToView:(UITextView *)textView {
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds];
if (expand) {
NSLog(#"expand");
self.bgUIImageView.hidden = YES;
self.blurredImageView.hidden = NO;
anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0.0f, 320.0f, 807.0f)];
anim.springBounciness = 18;
} else {
NSLog(#"Shrink");
self.bgUIImageView.hidden = NO;
self.blurredImageView.hidden = YES;
anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 355.0f, 320.0f, 225.0f)];
}
expand = !expand;
anim.springSpeed = 10;
[textView pop_addAnimation:anim forKey:#"popBounds"];
}
Is it related to the Facebook Pop animation?
Thanks!
I have an image with circle inside circle approx 10 circles,each of different color i want to show them one by one on button click from center to outside and on another button click disappear one by one from outer to inner. Is this possible and how?
Please suggest
You can get help from below code i m not wrong and you are looking for radar style animation
#import "RadarAnimation.h"
#implementation RadarAnimation
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self SetUPAnimation];
// Initialization code
}
return self;
}
-(void)SetUPAnimation
{
[self AddRader];
double delayInSeconds = 1.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self AddRader];
});
}
-(void)AddRader
{
UIView *view = [[UIView alloc] init];
// view.backgroundColor = [UIColor blueColor];
view.frame=self.frame;
[self setWidth:[Helper currentWidth] ofView:view];
[self setHeight:[Helper currentWidth] ofView:view];
[self setXPossitionto:self.frame.size.width/2-view.frame.size.width/2 ofView:view];
[self setYPossitionto:self.frame.size.height/2-view.frame.size.height/2 ofView:view];
view.layer.cornerRadius = CGRectGetHeight(view.frame)/2;
view.tag=175751;
int kRingExpansionTime=6.0;
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.duration = kRingExpansionTime;
scaleAnimation.repeatCount = HUGE_VAL;
scaleAnimation.autoreverses = YES;
scaleAnimation.fromValue = [NSNumber numberWithFloat:0.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.8];
[view.layer addAnimation:scaleAnimation forKey:#"scale"];
// fade out the ring part way thru the animation
CABasicAnimation* alphaAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
alphaAnim.fromValue = [NSNumber numberWithFloat:0.3];
alphaAnim.toValue = [NSNumber numberWithFloat:0.1];
alphaAnim.beginTime = kRingExpansionTime * 0.7f; // start part way thru
alphaAnim.duration = kRingExpansionTime - alphaAnim.beginTime;
CAAnimationGroup* group = [CAAnimationGroup animation];
group.duration = kRingExpansionTime;
group.repeatCount = HUGE_VALF; // repeat forever
group.animations = [NSArray arrayWithObjects:scaleAnimation,alphaAnim, nil];
[view.layer addAnimation:group forKey:nil];
view.backgroundColor = [UIColor colorWithRed:0/255.0 green:135.0/255.0 blue:219.0/255.0 alpha:0.5];
view.alpha=0.4;
view.layer.borderColor = [UIColor colorWithRed:0/255.0 green:135.0/255.0 blue:255.0/255.0 alpha:1.0].CGColor;
view.layer.borderWidth = 2.0;
//view.center=_VwEmptyplaceholder.center;
//view.center=CGPointMake(_VwEmptyplaceholder.frame.size.width/2, _VwEmptyplaceholder.frame.size.height/2);
view.userInteractionEnabled=NO;
view.tag=175751;
//[self insertSubview:view belowSubview:btn];
}
-(void)setXPossitionto:(CGFloat)xpostion ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.origin.x = xpostion;
view.frame=frame;
}
-(void)setYPossitionto:(CGFloat)ypostion ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.origin.y = ypostion;
view.frame=frame;
}
-(void)setWidth:(CGFloat)Width ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.size.width = Width;
view.frame=frame;
}
-(void)setHeight:(CGFloat)Height ofView:(UIView *)view
{
CGRect frame = view.frame;
frame.size.height = Height;
view.frame=frame;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
In my project, there’s a main View Controller with a subview that contains a Sprite Kit scene. The subview (“MySubview”) is implemented like this:
- (id) initWithFrame: (CGRect) frame {
self = [super initWithFrame: frame];
if (self) {
myScene* scene = [myScene sceneWithSize: CGSizeMake(WIDTH, HEIGHT)];
[self presentScene: scene];
}
return self;
}
The main View Controller initialises this subview like this:
- (void) viewDidLoad {
[super viewDidLoad];
_mySubview = [[MySubview alloc] initWithFrame: CGRectMake(X, Y, WIDTH, HEIGHT)];
[self.view addSubview: mySubview];
}
All this is good and working so far. But then I try adding Core Animation on an object outside of the Sprite Kit view. I add the following to my main View Controller’s implementation:
CAShapeLayer* circleLayer;
- (void) setupCircle {
CGPathRef circlePath = CGPathCreateWithEllipseInRect(CGRectMake(CIRCLE_X, CIRCLE_Y, CIRCLE_WIDTH, CIRCLE_HEIGHT), nil);
circleLayer = [CAShapeLayer layer];
circleLayer.path = circlePath;
circleLayer.fillColor = [UIColor orangeColor].CGColor;
circleLayer.strokeColor = [UIColor blueColor].CGColor;
circleLayer.lineWidth = 10;
[self.view.layer addSublayer: circleLayer];
}
- (void) animateCircle {
CABasicAnimation* circleAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
circleAnimation.duration = 4;
circleAnimation.fromValue = #0;
circleAnimation.toValue = #1;
[circleLayer addAnimation: circleAnimation
forKey: #"circleAnimation"];
}
And then I change my viewDidLoad method to:
- (void) viewDidLoad {
[super viewDidLoad];
_mySubview = [[MySubview alloc] initWithFrame: CGRectMake(X, Y, WIDTH, HEIGHT)];
[self.view addSubview: mySubview];
[self setupCircle];
[self animateCircle];
}
This draws the circle, but does not animate its stroke. When I comment out all the Sprite Kit subview code, it does animate. Is it a problem with threading, run loops, or something else? I’m stuck here. Thanks for the help.