I have a UIScrollView containing UIImageviews wrapped inside programmatically created UIScrollViews.
Inside that main UIScrollView i have a UITextView that will change it's content accordingly to the image view showing while scrolling between the various uiimageviews. I want to decrease the alpha of the showing UITextView accordingly to the position of the scrolled UIScrollView.
e.g. if the user is half way through the scrolling process while moving from one set of uiimageviews to another, the uitextview's alpha should be 0.5. Any Ideas how can i achieve this result ?
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat offset = scrollView.contentOffset.x; // here you will get the offset value
CGFloat value = offset / totalcontentsize;
// use 'value' for setting the textview alpha value
}
I just add logic how to approach.
Or you can use a category. Make a category on UIView called UIView+Looks
#interface UIView (Looks)
-(void)fadeTail;
#end
#implementation UIView (Looks)
-(void)fadeTail
{
// it's used to fade away the bottom,
// perhaps of a slab of text, web view or similar
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.bounds;
gradient.colors = #[
(id)[[UIColor whiteColor] CGColor],
(id)[[UIColor clearColor] CGColor]
];
gradient.startPoint = CGPointMake(0.5, 0.93);
gradient.endPoint = CGPointMake(0.5, 1);
[self.layer setMask:gradient];
}
#end
example usage (in this case on a web view
#property (strong) IBOutlet UIWebView *dossierBlock;
-(void)_fillMainArea
{
[self _loadBookImage];
NSString *longHtml = CLOUD.caMeeting[#"yourJsonTag"];
nullsafe(longHtml);
[self.dossierBlock longHtml baseURL:nil];
[self.dossierBlock fadeTail];
}
You can trivially make a "fadeTop" in the same way.
Related
I know how to do (1) but how can I do (2)?
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = #[(id)[UIColor blueColor].CGColor, (id)[UIColor redColor].CGColor];
[view.layer insertSublayer:gradient atIndex:0];
There are several ways you could do this. Here's one way:
Create a UIView subclass named GradientView to manage the gradient layer. This is helpful because it means you can use the normal UIKit techniques to manage the gradient layout (auto layout constraints, autoresizing masks, UIKit animations).
For each view that should participate in the common gradient, add a GradientView subview. Set up each GradientView's colors, locations, and start and end points identically.
For each view that should participate in the common gradient, turn on clipsToBounds.
Use auto layout constraints to make each GradientView span all of the participating superviews. (It's important to understand that constraints can cross superview/subview boundaries).
With this approach, auto layout takes care of making the gradient cover all of the views even if they change size or move around. For example, you won't have to do anything special to make the gradients animate nicely when the user rotates the device.
Thus, for your two-view example, I'm proposing that you set up a view hierarchy like this:
In the view debugger screenshot above, I disabled clipping. You can see that the two gradient views have identical gradients and share the same screen space. The topGradient is a subview of topView and bottomGradient is a subview of bottomView.
If we turn clipping on, you'll only see the part of topGradient that fits inside topView's bounds, and you'll only see the part of bottomGradient that fits inside bottomView's bounds. Here's what it looks like with clipping enabled:
And here's a screen shot of my test program in the simulator:
Here's the source code for GradientView:
#interface GradientView: UIView
#property (nonatomic, strong, readonly) CAGradientLayer *gradientLayer;
#end
#implementation GradientView
+ (Class)layerClass { return CAGradientLayer.class; }
- (CAGradientLayer *)gradientLayer { return (CAGradientLayer *)self.layer; }
#end
Here's the code I used to create all of the views:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *topView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 50)];
topView.layer.cornerRadius = 10;
topView.clipsToBounds = YES;
UIView *topGradient = [self newGradientView];
[topView addSubview:topGradient];
[self.view addSubview:topView];
UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(20, 90, 100, 50)];
bottomView.layer.cornerRadius = 10;
bottomView.clipsToBounds = YES;
UIView *bottomGradient = [self newGradientView];
[bottomView addSubview:bottomGradient];
[self.view addSubview:bottomView];
[self constrainView:topGradient toCoverViews:#[topView, bottomView]];
[self constrainView:bottomGradient toCoverViews:#[topView, bottomView]];
}
- (GradientView *)newGradientView {
GradientView *gv = [[GradientView alloc] initWithFrame:CGRectZero];
gv.translatesAutoresizingMaskIntoConstraints = NO;
gv.gradientLayer.colors = #[(__bridge id)UIColor.blueColor.CGColor, (__bridge id)UIColor.redColor.CGColor];
return gv;
}
And here's how I create the constraints that make a GradientView (or any view) cover a set of views:
- (void)constrainView:(UIView *)coverer toCoverViews:(NSArray<UIView *> *)coverees {
for (UIView *coveree in coverees) {
NSArray<NSLayoutConstraint *> *cs;
cs = #[
[coverer.leftAnchor constraintLessThanOrEqualToAnchor:coveree.leftAnchor],
[coverer.rightAnchor constraintGreaterThanOrEqualToAnchor:coveree.rightAnchor],
[coverer.topAnchor constraintLessThanOrEqualToAnchor:coveree.topAnchor],
[coverer.bottomAnchor constraintGreaterThanOrEqualToAnchor:coveree.bottomAnchor]];
[NSLayoutConstraint activateConstraints:cs];
cs = #[
[coverer.leftAnchor constraintEqualToAnchor:coveree.leftAnchor],
[coverer.rightAnchor constraintEqualToAnchor:coveree.rightAnchor],
[coverer.topAnchor constraintEqualToAnchor:coveree.topAnchor],
[coverer.bottomAnchor constraintEqualToAnchor:coveree.bottomAnchor]];
for (NSLayoutConstraint *c in cs) { c.priority = UILayoutPriorityDefaultHigh; }
[NSLayoutConstraint activateConstraints:cs];
}
}
The greaterThanOrEqual/lessThanOrEqual constraints, which (by default) have required priority, ensure that coverer covers the entire frame of each coveree. The equal constraints, which have lower priority, then ensure that coverer occupies the minimum space required to cover each coveree.
You can do this by adding a view on top of the view with the gradient, then cutting out the shapes by making a mask out of a UIBezierPath, then adding that to the view on top (let's call it topView):
let yourPath: UIBezierPath = //create the desired bezier path for your shapes
let mask = CAShapeLayer()
mask.path = yourPath.cgPath
topView.layer.mask = mask
I have a custom tableview cell with a UIWebView contained in it. The UIWebView content is large, so I have the cell expanding on tap. When the cell is collapsed I am fading the bottom of the cell to show the content is truncated.
To determine whether I should fade the cell content I am comparing the height of the cell with the height of the webview content within layoutSubviews().
This works the first time the cell is displayed.
When I tap to expand the fade out is removed. Good so far.
Now when I collapse the cell, the height reported in layoutSubviews() for the webview comes back correctly once, but it is immediately followed by a second call to layoutSubviews() which reports the height of the webview as the same size as the collapsed cell. This stops causes the cell fade that was just added to be removed.
I have inspected the cell with the view debugger and it reports the correct height for the webview.
How can I reliably get the height of the webview?
Here is my code from the custom cell:
- (void)layoutSubviews
{
[super layoutSubviews];
if (gradientLayer != nil) {
[gradientLayer removeFromSuperlayer];
gradientLayer = nil;
}
// if cell height is less than web view height we must fade
if (self.frame.size.height < self.webView.bounds.size.height) {
gradientLayer = [CAGradientLayer layer];
NSObject* fadeColor = (NSObject*)[UIColor colorWithWhite:1.0 alpha:.9].CGColor;
NSObject* transparentColor = (NSObject*)[UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
gradientLayer.colors = [NSArray arrayWithObjects:transparentColor, fadeColor, nil];
gradientLayer.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:1.0], nil];
gradientLayer.bounds = self.bounds;
gradientLayer.anchorPoint = CGPointZero;
[self.layer addSublayer:gradientLayer];
}
}
I have a background gradient that draws nicely when the screen is initially rendered in portrait mode. However, when the device is rotated to landscape mode, the right 40% of the screen is black (i.e. the background is not drawn on the part of the screen that wasn't previously drawn). I don't know how to get the background to redraw to fill the entire screen.
Can anyone tell me what I am doing wrong? Thanks!
Here is how it looks when initially drawn.
And here is now it looks when I rotate it:
Here is the code for my background gradient class:
#import "BackgroundGradient.h"
#interface BackgroundGradient()
#property (strong, nonatomic) UIView *view;
#end
#implementation BackgroundGradient
- (id) initWithView:(UIView *) view
{
if (!_view)
_view = view;
return self;
}
- (void) makeGradient
{
UIColor *darkOp = [UIColor colorWithRed:(193.0 / 255.0) green:(215.0 / 255.0) blue:(46.0 / 255.0) alpha: 1];
UIColor *lightOp = [UIColor colorWithRed:(222.0 / 255.0) green:(233.0 / 255.0) blue:(143.0 / 255.0) alpha: 1];
// Create the gradient
CAGradientLayer *gradient = [CAGradientLayer layer];
// Set colors
gradient.colors = [NSArray arrayWithObjects:
(id)darkOp.CGColor,
(id)lightOp.CGColor,
(id)darkOp.CGColor,
nil];
// Update the start and end points
gradient.startPoint = CGPointMake(0.5, 0.0);
gradient.endPoint = CGPointMake(0.5, 1.0);
// Set bounds
gradient.frame = self.view.bounds;
// Add the gradient to the view
[self.view.layer insertSublayer:gradient atIndex:0];
gradient.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:0.7],
[NSNumber numberWithFloat:0.9],
nil];
}
#end
And finally, here is how I instantiate the background object:
- (void)viewDidLoad
{
[super viewDidLoad];
self.background = [[BackgroundGradient alloc] initWithView:self.view];
[self.background makeGradient];
}
EDIT: I've added the following code and included updates to the start and end points (above):
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self.background makeGradient];
}
I'm almost there, but now, I get this. Notice how there is still a vertical line. It looks to me like the new background is getting drawn behing the previous background such that the previous background is still there and is blocking the new background. This is particularly noticeable as the animation from portrait to landscape is occurring.
This is where you are doing it wrong: CAGradientLayer *gradient = [CAGradientLayer layer]; and [self.view.layer insertSublayer:gradient atIndex:0];
You are 'adding'a new instance of gradient layer each time the device rotates. You shouldn't do that. Instead, only set it's frame on rotation, and everything will work absolutely fine. Use only one instance. Create it in viewDidLoad
Use view debugging to help out in such cases.
I solved this issue with this:
Resize the sublayer of my background image.
Swift
override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
self.backgroundImageView.layer.sublayers?.first?.frame = self.view.bounds
}
Update gradient's frame in viewDidLayoutSubviews:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// find gradient layer
let gradLayers = gradientView.layer.sublayers?.flatMap { $0 as? CAGradientLayer }
// this assumes there is only one gradient layer
gradLayers?.first?.frame = gradientView.bounds
}
I have a UIScrollView. In this I have a UIView which has a frame with a negative origin - I need to limit the scroll view so that you can't scroll around the entire view..
I have implemented Zoom in this scrollview.
When Zooming the Scroll view will adjust the size of the Zoomable view according to the scale. BUT IT DOES NOT ADJUST THE ORIGIN.
So if I have a view with a frame of {0, -500}, {1000, 1000}
The I zoom out to a scale of 0.5, this will give me a new frame of {0, -500}, {500, 500}
Clearly this is not good, the entire view is zoomed out of the scrollview. I want the frame to be {0, -250}, {500, 500}
I can fix things a bit in the scrollViewDidZoom method by adjusting the origin correctly.. This does work, but the zoom is not smooth.. Changing the origin here causes it to jump.
I notice in the documentation for UIView it says (regarding the frame property):
Warning: If the transform property is not the identity transform, the
value of this property is undefined and therefore should be ignored.
Not quite sure why that is.
Am I approaching this problem wrong? What is the best way to fix it?
Thanks
Below is some source code from the test app I am using:
In the ViewController..
- (void)viewDidLoad
{
[super viewDidLoad];
self.bigView = [[BigView alloc] initWithFrame: CGRectMake(0, -400, 1000, 1000)];
[self.bigScroll addSubview: bigView];
self.bigScroll.delegate = self;
self.bigScroll.minimumZoomScale = 0.2;
self.bigScroll.maximumZoomScale = 5;
self.bigScroll.contentSize = bigView.bounds.size;
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return bigView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// bigView.frame = CGRectMake(0, -400 * scrollView.zoomScale,
// bigView.frame.size.width, bigView.frame.size.height);
bigView.center = CGPointMake(500 * scrollView.zoomScale, 100 * scrollView.zoomScale);
}
And then in the View...
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);
CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
CGContextFillRect(ctx, CGRectMake(100, 500, 10, 10));
for (int i = 0; i < 1000; i += 100) {
CGContextStrokeRect(ctx, CGRectMake(0, i, 1000, 3));
}
}
Note that here the jumpiness is more apparent at larger zoom scales. In my real app where there is much more drawing and processing going on the jump is more apparent at all times.
You don't have to use the frame property - and should not, given Apple's very firm warning. In such cases you can usually use bounds and center to achieve your result.
In your case you can ignore all of the subview's properties. Assuming that your subview is the viewForZoomingInScrollView you can use the scrollView's contentOffset and zoomScale properties
- (void) setMinOffsets:(UIScrollView*)scrollView
{
CGFloat minOffsetX = MIN_OFFSET_X*scrollView.zoomScale;
CGFloat minOffsetY = MIN_OFFSET_Y*scrollView.zoomScale;
if ( scrollView.contentOffset.x < minOffsetX
|| scrollView.contentOffset.y < minOffsetY ) {
CGFloat offsetX = (scrollView.contentOffset.x > minOffsetX)?
scrollView.contentOffset.x : minOffsetX;
CGFloat offsetY = (scrollView.contentOffset.y > minOffsetY)?
scrollView.contentOffset.y : minOffsetY;
scrollView.contentOffset = CGPointMake(offsetX, offsetY);
}
}
Call it from both scrollViewDidScroll and scrollViewDidZoom in your scrollView delegate. This should work smoothly, but if you have doubts you can also implement it by subclassing the scrollView and invoking it with layoutSubviews. In their PhotoScroller example, Apple centers a scrollView's content by overriding layoutSubviews - although maddeningly they ignore their own warnings and adjust the subview's frame property to achieve this.
update
The above method eliminates the 'bounce' as the scrollView hits it's limits. If you want to retain the bounce, you can directly alter the view's center property instead:
- (void) setViewCenter:(UIScrollView*)scrollView
{
UIView* view = [scrollView subviews][0];
CGFloat centerX = view.bounds.size.width/2-MIN_OFFSET_X;
CGFloat centerY = view.bounds.size.height/2-MIN_OFFSET_Y;
centerX *=scrollView.zoomScale;
centerY *=scrollView.zoomScale;
view.center = CGPointMake(centerX, centerY);
}
update 2
From your updated question (with code), I can see that neither of these solutions fix you problem. What seems to be happening is that the greater you make your offset, the jerkier the zoom movement becomes. With an offset of 100points the action is still quite smooth, but with an offset of 500points, it is unacceptably rough. This is partly related to your drawRect routine, and partly related to (too much) recalculation going on in the scrollView to display the right content. So I have another solution…
In your viewController, set your customView's bounds/frame origin to the normal (0,0). We will offset the content using layers instead. You will need to add the QuartzCore framework to your project, and #import it into your custom view.
In the custom view initialise two CAShapeLayers - one for the box, the other for the lines. If they share the same fill and stroke you would only need one CAShapeLayer (for this example I changed your fill and stroke colors). Each CAShapeLayer comes with it's own CGContext, which you can initialise once per layer with colors, linewidths etc. Then to make a CAShapelayer do it's drawing all you have to do is set it's path property with a CGPath.
#import "CustomView.h"
#import <QuartzCore/QuartzCore.h>
#interface CustomView()
#property (nonatomic, strong) CAShapeLayer* shapeLayer1;
#property (nonatomic, strong) CAShapeLayer* shapeLayer2;
#end
#implementation CustomView
#define MIN_OFFSET_X 100
#define MIN_OFFSET_Y 500
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initialiseLayers];
}
return self;
}
- (void) initialiseLayers
{
CGRect layerBounds = CGRectMake( MIN_OFFSET_X,MIN_OFFSET_Y
, self.bounds.size.width + MIN_OFFSET_X
, self.bounds.size.height+ MIN_OFFSET_Y);
self.shapeLayer1 = [[CAShapeLayer alloc] init];
[self.shapeLayer1 setFillColor:[UIColor clearColor].CGColor];
[self.shapeLayer1 setStrokeColor:[UIColor yellowColor].CGColor];
[self.shapeLayer1 setLineWidth:1.0f];
[self.shapeLayer1 setOpacity:1.0f];
self.shapeLayer1.anchorPoint = CGPointMake(0, 0);
self.shapeLayer1.bounds = layerBounds;
[self.layer addSublayer:self.shapeLayer1];
Setting the bounds is the critical bit. Unlike views, which clip their subviews, CALayers will draw beyond the bounds of their superlayer. You are going to start drawing MIN_OFFSET_Y points above the top of your View and MIN_OFFSET_X to the left. This allows you to draw content beyond your scrollView's content view without the scrollView having to do any extra work.
Unlike views, a superlayer does not automatically clip the contents of sublayers that lie outside its bounds rectangle. Instead, the superlayer allows its sublayers to be displayed in their entirety by default.
(Apple Docs, Building a Layer Hierarchy)
self.shapeLayer2 = [[CAShapeLayer alloc] init];
[self.shapeLayer2 setFillColor:[UIColor blueColor].CGColor];
[self.shapeLayer2 setStrokeColor:[UIColor clearColor].CGColor];
[self.shapeLayer2 setLineWidth:0.0f];
[self.shapeLayer2 setOpacity:1.0f];
self.shapeLayer2.anchorPoint = CGPointMake(0, 0);
self.shapeLayer2.bounds = layerBounds;
[self.layer addSublayer:self.shapeLayer2];
[self drawIntoLayer1];
[self drawIntoLayer2];
}
Set a bezier path for each shape layer, then pass it in:
- (void) drawIntoLayer1 {
UIBezierPath* path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(0,0)];
for (int i = 0; i < self.bounds.size.height+MIN_OFFSET_Y; i += 100) {
[path moveToPoint:
CGPointMake(0,i)];
[path addLineToPoint:
CGPointMake(self.bounds.size.width+MIN_OFFSET_X, i)];
[path addLineToPoint:
CGPointMake(self.bounds.size.width+MIN_OFFSET_X, i+3)];
[path addLineToPoint:
CGPointMake(0, i+3)];
[path closePath];
}
[self.shapeLayer1 setPath:path.CGPath];
}
- (void) drawIntoLayer2 {
UIBezierPath* path = [UIBezierPath bezierPathWithRect:
CGRectMake(100+MIN_OFFSET_X, MIN_OFFSET_Y, 10, 10)];
[self.shapeLayer2 setPath:path.CGPath];
}
This obviates the need for drawRect - you only need to redraw your layers if you change the path property. Even if you do change the path property as often as you would call drawRect, the drawing should now be significantly more efficient. And as path is an animatable property, you also get animation thrown in for free if you need it.
In your case we only need to set the path once, so all of the work is done once, on initialisation.
Now you can remove any centering code from your scrollView delegate methods, it isn't needed any more.
I have a UICollectionView that has only a few cells (about 20). Performance for this collection works great. However, as soon as I try to round the corners of the UICollectionViewCells that are being rendered by this view, my performance takes a significant hit. In my cell's init method, this is the only line I add to cause this:
[self.layer setCornerRadius:15];
Since this is in the init method and I am reusing the cells properly, I don't see why this should be causing me issue.
I have tried adjusting the rasterization and opacity of the sell using multiple combinations of the following, with still no effect:
[self.layer setMasksToBounds:YES];
[self.layer setCornerRadius:15];
[self.layer setRasterizationScale:[[UIScreen mainScreen] scale]];
self.layer.shouldRasterize = YES;
self.layer.opaque = YES;
Is their some setting or trick to improve the performance of a UICollectionView that has cells with rounded corners?
As #Till noted in comments, a prerendered image should solve your performance problem. You can put all the corner rounding, shadowing, and whatever other special effects into that instead of needing CA to render them on the fly.
Prerendered images don't lock you into a static content size, either: look into the UIImage resizable image stuff. (That's still way faster than CA rendering every frame.)
I have found that this is caused entirely because of the call to dequeuereusablecellwithidentifier. Each time this is called, the cell with rounded corners needs to be re-rendered. If the collection view did not remove them from the view when the item scrolled off the screen, then the performance would not be affected (as long as their wasn't too many items in the collection that is). Seems like a double edged sword - both ways have their limits.
There is a code for UIView subclass, which is provide you a view with opaque rounded borders and transparent hole in the middle.
You should create needed view as usual and after that you can add view with hole over your view. Visualisation is here.
It works if you use one-colored background for UICollectionView or UITableView, you can add following subview for each cell:
#interface TPRoundedFrameView : UIView
#property (assign, nonatomic) CGFloat cornerRadius;
#property (strong, nonatomic) UIColor * borderColor;
#end
#implementation TPRoundedFrameView
- (instancetype)init {
if ((self = [super init])) {
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
UIBezierPath * path = [UIBezierPath bezierPathWithRect:rect];
UIBezierPath * innerPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:self.cornerRadius];
[path appendPath:[innerPath bezierPathByReversingPath]];
[self.borderColor set];
[path fill];
}
#end
Example for target cell class:
- (void)awakeFromNib {
[super awakeFromNib];
// creating holed view with rounded corners
self.myRoundedView.backgroundColor = [UIColor whiteColor];
TPRoundedFrameView * roundedFrame = [TPRoundedFrameView new];
roundedFrame.cornerRadius = 5.f;
roundedFrame.borderColor = [UIColor groupTableViewBackgroundColor];
// add borders to your view with appropriate constraints
[self.myRoundedView addSubview:roundedFrame];
roundedFrame.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary * views = NSDictionaryOfVariableBindings(roundedFrame);
NSArray * horizontal = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[roundedFrame]-0-|" options:0 metrics:nil views:views];
NSArray * vertical = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[roundedFrame]-0-|" options:0 metrics:nil views:views];
[self.myRoundedView addConstraints:horizontal];
[self.myRoundedView addConstraints:vertical];
}
Result:
Table with rounded views as cells
I fixed all of my performance borderRadius issues by applying this radius on the contentView instead of the cell itself.
self.contentView.layer.borderWidth = 1.0f;
self.contentView.layer.cornerRadius = 5.0f;
self.contentView.layer.borderColor = [UIColor colorWithRed:202/255. green:202/255. blue:202/255. alpha:1.0].CGColor;