Creating a dropshadow for UITableView - cocoa-touch

Would somebody please explain how to create a one or two pixel drop shadow ONLY on the the very last cell (in other words, I don't want a shadow around the entire tableview, just the bottom cell. An image of what I'm talking about:

Solved. Use the following code to produce a very nice, subtle shadow to the bottom of your UITableViewCell. Makes it look like it's raised slightly out of the page :)
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(3, 49, cell.frame.size.width-26, 3)];/// change size as you need.
separatorLineView.backgroundColor = shadowColor;// you can also put image here
UIBezierPath *roundedShadow = [UIBezierPath bezierPathWithRoundedRect:separatorLineView.bounds byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:CGSizeMake(8.0f, 8.0f)];
CAShapeLayer *newSeparatorShape = [[CAShapeLayer alloc] init];
[newSeparatorShape setPath:roundedShadow.CGPath];
separatorLineView.layer.mask = newSeparatorShape;
[cell.contentView addSubview:separatorLineView];
Also, don't forget to put this at the top of your .m file #import <QuartzCore/QuartzCore.h>

You could, in tableView:cellForIndexPath: set the cell's background image to one that includes the rounded corners with the shadow.

Related

outside border for UIImageView

I know I can create border using below code.
[[myImageView layer] setBorderWidth:2.0f];
[[myImageView layer] setBorderColor:[UIColor greenColor].CGColor];
However this draw border inside image.
What I was looking is draw border outside ImageView.
Note:
I search online for this and found below.
Can be done by using another image which will have border.
Can be done by drawing another view which is little bigger then current image.
Is there quick way (especially in-built in iOS), where I can draw border outside UIImageView? Any views?
Why don't you try border with using imageview's frame ?
CGFloat borderWidth = 5.0f;
self.imgview.frame = CGRectInset(self.imgview. frame, -borderWidth, -borderWidth);
self.imgview. layer.borderColor = [UIColor blueColor].CGColor;
self.imgview. layer.borderWidth = borderWidth;
There is no quickway in-built in iOS, there is no margin that you could set on the image layer.
If I were you, I'd develop a new class that inherit from UIView (ex UIImageWithBorderView) and which include a UIImageView and making the "UIImageWithBorderView" bigger than the UIImageView (and think about NOT to autoresize the UIImageView with the UIView parent, otherwise your UIImageView will be stretched, and prevent the UIImageWithBorderView from being smaller than the UIImageView frame), and then add borders to the "UIImageWithBorderView".
This way, your UIImageView will be intact and you'll have a specific, reusable composant for your needs.
Hope it helps !

Customizing tableView: Corner radius, decreased width and shadow

