I have a tableview with only a few rows. So instead of displaying a bunch of blanks I added a blank UIView to the tableview.footer. However I would like the last cell to cast a dropshadow on the UIView. How would I achieve this? Here is my current code.
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *emptyView = [[UIView alloc] initWithFrame:CGRectZero];
CALayer *layer = [emptyView layer];
[layer setShadowOffset:CGSizeMake(0, 1)];
[layer setShadowColor:[[UIColor darkGrayColor] CGColor]];
[layer setShadowRadius:8.0];
[layer setShadowOpacity:0.8];
self.tableView.tableFooterView = emptyView;
}
EDIT:
It is adding the UIView to the footer but not creating the dropshadow. I'm not sure the layer is the best approach for this or even correct for this type of thing.
It is probably because you set the frame to CGRectZero.
The zero rectangle is equivalent to CGRectMake(0,0,0,0).
A shadow of a zero rect (x=0, y=0, width=0, height=0) won't show at all.
Try giving it a proper frame size and you will see the difference.
Check out this for ref as well: https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html
I ended up using
shadowBackgroundView.layer.shadowOpacity = 0.3;
shadowBackgroundView.layer.shadowRadius = 2;
shadowBackgroundView.layer.shadowColor = [[UIColor blackColor] CGColor];
shadowBackgroundView.layer.shadowOffset = CGSizeMake(0.0, 1.0);
CGPathRef shadowPath = [UIBezierPath bezierPathWithRoundedRect: shadowBackgroundView.bounds
byRoundingCorners: UIRectCornerAllCorners
cornerRadii: CGSizeMake(PageCellBackgroundRadius, PageCellBackgroundRadius)].CGPath;
shadowBackgroundView.layer.shadowPath = shadowPath;
shadowBackgroundView.layer.shouldRasterize = YES;
[self addSubview: shadowBackgroundView];
In cellForRowAtIndexPath: function:
// drop shadow
cell.layer.shadowOpacity = 1.0;
cell.layer.shadowRadius = 1.7;
cell.layer.shadowColor = [UIColor blackColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(0.0, 0.0);
Related
Consider this image
How would I go about drawing a custom UIView that is literally just a ellipse. Would I just override the drawRect method? And can someone show me the code for dragging red ball on ecllips path?
Drawing the ball can be done in a custom drawRect if you want, or you could use CAShapeLayer:
UIView *ball = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
ball.userInteractionEnabled = TRUE;
CAShapeLayer *ballLayer = [CAShapeLayer layer];
ballLayer.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 50) radius:48 startAngle:0 endAngle:M_PI * 2.0 clockwise:YES].CGPath;
ballLayer.strokeColor = [UIColor blackColor].CGColor;
ballLayer.lineWidth = 0.5;
ballLayer.fillColor = [UIColor redColor].CGColor;
ballLayer.shadowColor = [UIColor blackColor].CGColor;
ballLayer.shadowRadius = 2;
ballLayer.shadowOpacity = 0.75;
ballLayer.shadowOffset = CGSizeZero;
[ball.layer addSublayer:ballLayer];
[self.view addSubview:ball];
Creating the ellipse could be done in a similar fashion.
Dragging the ball could be done with a gesture.
UIGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[ball addGestureRecognizer:pan];
Where:
- (void)handlePan:(UIPanGestureRecognizer *)gesture {
CGPoint translate = [gesture translationInView:gesture.view];
if (gesture.state == UIGestureRecognizerStateChanged) {
gesture.view.transform = CGAffineTransformMakeTranslation(translate.x, translate.y);
} else if (gesture.state == UIGestureRecognizerStateEnded) {
gesture.view.center = CGPointMake(gesture.view.center.x + translate.x, gesture.view.center.y + translate.y);
gesture.view.transform = CGAffineTransformIdentity;
}
}
You presumably would want to constrain the ball's movement to the ellipse, then you'd just adjust the translate coordinates accordingly. But hopefully this illustrates how to create a gesture recognizer, and move a UIView accordingly.
I have an UIView which I created and set background color to white. This view contains UILabel, which is a class called BubbleView. (Sorry I cannot add a picture because you need reputation 10+ :(
PROBLEM:
1. The following code produces a gray Label with rounded corner with gray-border square corner tips. This is because the UIView produces the square corner tips. The UILabel is rounded. Please note that I already set the background of UIView to white.
2. My text string of the UILabel is hiding behind UIView, so it is not displayed.
I'd love to show you pictures, but I am new and I cannot add pictures until I get to 10+ reputations.
http://i.stack.imgur.com/CdRjy.png
http://i.stack.imgur.com/zCdCV.png
Here is my code for setting the text and the view:
BubbleView:
- (void)drawRect:(CGRect)rect
{
const CGFloat boxWidth = self.bubbleWidth;
const CGFloat boxHeight = self.bubbleHeight;
NSLog(#"text, width, height: %#, %f, %f", self.text, self.bubbleWidth, self.bubbleHeight);
CGRect boxRect = CGRectMake(
roundf(self.bounds.size.width - boxWidth) / 2.0f,
roundf(self.bounds.size.height - boxHeight) / 2.0f,
boxWidth,
boxHeight);
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:boxRect cornerRadius:14.0f];
[[UIColor colorWithWhite:0.3f alpha:0.8f] setFill];
[roundedRect fill];
NSDictionary *attributes = #{
NSFontAttributeName : [UIFont systemFontOfSize:16.0f],
NSForegroundColorAttributeName : [UIColor whiteColor]
};
CGPoint textPoint = CGPointMake(
self.center.x+boxWidth/2,
self.center.y+boxHeight/2);
NSLog(#"text point origin: %f, %f", textPoint.x, textPoint.y);
[self.text drawAtPoint:textPoint withAttributes:attributes];
}
Main View Controller:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
[self setText];
}
-(void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self setText];
}
- (void) setText
{
NSString *textR = #"I need this text to show up on autolayout so that i could continue working";
UIFont* font = [UIFont fontWithName:#"HelveticaNeue" size:14.0f];
CGSize constraint = CGSizeMake(250,9999);
CGRect textRect = [textR boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:font}
context:nil];
BubbleView *hostView = [[BubbleView alloc] initWithFrame:CGRectMake(20.0f, 160.0f, textRect.size.width+20, textRect.size.height+20)];
hostView.bubbleWidth = textRect.size.width+20;
hostView.bubbleHeight = textRect.size.height+20;
hostView.text = textR;
hostView.layer.cornerRadius = 10.0f;
self.view.layer.masksToBounds = TRUE;
[hostView drawRect:textRect];
hostView.backgroundColor = [UIColor whiteColor];
self.detailsView = hostView;
//self.detailsView.backgroundColor = [UIColor whiteColor];
NSLog(#"size: %f, %f", textRect.size.width, textRect.size.height);
NSLog(#"origin: %f, %f - size: %f, %f, backgroundColor: #%#", self.detailsView.frame.origin.x, self.detailsView.frame.origin.y, self.detailsView.frame.size.width, self.detailsView.frame.size.height, self.detailsView.backgroundColor);
[self.view addSubview:self.detailsView];
self.hostSays.text = textR;
self.hostSays.textColor = [UIColor blueColor];
[self.view layoutSubviews];
}
SOLUTION (ONLY 1 PART):
OK so I managed to solve half of my problems. I had to add the following code in my BubbleView class (inside - (id)initWithFrame:(CGRect)frame). This got rid of the square angles! (I think Wain was the one who suggested this but I might've misunderstood him)...
[self setOpaque:NO];
[self setBackgroundColor:[UIColor clearColor]];
So...still have the other part 2 of problem to solve and I'm hoping someone has run into this issue before!
Set the background colour of the view and add the label as a subview. Set the frame to get your required padding. Do not implement drawRect.
Now, the view will draw the background colour and the label automatically and the label will draw the text (with its background colour and border settings).
I know when I create custom buttons I need to setMasksToBounds
+ (void) addBorderToButtons:(UIButton *) btn
{
// Round button corners
CALayer *btnLayer = [btn layer];
[btnLayer setMasksToBounds:YES];
[btnLayer setCornerRadius:15.0f];
// Apply a 1 pixel, black border around Buy Button
[btnLayer setBorderWidth:1.5f];
[btnLayer setBorderColor:[[UIColor blackColor] CGColor]];
}
Setting this changes
To this
If you want to save your coding approach you strongly need to add [super drawRect:rect] in your drawRect: method
- (void)drawRect:(CGRect)rect{
[super drawRect:rect];
YOUR CODE
}
In this case you will see your text in UILabel.
Also you should not call drawRect: directly. It will be called automatically in runtime:
BubbleView *hostView =
[[BubbleView alloc] initWithFrame:CGRectMake(20.0f,
160.0f,
textRect.size.width+20,
textRect.size.height+20)];
hostView.bubbleWidth = textRect.size.width+20;
hostView.bubbleHeight = textRect.size.height+20;
hostView.text = textR;
// hostView.layer.cornerRadius = 10.0f;
// self.view.layer.masksToBounds = TRUE;
// [hostView drawRect:textRect];
// hostView.backgroundColor = [UIColor whiteColor];
self.detailsView = hostView;
I'm trying to crop an image to an irregular shape, but I need to make the area that was removed transparent.
Inside subclass of UIView
CALayer *myLayer = [CALayer layer];
CAShapeLayer *mask = [CAShapeLayer layer];
myLayer.frame = self.bounds;
myLayer.contents = (id)[self.picture CGImage];
mask.path = path;
myLayer.mask = mask;
[self.layer addSublayer:myLayer];
This will crop the image appropriately, but the background color of the view is white and therefore still visible. I've tried making the other layers transparent, but it has not worked.
(self and subview both refer to same view)
[self layer].backgroundColor = [UIColor clearColor].CGColor //no change
[self layer].opacity = 0; //makes entire view transparent
subView.backgroundColor = [UIColor clearColor]; // entire view becomes transparent
Is it possible to create the effect I'm trying to achieve?
I tried the same thing, here is the exact code:
// In KMViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
CGRect frame = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
KMView *view = [[KMView alloc] initWithFrame:frame];
view.center = self.view.center;
[self.view addSubview:view];
}
// In KMView.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// self.backgroundColor = [UIColor clearColor];
CALayer *layer = [CALayer layer];
CAShapeLayer *mask = [CAShapeLayer layer];
layer.frame = self.bounds;
UIImage *image = [UIImage imageNamed:#"orange"];
layer.contents = (id)image.CGImage;
CGPathRef path = CGPathCreateWithEllipseInRect(frame, NULL);
mask.path = path;
CGPathRelease(path);
layer.mask = mask;
[self.layer addSublayer:layer];
}
return self;
}
It worked for me as expected. The background was transparent. Then I tried adding
self.backgroundColor = [UIColor clearColor];
to the beginning of the code and nothing changed, the image was showing on a transparent background clipped to the path.
I think the problem might be somewhere else.
I am adding a shadow to my view by following
- (void)viewDidLoad{
[super viewDidLoad];
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
self.view.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.view.layer.shadowOpacity = 1.0f;
self.view.layer.shadowRadius = 4.0f;
self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
}
However, I am getting a view with no shadow at all like below
Did I miss some points in the middle of the way. Please advice me on this issue
You need to set layer.masksToBounds to NO and clipsToBounds to YES.
self.view.layer.masksToBounds = NO;
self.view.clipsToBounds = YES;
You are not offsetting your shadow at all.
Try:
self.view.layer.shadowOffset = CGSizeMake(0.0f, 1.0f);
Sorry all, this is my stupid mistake. The view structure I am having is
view(UIView) ( in white color )
|
|
aView (UIView) ( in orange color )
what I did was to show the shadow of view not aView. Just corrected the code like below
(void)viewDidLoad{
[super viewDidLoad];
self.aView.layer.shadowColor = [UIColor blackColor].CGColor;
self.aView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.aView.layer.shadowOpacity = 1.0f;
self.aView.layer.shadowRadius = 4.0f;
self.aView.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath;
}
making the offset 0, will produce a nil effect on the view.
you can try this:
-(void)makeShadow
{
self.layer.shadowOpacity = 0.7f;
self.layer.shadowOffset = CGSizeMake(5.0f,3.0f);
self.layer.shadowColor =[[UIColor blackColor] CGColor];
// UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
// layer.shadowPath = path.CGPath;
// layer.shadowRadius = 5.0f;
}
-(void)makeCornerRadius:(CGFloat)_cornerRadius
{
self.cornerRadius = _cornerRadius;
[self.layer setMasksToBounds:NO];
[self.layer setCornerRadius:_cornerRadius];
}
you should make the offset have a certain value not 0.
for example:
self.view.layer.shadowOffset = CGSizeMake(3, -1);
so that there will be a shadow forming in your view.
Make sure that self.clipsToBounds = NO;
Your view looks unrelated to the code you provided. Be sure you are applying the shadow to the correct view, you are not masking the view to its bounds, and the colors are correct. The code below shows a working example:
UIView *pointView = [[UIView alloc] initWithFrame:pointLabel.frame];
pointView.backgroundColor = [UIColor whiteColor];
pointView.layer.shadowColor = [UIColor lightGrayColor].CGColor;
pointView.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
pointView.layer.shadowOpacity = 1.0f;
pointView.layer.shadowRadius = 5.0f;
pointView.layer.shadowPath = [UIBezierPath bezierPathWithRect:pointView.bounds].CGPath;
I've been unsuccessful at animating a flashing stroke on a CAShapeLayer using the answer from this previous thread, and after many searches I can find no other examples of animating the stroke using CABasicAnimation.
What I want to do is have the stroke of my CAShapeLayer pulse between two colors. Using CABasicAnimation for opacity works fine, but the [CABasicAnimation animationWithKeyPath:#"strokeColor"] eludes me, and I'd appreciate any advice on how to successfully implement.
CABasicAnimation *strokeAnim = [CABasicAnimation animationWithKeyPath:#"strokeColor"];
strokeAnim.fromValue = (id) [UIColor blackColor].CGColor;
strokeAnim.toValue = (id) [UIColor purpleColor].CGColor;
strokeAnim.duration = 1.0;
strokeAnim.repeatCount = 0.0;
strokeAnim.autoreverses = NO;
[shapeLayer addAnimation:strokeAnim forKey:#"animateStrokeColor"];
// CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
// opacityAnimation.fromValue = [NSNumber numberWithFloat:0.0];
// opacityAnimation.toValue = [NSNumber numberWithFloat:1.0];
// opacityAnimation.duration = 1.0;
// opacityAnimation.repeatCount = 0.0;
// opacityAnimation.autoreverses = NO;
// [shapeLayer addAnimation:opacityAnimation forKey:#"animateOpacity"];
Uncommenting the opacity animation results in an expected opacity fade. The stroke animation produces no effect. An implicit strokeColor change animates as expected, but I would like documented confirmation that strokeColor can be explicitly animated using CABasicAnimation.
Update: The specific problem was that shapeLayer.path was NULL. Correcting that fixed the problem.
The code below works great for me. What is the lineWidth of your shapeLayer stroke path? Could that be the issue?
- (void)viewDidLoad
{
[super viewDidLoad];
UIBezierPath * circle = [UIBezierPath bezierPathWithOvalInRect:self.view.bounds];
CAShapeLayer * shapeLayer = [CAShapeLayer layer];
shapeLayer.path = circle.CGPath;
shapeLayer.strokeColor =[UIColor blueColor].CGColor;
[shapeLayer setLineWidth:15.0];
[self.view.layer addSublayer:shapeLayer];
CABasicAnimation *strokeAnim = [CABasicAnimation animationWithKeyPath:#"strokeColor"];
strokeAnim.fromValue = (id) [UIColor redColor].CGColor;
strokeAnim.toValue = (id) [UIColor greenColor].CGColor;
strokeAnim.duration = 3.0;
strokeAnim.repeatCount = 0;
strokeAnim.autoreverses = YES;
[shapeLayer addAnimation:strokeAnim forKey:#"animateStrokeColor"];
}
Let me know if it works for you...