Round corners on UITableView - iphone

What is the best way to get round corners on an entire UITableView as seen in Stocks and Spotlight? The grouped style doesn't solve the problem because the round corners scroll away with the cell. I'm trying to clip the view so the corners are always round regardless of scroll position.
I saw another discussion about doing this to a UIImage that suggested masking it with another image. I'm not sure if this would work because I need taps to pass through to the table. This isn't isn't ideal for me because I want the background pattern to show through through the corners.

It's an old question but perhaps you still want to know how to do this.
I reproduced a tableView like in Stocks/Spotlight. The trick is
view.layer.cornerRadius = 10;
For this to work you need to include the QuartzCore into the class that you call that property:
#import <QuartzCore/QuartzCore.h>
I heard that this only works since OS 3.0. But since my application is using core data it wasn't a problem because it was already for OS 3.0 and hight.
I created a custom UIView with a subview with cornerRadius 10 and with
view.backgroundColor = [UIColor clearColor];
Then you have to place an UITableView grouped style in that subview. You need to set the backgroundColor to clearColor and the separatorColor to clearColor. Then you have to position the tableview inside the rounded corner view, this is done by setting the frame size and origin. My loadView class of my custom UIView looks like this:
self.view = [[UIView alloc] init];
self.view.backgroundColor = [UIColor clearColor];
CustomUIViewClass *scherm = [[CustomUIViewClass alloc] init];
CGRect frame;
frame.origin.x = 10;
frame.origin.y = 50;
frame.size.width = 300;
frame.size.height = 380;
scherm.frame = frame;
scherm.clipsToBounds = YES;
scherm.layer.cornerRadius = 10;
[self.view addSubview:scherm];
CustomUITableViewClass *table = [[CustomUITableViewClass alloc] initWithStyle:UITableViewStyleGrouped];
frame.origin.y = -10;
frame.origin.x = -10;
frame.size.width = 320;
frame.size.height = 400;
table.tableView.frame = frame;
[scherm addSubview:table.tableView];
I hope you understand my english, maybe I will write a short blog post about this technique with a sample project, will post the link here when I'm ready.

An easier way to do this is to simply import the QuartzCore framework to your project. #import <QuartzCore/QuartzCore.h> to your tableViewController and just set
myTableView.layer.cornerRadius=5;
This will give you rounded corners without having to add your tableview to a superView or clipping it.

Instead of hacking through the code, here's an easy to mimic the grouped style. This works if all you want is one section.
In Interface Builder:
Set UITableView style to Plain and make the frame with some padding on the left and right, perhaps with x = 10 and width = 300.
Then set the corner radius and color yourself:
#import <QuartzCore/QuartzCore.h>
self.tableView.layer.borderColor = [UIColor colorWithWhite:0.6 alpha:1].CGColor;
self.tableView.layer.borderWidth = 1;
self.tableView.layer.cornerRadius = 4;

Have you tried the "grouped" table view style?
self.tableView.style = UITableViewStyleGrouped;
For further reference, see the Table View Programming Guide. The "About Table Views" chapter has some nice screenshots describing the different styles.

Well, there is alot of approach to solve this problem.
However, in my case, all doesn't work correctly. My table sometimes is smaller than table size.
I will share the way I did. I belive is alot easer and faster than some options above.
Make the first and last item rounded.
Create CAShapeLayer for top(left|right) and bottom(left|right).
shapeTop = [CAShapeLayer layer];
shapeTop.path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake( 0.0f, 0.0f, 306.0f, 58.0f )
byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
cornerRadii:CGSizeMake( 6.0f, 6.0f )].CGPath;
shapeBottom = [CAShapeLayer layer];
shapeBottom.path = [UIBezierPath
bezierPathWithRoundedRect:CGRectMake( 0.0f, 0.0f, 306.0f, 58.0f )
byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
cornerRadii:CGSizeMake( 6.0f, 6.0f )].CGPath;
The table need to be backgroud clearColor;
The cells has to be a colored background;
Set the layer.mask of it
UIView* backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
backgroundView.backgroundColor = [UIColor whiteColor];
cell.backgroundView = backgroundView;
Don't forget #import <QuartzCore/QuartzCore.h>

I recently came across this problem and solved it a different way. Thought I'd share the results with everyone.
I created a rectangular UIView with a clear, rounded-corner interior, and then laid that on top of the UITableView. You can find the full description at my programming blog.
It works exactly the way I want.

Below code for Swift version :
let redColor = UIColor.redColor()
self.tableView.layer.borderColor = redColor.colorWithAlphaComponent(0.9).CGColor
self.tableView.layer.borderWidth = 1;
self.tableView.layer.cornerRadius = 4;
Make sure that you have import QuartzCore in import section.

Here is swift extension:
extension UITableView {
public var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = true
}
}
}
Used by this way
tableView.cornerRadius = 7.5