This is what I want to do:
As you can see i want to:
Decrease the width of the tableView (I want more margin on the sides than the grouped tableView provides)
Corner radius (bigger radius than the default for grouped tableView)
Drop shadow around the table and a special shadow beneath the last cell
You can do this by "drawing" the backgroundView of the cells yourself.
I'd recommend getting an image to use as the background (if the cells are all the same height).
You'll need three images.
A "top" image with the top corners rounded.
A "bottom" image with the bottom corners rounded and the drop shadow how you want it.
And a "middle" image with no rounded corners.
If the cells don't have any texture or gradient within them then you can use stretchable images to reduce the memory footprint of them.
Then I would subclass the UITableViewCell and override the backgroundView to add a UIImageView. I'd also provide an accessor method to change the type (top, middle, bottom) of the cell.
Each cell can then have three placeHolder properties of a UIImage (topImage, bottomImage and middleImage). When the type of the cell is changed these can be accessed (use lazy instantiation to make sure they are only loaded once and only when needed) and then set the backgroundVIew image to be the required image.
Something like this...
In the UITableViewCell subclass define a type enum...
typedef enum {
CellTypeTop,
CellTypeMiddle,
CellTypeBottom
} cellType;
Then a property for the type...
#property (nonatomic) cellType cellType
Then in the .m ...
Define some more internal properties...
#property UIImageView *bgImageView;
#property UIImage *topImage;
#property UIImage *middleImage;
#property UIImage *bottomImage;
Then add the imageView (only once)...
- (void)awakeFromNib //or in the init depends how you are initialising the cell
{
self.bgImageView = [[UIImageView alloc] initWithFrame:blah];
[self.backgroundView addSubView:self.bgImageView];
}
Now when the type is changed...
- (void)setCellType:(cellType)cellType
{
switch(cellType) {
case CellTypeTop:
self.bgImageView.image = self.topImage;
break;
case CellTypeMiddle:
self.bgImageView.image = self.middleImage;
break;
case CellTypeBottom:
self.bgImageView.image = self.bottomImage;
break;
}
}
Finally a lazy instantiation of the images...
- (UIImage *)topImage
{
if (_topImage == nil) {
_topImage = [UIImage imageNamed:#"topImage"];
//alternatively...
_topImage = [[UIImage imageNamed:#"topImage"] stretchableImageWith...
}
return _topImage;
}
Now repeat these for the other images.
This will be more performant (by a long way) than using a CALayer alternative and, especially if using the stretchable images, will have a very small memory footprint.
Several other users have said that this is not good for performance, memory, design, whatever, but it really is the best way to get the best performance for UserExperience than CALayers. Yes, it will use more memory than CALayers but only marginally and it will get to a limit as there are only a few dequeueable cells created.
A couple of links explaining performance issues when using CALayers in scrollViews...
http://www.quora.com/iOS-Development/What-is-the-best-way-to-optimize-the-performance-of-a-non-paging-but-view-recycling-UIScrollView-involving-loading-potentially-caching-and-displaying-bundled-images
Bad performance on scroll view loaded with 3 view controllers, drawn with CALayer
::EDIT:: Edit to answer Michael's question.
In the storyboard create a UITableViewController (rename the Class in the inspector so that it matches your subclass UITableViewController - I'll call it MyTableViewController).
Create a subclass of UITableViewCell (I'll call mine MyTableViewCell) in the code (i.e. the .h and .m).
Add the above code to do with properties and types and imageViews to your MyTableViewCell.h file.
In the storyboard select the cell in the TableViewController and rename the class to MyTableViewCell. Also set the reuse identifier on it.
In the MyTableViewController code you will need a function like this...
-(UITableViewCell*)tableView:(UITabelView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
MyTableViewCell *cell = [tableView dequeueCellWithReuseIdentifier:#"Cell"];
cell.cellType = CellTypeTop; //or whichever it needs to be
cell.textLabel.text = #"Blah";
return cell;
}
Oh, another thing, in the storyboard you will be able to layout your cell how you want it to look and link up all the labels and imageviews etc... Make sure you add IBOutlet to the UIImageView so that you can link it up in the storyboard.
make sure you have #import <QuartzCore/QuartzCore.h> imported, then you can start accessing the layers of the UITableView like.
UITableView *yourTable = [[UITableView alloc] initWithStyle:UITableViewStyleGrouped];
[[yourTable layer] setCornerRadius:10.0f];
[[yourTable layer] setShadowColor:[[UIColor blackColor] CGColor]];
[[yourTable layer] setShadowOffset:CGSizeMake([CALayer ShadowOffSetWidthWithFloat:10.0f], [CALayer ShadowOffSetWidthWithFloat:10.0f])];
[[yourTable layer] setShadowOpacity:[CALayer ShadowOpacity:1]];
[[yourTable layer] setMasksToBounds:NO];
UIBezierPath *path = [UIBezierPAth bezierPathWithRect:yourTable.bounds];
[[yourTable layer] setShadowPath:[path CGPath]];
This will add shadow affect to your table view with the shadow not masked to the bounds of the UITableView, at setCornerRadius you can set the corners of the table to whatever you want. You can also set the frame of the UITableView by doing
[yourTable setFrame:CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)];
EDIT
As another user has tried to point out that CALayer is very slow, this is not the case
CALayer was introduced to help performance issues around animation. Please read documentation. Loading an image straight in may seem like a good idea but in the long run will take up more memory. Please this question about memory allocation for images. As you can see it may seem faster, but it takes up 2.25 MByte of memory per image which after loading each image so many times your app will start to become slow.

Draw Over Image

I'm working on some drawing code. I have that portion working great.
I want to draw over an image, but I want to still be able to see the detail of the image, the black lines, etc.
What I am working on is making a transparent UIImageView that holds the image.
I'm not sure how to get this set up properly though.
Should this be added above the other UIImageView that I color on or below it?
Here's what I have so far:
- (void)viewDidLoad
{
[super viewDidLoad];
topImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 46, 320, 370)];
[topImageView setImage:[UIImage imageNamed:#"imagesmall.png"]];
topImageView.alpha = 1.0;
topImageView.layer.opacity = 1.0;
topImageView.layer.opaque = NO;
[self.view addSubview:topImageView];
[topImageView release];
}
Thoughts anyone?
Yes, you can draw views over other views. They are drawn in the order that they're added as subviews, unless you reorder them after that.
You may need to set the opaque property for some views (this is distinct from and overrides their layer opacity), and set their backgroundColor to nil. UIImageView seems to be transparent by default, as long as its image is; some other UIView subclasses are not.
So, just what is your overlay going to be? If you just need to display one image over another, what you have here seems to work already. If you need to draw some lines programmatically, you'll need to do this:
Create a subclass of UIView.
Implement its drawRect method to display the content you need.
When you add your custom view on top of the background image, make sure it is not opaque and has no backgroundColor.
A common problem here is to find that your foreground is working, but the background isn't being loaded properly. To make sure the background is there, set the alpha of the foreground view to 0.5. You won't want to do that in production, but it will allow you to verify that both views exist.

Custom background drawing in an grouped UITableViewCell

I'm having some trouble drawing a custom gradient background in a UITableViewCell when the style is set to 'grouped' and the cell is first or the last one of the section. My approach is to simply create a CAGradientLayer and add it to the view like this:
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = rect;
gradient.colors = [NSArray arrayWithObjects:(id)[_backgroundColorLight CGColor], (id)[_backgroundColorDark CGColor], nil];
[self.backgroundView.layer insertSublayer:gradient atIndex:0];
self.backgroundView.layer.masksToBounds = YES;
Unfortunately this produces cells like this one:
Does anyone have a hint on how to make the background fit the boarders of the cell?
Thanks
–f
If you draw a custom background, you also have to draw the borders yourself. There's quite some open source stuff out there.
Basically, you need to know [in the cell] if it's top/middle/bottom/single, and cut the stuff in drawRect. You won't come far with insertSublayer.
Check out the PageCellBackground class you find here:
http://cocoawithlove.com/2010/12/uitableview-construction-drawing-and.html
I've not tried it but CAGradientLayer happens to be a subclass of CALayer, so perhaps setting its borderRadius may work. But it rounds all corners then, so you may compensate for that by making the layer bigger than the cell and have the cell view cut it off.
Look at Rounded UIView using CALayers - only some corners - How? for more examples

reproduce UITableViewCellSeparatorStyleSingleLineEtched in UITableViewStylePlain

How can one reproduce the same effect as Single Line Etched when using plain table and custom cells?
I think I need to add them as subview to each cell, excluding the last one. I want to know how to reproduce that without having to use images to that. Does anyone know?
Isn't the separator just a single pixel grey line, even for Single Line Etched?
In this case, create a UIView the width of the cell, but only one pixel high and then set it's background colour,then stick it at the bottom of the cell's content view.
UIView *lineView;
lineView = [[UIView alloc] initWithFrame:CGRectMake(0.0f,
cell.contentView.bounds.size.height-1.0f,
cell.contentView.bounds.size.width,
1.0f);
lineView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
lineView.backgroundColor = [UIColor grayColor];
[cell.contentView addSubview:lineView];