I'm not sure if this has been asked before, but I'm having a hard time finding it. Perhaps I'm not using the right search terms, so if an answer already exists, if someone could point me in the right direction, it'd be most appreciated!
I just noticed that the glimmer animation on the "slide to unlock" text of the lockscreen has changed with the iOS 7.1 update. The spotlight now has an ovular / diamond shape that cascades across the letters without appearing on the view behind it.
In the past, I've replicated this type of feature by changing the color of individual letters sequentially, but for this, the animation goes through the middle of the letters. Without affecting the background.
How can I replicate this?
You can animate label text and use custom slider for it, I hope it helps you:
CALayer *maskLayer = [CALayer layer];
// Mask image ends with 0.15 opacity on both sides. Set the background color of the layer
// to the same value so the layer can extend the mask image.
maskLayer.backgroundColor = [[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.15f] CGColor];
maskLayer.contents = (id)[[UIImage imageNamed:#"Mask.png"] CGImage];
// Center the mask image on twice the width of the text layer, so it starts to the left
// of the text layer and moves to its right when we translate it by width.
maskLayer.contentsGravity = kCAGravityCenter;
maskLayer.frame = CGRectMake(myLabel.frame.size.width * -1, 0.0f, myLabel.frame.size.width * 2, myLabel.frame.size.height);
// Animate the mask layer's horizontal position
CABasicAnimation *maskAnim = [CABasicAnimation animationWithKeyPath:#"position.x"];
maskAnim.byValue = [NSNumber numberWithFloat:myLabel.frame.size.width];
maskAnim.repeatCount = 1e100f;
maskAnim.duration = 1.5f;
[maskLayer addAnimation:maskAnim forKey:#"slideAnim"];
myLabel.layer.mask = maskLayer;
You should be able to use the mask property of CALayer to create a cutout of the contents of another layer.
Set the mask to contain your text (maybe a CATextLayer can work here). This is what Shimmer says it uses.
Make the foreground color of your label be a UIColor initiated with
+colorWithPatternImage or
-initWithPatternImage
using an animated image and setting the background color of the label to transparent. I've not tried this, but I don't see why it wouldn't work.
The best way to do this is with a multi layer object.
Top: UILabel with opaque background and clear text
Clear text is rendered in drawRect: func through complicated masking process
Middle: Worker View that is performing a repeating animation moving an image behind the top label
Bottom: a UIView that you add the middle and top subview to in that order. Can be whatever color you want the text to be
An example can be seen here
https://github.com/jhurray/AnimatedLabelExample
The most effective way I've found to recreate the glimmering text effect is to use the Shimmer Cocoapod created by Facebook. Below is the example image from the Shimmer GitHub repo, which is located at the following URL: https://github.com/facebook/Shimmer
Shimmer example
There are full instructions to install and use Shimmer on the repo, but the gist is that after installing the Cocoapod you'll add a special subview or layer into which will go the contents you wish to have glimmer/shimmer, then set the effect to start.
Try to have a semi-transparent foreground with transparent cutouts for the letters. The "glimmer" can be moved across behind the cutouts.
Make a layer on top that has cutout layers with an animated PNG or something as the background.
Under this layer, have another layer with exactly the reverse transparency (letters are opaque and space between letters is transparent.
This way, the user sees through the letters to the animation, and between the letters to whatever the letters are over.
Just make sure you have code to keep the layers in the right order.
I think that it's a semi transparent view, but it's a special view in which the drawrect is overridden to color each pixel of the letters with the same color (but stronger to make it visible) of the pixel in the view beneath it.
Imagine this like the magnifying view. it displays a magnified version of the the view beneath it.
Related
I want to bind two views to a button's border like a mask. The effect I want is seen in the image below
So I have a custom controller that uses a PageViewController to swipe between two UIViewControllers. I also have two views (the red one and the blue one). I can track the direction and degree of the page turning, so I can link that to the movement of the two views. All I need to do is apply a mask to the moving boxes so that all the movement stays within the button.
If anyone knows how to do this, I'd be eternally grateful for the information!
My understanding is that you have a view, then you want to transition between its two subviews with a sliding animation. This is fairly straight forward.
First set "Clip Subviews" to true (either in storyboard editor or setting view.clipToBounds=true). If you want a sphere like you show then set layer.cornerRadius = view.frame.size.width/2
The you can just set the frames of your subviews- either animating them with UIView animateWithDuration or setting the frames yourself in your animation loop.
The former in code (for sliding the first element to the left and right element in):
[UIView animateWithDuration:duration animations:^{
[subview1 setFrame:CGRectMake(-subview1.frame.size.width, 0, subview1.frame.size.width, subview1.frame.size.height)];
[subview2 setFrame:CGRectMake(0, 0, subview2.frame.size.width, subview2.frame.size.height)];
}];
The reverse animation is similar. If you're doing it in your own animation loop (which sounds like what you want) then you can do the interpolation yourself pretty easily.
If you want to be more advanced with your mask (i.e. based on an image) then look at something like this: How to mask UIViews in iOS
This solution may not be the optimized one, but do the trick you want. First i wanna make sure that i understand your requirement. I understand that you wanna go away to left the red image & bring in the right blue image in the button with the sliding effect.
If my understanding meet your requirement,Here is the trick
First decide which portion of red & blue image you needed. That must be easy as you know the direction & degree of the turning the UIPageViewController.
Then Crop that decided portions from the red & blue image using the code here.
Now draw both resulted cropped image on the coreGraphics side by side (red on the left & blue on the right) & retrieve the final resulted image.
set the image to the UIButton.
Finally to acquire the round shape you can set the radius property of layer property of the button.
For the third step, how you can you draw image on coreGraphics & retrieve apple give a detail explanation here
You have to do all these steps each time you wanna update the image of the UIButton. There may be a other good way to do this :)
You can use corner radious on the button layer
CGPoint saveCenter = roundedView.center;
CGRect newFrame = CGRectMake(roundedView.frame.origin.x, roundedView.frame.origin.y, newSize, newSize);
button.frame = newFrame;
button.layer.cornerRadius = newSize / 2.0;
button.center = saveCenter;
I have an image view that starts out cropping it's image with clipsToBounds and content mode set as "scale aspect fill", and I want it to "enlarge" the image to the whole image. If clipsToBounds=NO was an animatable property, that would be exactly what I want, which it does not seem to be. Is there a way to animate that?
If not, another way would be resizing the view so it is the same width-height ratio as the image's size, while keeping it no smaller than the image view was to begin with (i.e. minimal increate to height or width, no decrease to either). I'm not sure the best approach to doing this, considering the image could be much bigger or smaller than the image view, and the image's width-height ratio could be just about anything (but it will usually be an iOS device camera photo).
UPDATE 1: It seems like layer.masksToBounds would work, the documentation says that it is animatable, but my code does not seem to work:
CABasicAnimation *layerAnim = [CABasicAnimation animationWithKeyPath:#"masksToBounds"];
layerAnim.fromValue = #(YES);
layerAnim.toValue = #(NO);
layerAnim.removedOnCompletion = YES;
layerAnim.duration = 1.0;
[_imageView.layer addAnimation:layerAnim forKey:#"masksToBounds"];
I am running this layer animation at the same time as a UIView block animation that is changing the frame and transform of the image view, if that matters.
UPDATE 2: I did not have this core animation in the UIView animation block, which according to the documentation, it should be. I have moved the above code into the animation block, but it is still not animating (change happens instantly). I'm beginning to think that "animatable" simply means it can be placed in an animation, not that it will actively animate over time.
So you don't want your image to grow, but you want it to be clipped at first, and then the outer pixels are exposed?
You can do that using Core Animation and a layer mask.
Here's what you do:
Set the image view's clipsToBounds to FALSE, so the image would fully display if you let it.
Create a CAShapeLayer that's the size of the whole image. Create a rectangular bezier path that's the size of the initial image. Install that bezier path's CGPath as the path of the shape layer.
Set the shape layer's fill color to an opaque color
Then install the shape layer as the mask of your image view's layer. That will cause the image to be clipped to the shape of the shape layer.
Now, if you change the path that's installed in the shape layer to a rectangle that's the full size of the image, the system will animate the change for you.
As of March 21st 2019, it seems like the masksToBounds documentation is just wrong. masksToBounds does not seem to be animatable. I have tried animating masksToBounds with CABasicAnimation and CAKeyframeAnimations and it doesn't seem to work.
I have a circular UIView. I want to be able to apply a mask that sits on top of it, and rotates above it so that the circular view appears gradually.
Is this even possible in iOS? I know it is in flast. But not sure where would I even start with a task like this in iOS??
You can create a shape layer like in this answer that will look as if it is appearing gradually (like a clock making a full circle). Then you can put the circular content in another layer (or use your view's layer) and make the shape layer the mask:
CAShapeLayer *maskLayer = // see linked answer
yourCircularView.layer.mask = maskLayer;
CABasicAnimation *drawMaskAnimation = // see linked answer
[maskLayer addAnimation:drawMaskAnimation forKey:#"appear gradually"];];
All UIView is backed by CALayer which allows some of the properties to be animated as well as mask to be applied. You will find the tutorial in this page very helpful. www.raywenderlich.com
I am creating an iOS user interface to allow a user to pick a rectangle within an existing image, dragging the corners of that rectangle to the desired size. I now have four custom UIButtons (30% alpha) and a custom view (also with 30% alpha) that draws the dashed lines between the four corner buttons.
To "improve" the interface, I would like my drawRect code to make the cropped portion of the image appear "normal" while everything outside the cropped region is washed out (filled with white color, which will give me the correct effect since the UIView is set to 30% alpha).
The obvious algorithm would be:
Fill the entire image with [UIColor whiteColor] fill
Draw the four dashed lines with a [UIColor clearColor] fill
When I do this, the clear fill isn't showing up. I believe this is because the "fill" of the clear color in step #2 isn't being seen because the pixels were already set to white in step #1. Perhaps there's a blend mode that will allow me to see the transparency of the second rectangle? I'm not sure about the various blend modes.
My second attempt, which works, does the following:
Draw the four dashed lines with [UIColor clearColor] fill
Draw four additional rectangles with [UIColor whiteColor] fill, each representing the portions to the left, right, above, and below the cropped region.
As I mention, this method works, but seems to me there should be a simpler way instead of me having to calculate these four additional rectangles each and every time.
There is a similar question on SO Create layer mask with custom-shaped hole that uses CALayer and masks, but this seems to be overkill for what I need.
Does anybody have any suggestions on how to improve this?
You can set the blend mode to kCGBlendModeCopy and use clearColor to reset a pixel's alpha to zero. You can presumably also use kCGBlendModeClear but I haven't tested that.
You can also set the clipping path to just contain the pixels you want cleared and call CGContextClearRect(gc, CGRectInfinite).
If you want to use a clipping mask with a hole in it, you can do so without using a CALayer, and you can build it a little more simply than in the answer you linked, by using the even-odd rule and CGRectInfinite:
CGContextSaveGState(GC); {
CGContextBeginPath(gc);
CGContextAddRect(gc, myRect); // or whatever simple path you want here
CGContextAddRect(gc, CGRectInfinite);
CGContextEOClip(gc);
// drawing code here is clipped to the exterior of myRect
} CGContextRestoreGState(gc);
I have a requirement where I have to draw a view's shadow beyond the view's frame. We already have complex view hierarchy / layering and it would not be possible now to change the view's frames and layout to accommodate the shadows within the viewController's view's bounds.
1. I am bit concerned here of whether I am allowed to draw the shadow's outside the view by following this methodology:
"You can also create a drop shadow that will be based on the alpha component of whatever is drawn in your view. Often this will result in a shadow just around the edges of the view. This example code on a UILabel:
label.layer.shadowColor = [UIColor blackColor].CGColor;
label.layer.shadowOpacity = 1.0;
label.layer.shadowRadius = 5.0;
label.layer.shadowOffset = CGSizeMake(0, 3);
label.clipsToBounds = NO;
In this case, you need clipsToBounds to be NO in order for a shadow outside the frame of your view to show up. Next I’ll show you how you can actually combine rounded corners and drop shadows, since I’m sure that’s what you really want to do now."
Reference: http://bynomial.com/blog/?p=52
2. Now, I have come across threads which tells that drawing shadows outside the view is not encouraged. But no explanation given:
How can I draw a shadow beyond a UIView's bounds?
Is there any reason as why we should not be drawing shadows (CALayer) outside view's frame? Or, is it fine following the 1st approach?
Thanks,
Raj
I see absolutely no reason not to draw a shadow this way, and this is frankly the only way. Why would you "not be allowed" to draw a shadow outside the bounds? That's what the clipsToBounds property is for.