UITableViewStyleInsetGrouped
A table view where the grouped sections are inset with rounded corners.
example code:
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
looks like:
Settings looking table view sections

Related

Slideshow using UIScrollView and AutoLayout

I wanted to create a simple slideshow of images using an UIScrollView and I noticed that, using the new AutoLayout mode, the operation became way more complicated compared to iOS5. I wasn't able to find any SIMPLE and SHORT example/tutorial for accomplishing it. There was a lot of material about "pure" and "hybrid" approaches,but honestly nothing really worked for me. Maybe the material is not clear enough, maybe I'm not good enough..who knows. Anyway, I thought it could be useful sharing my finding and the consequent snippet of code which is currently doing the job for me. Here we go:
- (void)setupSlideshow {
NSInteger nPhotos = [self.profilePhotos count];
UIScrollView *scrollView;
UIImageView *imageView;
NSDictionary *viewsDictionary;
// Create the scroll view and the image view.
scrollView = self.slideShow;
CGFloat sWidth = scrollView.frame.size.width;
CGFloat sHeight = scrollView.frame.size.height;
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, nPhotos * sWidth, sHeight)];
scrollView.pagingEnabled = YES;
CGFloat cx = 0;
for (int i = 0; i < nPhotos; i++) {
imageView = [[UIImageView alloc] init];
// Add an image to the image view.
[imageView setImage:[UIImage imageNamed:self.profilePhotos[i]]];
CGRect imFrame = imageView.frame;
imFrame.origin.x = cx;
imFrame.origin.y = 0;
imFrame.size.width = sWidth;
imFrame.size.height = sHeight;
imageView.frame = imFrame;
[container addSubview:imageView];
cx += sWidth;
}
container.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:container];
// Set the constraints for the scroll view and the image view.
viewsDictionary = NSDictionaryOfVariableBindings(scrollView, container);
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-0-[container(%f)]-0-|",cx]
options:0
metrics: 0
views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[container]-0-|" options:0 metrics: 0 views:viewsDictionary]];
}
The scrollView has been instantiated in the StoryBoard.
As you can notice, I adopted an approach based on a UIView container for the pictures I want to use which has been added to a scrollview. I have then added some constraints using the Visual Constraints Format notation. I tried to match the width of the container to the scroller's one using this:
[NSString stringWithFormat:#"H:|-0-[container(==scrollView)]-0-|"]
but it doesn't work (to be precise it doesn't scroll but sticks to the first image), so I opted for a dynamic approach using a simple string format.
As I said, it does the job, but I'm sure I can make it way more elegant. Besides that, is it possible to fix the problem relative the dynamic width?
I hope to receive some useful feedback, in order to refine this example. I will then setup a GitHub for making it publicly available for all of those who spent 3 days banging their head against a wall...like I did.

tableView as subview in a semi-transparent view

I'm developing a little iOS component and I have a problem with a semi-transparent view with subviews. This is my scenario:
- one view with a semi-transparent background using [UIColor colorWithRed:green:blue:alpha]
- a little UITableView, with alpha = 1.0, added as a subview to the semi-transparent view
- some other subviews
Everything works well but the problem raises when the UITableView is scrolled up or down, in fact the area of the semi-transparent view around the UITableView loses its transparency becoming darker than its original background color.
Here's an image to explain the problem:
Look at the space with the two arrows...
Can anyone help me with this problem?
Thank you so much for your attention!
Update:
Some code:
_alertBg = [[UIView alloc] initWithFrame:CGRectZero];
_alertBg.backgroundColor = self.backgroundColor;
_alertBg.frame = CGRectMake((_bgView.frame.size.width - 240) / 2, (_bgView.frame.size.height - 260) / 2, 240, 260);
_alertBg.layer.cornerRadius = 8.0;
_alertBg.layer.borderWidth = 2.0;
_alertBg.layer.borderColor = self.borderColor.CGColor;
_alertBg.layer.shadowColor = [UIColor grayColor].CGColor;
_alertBg.layer.shadowOffset = CGSizeMake(0, 3);
_alertBg.layer.shadowOpacity = 0.8;
_alertBg.layer.masksToBounds = YES;
[_bgView addSubview:_alertBg];
_table = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_table.frame = CGRectMake(10, _titleLabel.frame.origin.y + _titleLabel.frame.size.height + 12, _alertBg.frame.size.width - 20, 150);
_table.layer.cornerRadius = 6.0;
_table.layer.masksToBounds = YES;
_table.delegate = self;
_table.dataSource = self;
[_alertBg addSubview:_table];
From the code above, self.backgroundColor is something like [UIColor colorWithRed:0 green:0 blue:1 alpha:0.7]
I put the available code in a test project, and got the same problem as you have. Commenting out _alertBg.layer.shadowOpacity = 0.5; fixes the issue for me. Maybe someone can clarify why is this an issue, I have limited experience with QuartzCore.
EDIT: Okay, inched closer to the real reason. It seems that if you don't have set the _alertBg.layer.shadowPath property all kinds of crazy things happen when you scroll the table (my guess here is that the table scroll calls a redraw of the _alertBg and the shadow redrawing gets called in quick succession far too many times and you get those visual artifacts).
Adding a shadowPath fixes the problem, so the layer code for the _alertBg should be as following:
_alertBg.layer.cornerRadius = 8.0;
_alertBg.layer.borderWidth = 2.0;
_alertBg.layer.borderColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.7].CGColor;
_alertBg.layer.shadowColor = [UIColor grayColor].CGColor;
_alertBg.layer.shadowOffset = CGSizeMake(0, 5);
_alertBg.layer.shadowOpacity = 0.8;
_alertBg.layer.shadowPath = [UIBezierPath bezierPathWithRect:_alertBg.bounds].CGPath;
_alertBg.layer.masksToBounds = YES;
Just fix the shadowPath to your liking and you should be ready to go.
PS: On my Google-quest I found this excellent blog post about shadows, it might be of help.
Maybe match the background colour of tableView with _alertBg?
Its may be problem of dequeueReusableCellWithIdentifier.
just try this..., set dequeueReusableCellWithIdentifier to nil like bellow in cellForRowAtIndexPath method of UITableViewController delegate method
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
Also see my this answer may be you can get some idea from this..
iPhone Hide/Show labels in Uitableview cell

