In my App I am trying to get a paralax effect in my table. (e.g it's background) which contains a blurred map for each entry.
How I've set it up is i have a XIB with a UITableViewCell and have added the labels to the contentView. Then in code I add the image to the backgroundView. (The backgroundView doesn't exist, and I create an "empty view" to where I add the image).
Then I add the UIInterpolatingMotionEffect to the image view.
This works. But, since the image has the same dimensions as the table view cell, when a person tilts the phone and the paralax effect kicks in white edges appear. As you can see in the image below.
That is not something I want. So I thought, well I could just put a bigger image in the backgroundView. This works while I am not in editing mode. But in editing mode the background image overlaps partially with the delete button. As seen here:
So I thought, I should clip the backgroundView containing the image view. Which I've done with the following code:
self.backgroundView.clipsToBounds = YES;
or this
// Create a mask layer and the frame to determine what will be visible in the view.
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
CGRect maskRect = self.bounds;
// Create a path with the rectangle in it.
CGPathRef path = CGPathCreateWithRect(maskRect, NULL);
// Set the path to the mask layer.
maskLayer.path = path;
// Release the path since it's not covered by ARC.
CGPathRelease(path);
// Set the mask of the view.
self.backgroundView.layer.mask = maskLayer;
But neither solutions work. It looks like it is not being clipped. Is there an other way to go about this?
Related
I'm using AVSynchronizedLayer to show the animations added to a video. I have a custom CALayer which contains text drawn using coretext. I will add this custom CALayer with coretext to another CALayer as sublayer. And finally this layer is added to AVSynchroziedLayer.
// initilaise annotation layer
CALayer *textLayer = annotation.drawinglayer;// initialise custom layer
textLayer.position = annotation.location;
textLayer.beginTime = 1e-100;
[self.annotationLayer addSublayer:textLayer];
// set annotationlayer frame
//add this annotation layer as sublayer of AVSynchronizedLayer.
So when I play the video it works fine as expected. When I seek forward, it works as expected, but when I pause and seek backword the content of textlayer (text or lines) fades whereas the layer remains. Only content disappears, if it has sublayers it will not fade . I just want to place text for a particular time range.But it fades when I seek back. Please help.
I am doing some custom download progresses bar in side the (subclassed) UIButton (or) i can also do that in UIView, every thing is fine, now i want change the colour of the title as the progress the proceeds, for example as u can see in the below image shows what is now i am getting,
what i want is like below image
i want change the color of the title to white or some other color as download proceeds, is there any way i can do, any sample code for this.
i am achieving this by using below code
- (void)drawInContext:(CGContextRef)progressContext
{
CGContextSetFillColorWithColor(progressContext, self.progressLayerColor.CGColor);
CGMutablePathRef Path = CGPathCreateMutable();
CGRect boundsRect = self.bounds;
CGPathMoveToPoint(Path, NULL, boundsRect.origin.x, boundsRect.origin.y);
CGPathAddRect(Path, NULL, CGRectMake(0, 0, self.progress, 35));
CGPathCloseSubpath(Path);
CGContextAddPath(progressContext, Path);
CGContextFillPath(progressContext);
CGContextSetBlendMode(progressContext, kCGBlendModeClear);
CGContextFillPath(progressContext);
CGPathRelease(Path);
}
I'd do this with two UILabels, one with a green background and white text, one with a white background and black text, with the green one one on top of the other with the same frame.
The topmost label has a CAShapeLayer as it's layers mask. The CAShapeLayer has a single, wide (at least the height of the label) black stroke across its whole length, from left to right.
By default this would make the whole view look green. So far, so useless.
However, a CAShapeLayer has an (animatable) strokeEnd property. If you set this to 0.0, the green label will be invisible. Set it to 0.5, you see half and half.
You now have a method to animate a progress meter, just by updating the strokeEnd property of this mask layer.
With the help of what #jrturton suggested i am able to make this kind of progress bar,
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = _labelGreen.bounds;//it the label on top with green background and white text color
CGMutablePathRef mutPath = CGPathCreateMutable();
CGPathMoveToPoint(mutPath, NULL, 0, 0);
CGPathAddRect(mutPath, NULL, CGRectMake( 0, 0, progress, _labelGreen.frame.size.height)); //as the progress cganges the width of mask layer also changes
maskLayer.path = mutPath;//set the path
_labelGreen.layer.mask = maskLayer;
the resulted output will be like below image
A trivial solution would be to use 2 UIImageViews. The one below would have an image with white background and black text, and the one above would have green background with white text. The image below would always have the same frame, but the other would start with a width 0. As the download progresses you would increase it's width and it would start to cover the image that is below (with the black font). And of course, you would use the View Mode: left on your expanding image view, to always have the image positioned on the left with no resizing.
So normally when you have a view and you want to add a drop shadow I do something like this:
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:diptic.bounds];
diptic.layer.masksToBounds = NO;
diptic.layer.shadowColor = [UIColor blackColor].CGColor;
diptic.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
diptic.layer.shadowRadius = 10;
diptic.layer.shadowOpacity = .5f;
diptic.layer.shadowPath = shadowPath.CGPath;
Where diptic is my UIScrollView.
The problem is that because diptic is a scroll view, that I have content in the scroll view that I don't want to be on the screen until they scroll to it, so I want to have masksToBounds set to YES but if I do that then I can't see my shadow..
you can see the description of the dartboard ("A basically new dartboard...") I want to be hidden until the user scrolls to it. Also, the rounded corners of the diptic isn't clipping the square corners on the top of the image.
Is there any way to be selective of what is masked and what isn't?
Put diptic into another view with the same bounds, that way you can mask diptic to bounds but apply the shadow to the containing view that wouldn't have its content masked to its bounds.
I have one component that has an UIView subclass and a custom CAlayer into it.
In the UIView there is a circle that is drawn with CoreGraphics, and this is the code:
CGRect b = self.bounds;
int strokeSize = 2;
CGRect arcBounds = CGRectMake(b.origin.x+1, b.origin.y+1, b.size.width-2, b.size.height-2);
CGContextSaveGState(ctx); {
CGContextSetLineWidth(ctx, strokeSize);
CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
CGContextStrokeEllipseInRect(ctx, arcBounds);
} CGContextRestoreGState(ctx);
when I draw that circle in the drawRect method inside the UIView it works perfect and the circle is drawn smooth and looks great.
The problem appears when I draw another circle just over this one, but the second one is drawn in the CALayer, actually in the drawInContext method of my custom CALayer. Using just the same code the circle doesn't looks good, and have some "pixellation" on the borders.
Any clues on what can be happening? Thanks in advance.
This is due to the contentsScale property. When you have a custom CALayer the default value of this property is 1.0.
The default value of this property is 1.0. For layers attached to a
view, the view changes the scale factor automatically to a value that
is appropriate for the current screen. For layers you create and
manage yourself, you must set the value of this property yourself
based on the resolution of the screen and the content you are
providing. Core Animation uses the value you specify as a cue to
determine how to render your content. Source.
If you have a retina device and you draw with the contentsScale set to 1.0, it will result in that pixelated look you described. In order to fix this you should set the layer's contentsScale to the one of the screen.
[self.layer setContentsScale:[[UIScreen mainScreen] scale]];
This issue does not happen when you draw the circle in the drawRect method of your UIView since there the default contentsScaleFactor is already the one of the screen.
For views that implement a custom drawRect: method and are associated
with a window, the default value for this property is the scale factor
associated with the screen currently displaying the view. Source.
I am trying to implement camera zoom using CGAffinetransform. Transform is fine, but when I scale it to a bigger size, it goes out of the frame I have assigned to the AVCaptureVideoPreviewLayer. I tried setting masksToBounds property to YES but it didn't help.
Can I contain it within its frame?
Edit:
What I want is that I can specify a specific area for the camera preview layer, if I apply scaling transform to it, (i.e., frame of preview layer gets expanded), the part of the layer outside of the specified area gets clipped.
You should put the layer you are scaling inside of another layer and mask that one instead (the superlayer). The same thing works with views.
I.e. You have two views / layers: clippingView and scalingView where scalingView is the subview of clippingView and clippingView is the view that actually clips to it's bounds.
[clippingView addSubview:scalingView];
clippingView.clipsToBounds = YES;
or using layers
[clippingLayer addSublayer:scalingLayer];
clippingLayer.masksToBounds = YES;
You guys are all partially right I found but I wanted to clarify.
Lets say we added something like AVCaptureVideoPreviewLayer to the view via [self.view.layer addSublayer:previewLayer]
[self clipsToBounds] does NOTHING until you are telling its primary layer to mask to bounds. [self.view.layer masksToBounds];
Just because your view has a frame and so does its layers DOES NOT MEAN IT HAS BOUNDS. If it doesnt have bounds then there is nothing to mask to. So do this self.view.layer.bounds = self.view.frame;
So heres it all together..keep in mind I did this in my own UIView class so I dont need to call self.view.
previewLayer.bounds = self.frame;
self.layer.bounds = self.frame;
self.layer.masksToBounds = YES;
previewLayer.masksToBounds = YES;
[self setBounds:self.frame];
[self clipsToBounds];
clipsToBounds property of the view to which I am adding the layer should have been set to YES.