Customize UISearchBar: Trying to get rid of the 1px black line underneath the search bar

My question is already specified in the title: I would like to get rid of the black line drawn on the bottom of the UISearchBar. Any ideas?
Here's an image of what I mean:
UPDATE:
I think that the line is part of the UITableView's tableHeaderView. I still don't know how to remove it.
Try this
searchBar.layer.borderWidth = 1;
searchBar.layer.borderColor = [[UIColor lightGrayColor] CGColor];
Why:
So, I've dug into the API's trying to figure out why this is happening. Apparently whomever wrote the UISearchBar API is rasterizing the lines onto an image and setting it as it's backgroundImage.
Solution:
I propose a simpler solution, if you want to set the backgroundColor and get rid of the hairlines:
searchBar.backgroundColor = <#... some color #>
searchBar.backgroundImage = [UIImage new];
Or if you just need a background image without the hairlines:
searchBar.backgroundImage = <#... some image #>
I have 0.5px black horizontal lines both on top and on the bottom of my UISearchBar. The only way I had so far to get rid of them is by setting its style to Minimal:
mySearchBar.searchBarStyle = UISearchBarStyleMinimal;
Solution for
XCode 10.1 Swift 4.2
I fixed this by adding a subview to the searchBar's view stack like so:
CGRect rect = self.searchBar.frame;
UIView *lineView = [[UIView alloc]initWithFrame:CGRectMake(0, rect.size.height-2,rect.size.width, 2)];
lineView.backgroundColor = [UIColor whiteColor];
[self.searchBar addSubview:lineView];
Here, self.searchBar is an UISearchBar pointer of my controller class.
Swift 4.2:
controller.searchBar.layer.borderWidth = 1
controller.searchBar.layer.borderColor = UIColor(red: 255/255, green: 253/255, blue: 247/255, alpha: 1.0).cgColor
Answer based on Ayush's answer.
This is ridiculous to have to go through hoops and bounds for this little 1 px line. I've been googling around for a couple of hours to get rid of it. I tried combos of different answer to get it to work. When I came back here I realized Oxcug already had it but it's in Objective-C and that's not native for me.
Anyway here is the answer in Swift 5. If you want to have a color background inside the actual search textField I added that too.
// these 2 lines get rid of the 1 px line
searchBar.backgroundColor = .white
searchBar.backgroundImage = UIImage()
// this line will let you color the searchBar textField where the user actually types
searchBar.searchTextField.backgroundColor = UIColor.lightGray
Set the tableHeaderView to nil before putting your UISearchBar there.
If that does not help, try to cover it up. First add your search bar to a generic and appropriately sized UIView (say, "wrapper") as a subview, then
CGRect frame = wrapper.frame;
CGRect lineFrame = CGRectMake(0,frame.size.height-1,frame.size.width, 1);
UIView *line = [[UIView alloc] initWithFrame:lineFrame];
line.backgroundColor = [UIColor whiteColor]; // or whatever your background is
[wrapper addSubView:line];
[line release];
And then add it to the tableHeaderView.
self.tableView.tableHeaderView = wrapper;
[wrapper release];
This question has already been solved but maybe my solution can help someone else. I had a similar problem, except I was trying to remove the 1px top border.
If you subclass UISearchBar you can override the frame like this.
- (void)setFrame:(CGRect)frame {
frame.origin.y = -1.0f;
[super setFrame:frame];
self.clipsToBounds = YES;
self.searchFieldBackgroundPositionAdjustment = UIOffsetMake(0, 1.0f);
}
Or if you would like to fix the bottom pixel you could do something like this, (untested).
- (void)setFrame:(CGRect)frame {
frame.origin.y = 1.0f;
[super setFrame:frame];
self.clipsToBounds = YES;
self.searchFieldBackgroundPositionAdjustment = UIOffsetMake(0, -1.0f);
}
Only for simplicity of the example are the clipsToBounds and searchFieldBackgroundPositionAdjustment in the setFrame.
Also the searchFieldBackgroundPositionAdjustment is only needed to re-center the search field.
UPDATE
It turns out that the tableView will shift 1px from updating the origin.y while the searchBar is active. It feels a little strange. I realized that the solution is as simple as setting, self.clipsToBounds = YES;
I used
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
searchBar.backgroundImage = UIImage() // Removes the line
And it worked like a charm :)
Warning. This is a hack. Would like to know a better, more official way.
You can use the pony debugger to figure out where in the subview hierarchy it is. I think the thing you are see is a private UIImageView called "separator"
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
for (UIView* view in self.searchBar.subviews) {
if (view.frame.size.height == 1 && [view isKindOfClass:[UIImageView class]]) {
view.alpha = 0;
break;
}
}
}
You can use
[[UISearchBar appearance] setSearchFieldBackgroundImage:[UIImage imageNamed:#"someImage.png"]forState:UIControlStateNormal];
on iOS 5+ to get rid of the line.
what worked with me is, setting the searchbar barTintColor as the navbar color
searchBar.barTintColor = UIColor.colorWithHexString(hexStr: "479F46")
after testing, it solves the problem in both iOS 10.x and 11.x
GIF :

Draw rectangle in custom table cell

How would I draw a rectangle in a custom table cell class? The cell currently has a background image with a few text labels. I would like to draw a rectangle behind each of the labels so they are easier to read over the detailed background image.
I know I could just set the background colour of the label but I would like to have padding between the background colour and the text. If that is possible, I'd love to know how! :)
I'm subclassing a TTTableMessageItemCell in Three20, a method below gets called in which you can play with subviews of the cell,
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat padding = 16;
CGFloat boxWidth = self.contentView.width - 2*padding;
CGFloat textWidth = boxWidth - (padding*2);
CGFloat textHeight = 100;
CGFloat top = kTableCellSmallMargin;
// Position Heading Text
_titleLabel.frame = CGRectMake(padding, top, textWidth, _titleLabel.font.ttLineHeight);
top += _titleLabel.height;
// Position Detail Text
[self.detailTextLabel sizeToFit];
self.detailTextLabel.top = top+2*padding;
self.detailTextLabel.left = 2*padding;
self.detailTextLabel.width = textWidth;
self.detailTextLabel.height = 100;
}
I would like the rectangles to be placed behind the _titleLable and detailTextLabel labels.
edit
I have been able to add the right box using the following,
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor whiteColor];
view.frame = CGRectMake(padding, top, textWidth, textHeight+2*padding);
[self insertSubview:view belowSubview:self.detailTextLabel];
It is laying on top of the label and I cant seem to get it behind it...
edit
I was adding the view to the wrong subview, fixed it with,
[[self.subviews objectAtIndex:0] insertSubview:view atIndex:0];
You can add the labels to views and these to the cell.
You could use insertSubview:belowSubview: to add views behind your labels. With backgroundColor and the right frame they will do what you intend to.
You can also bring detailLabel to front

Putting a graphical frame/border around a table

I've a few tables in my app. At the moment they are a plain standard transparent table.
You can see the background image behind the table and thats ok.
Put the table looks strange and maybe out of place because it is not obvious its a table.
Is there some option( i couldnt find any) for adding a frame/boarder(like a picture frame) around the table that the table can scroll inside of? I've searched though table and didnt see any.
So if thats true then that leaves me needing to draw a graphic over the table so that the table appears inside it. Any advise welcome.
EDIT:
CGRect cgRct = CGRectMake(30, 50, 270, 350);
table = [[[UITableView alloc] initWithFrame:cgRct
style:UITableViewStylePlain]autorelease];
table.backgroundColor = [UIColor clearColor];
table.layer.borderWidth = 5;
table.layer.borderColor = [UIColor redColor];
table.dataSource = self;
table.delegate = self;
[self.view addSubview:table];
Added this code and the import of Quartz.
But no boarder was drawn.
You can use its layers' properties:
#import <QuartzCore/QuartzCore.h>
tableView.layer.borderWidth = 1.0;
tableView.layer.borderColor = [UIColor redColor].CGColor;
You could also make the tableview smaller on all sides and the have that sit on an image of a frame.