I am using a Storyboard to create all my tables but I need to move the tables down the page to insert a UIView above each table. This was trivial using a nib and Interface builder or in code but I can't seem to do it via interface build and story boards. OK so then I try to do it code and no luck there either:
In viewDidLoad:
CGRect frame = self.view.frame;
self.view.frame = CGRectMake(frame.origin.x, frame.origin.y + 44.0f, frame.size.width,
frame.size.height - 44.0f);
If I check both self.view.frame and self.tableView.frame they have been re-sized, yet when the table displays nothing happen.
I have searched around but haven't found a solution so any help would be greatly appreciated.
Add your UIView in table header tableHeaderView.
Also, set custom height to the table header - sectionHeaderHeight:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableView_Class/Reference/Reference.html
Use this:
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 50.0;
}
Related
I have been working on this for about 2 days, so i thought i share my learnings with you.
The question is: Is it possible to make the width of a cell in a grouped UITableView smaller?
The answer is: No.
But there are two ways you can get around this problem.
Solution #1: A thinner table
It is possible to change the frame of the tableView, so that the table will be smaller. This will result in UITableView rendering the cell inside with the reduced width.
A solution for this can look like this:
-(void)viewWillAppear:(BOOL)animated
{
CGFloat tableBorderLeft = 20;
CGFloat tableBorderRight = 20;
CGRect tableRect = self.view.frame;
tableRect.origin.x += tableBorderLeft; // make the table begin a few pixels right from its origin
tableRect.size.width -= tableBorderLeft + tableBorderRight; // reduce the width of the table
tableView.frame = tableRect;
}
Solution #2: Having cells rendered by images
This solution is described here: http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html
I hope this information is helpful to you. It took me about 2 days to try a lot of possibilities. This is what was left.
A better and cleaner way to achieve this is subclassing UITableViewCell and overriding its -setFrame: method like this:
- (void)setFrame:(CGRect)frame {
frame.origin.x += inset;
frame.size.width -= 2 * inset;
[super setFrame:frame];
}
Why is it better? Because the other two are worse.
Adjust table view width in -viewWillAppear:
First of all, this is unreliable, the superview or parent view controller may adjust table view frame further after -viewWillAppear: is called. Of course, you can subclass and override -setFrame: for your UITableView just like what I do here for UITableViewCells. However, subclassing UITableViewCells is a much common, light, and Apple way.
Secondly, if your UITableView have backgroundView, you don't want its backgroundView be narrowed down together. Keeping backgroundView width while narrow down UITableView width is not trivial work, not to mention that expanding subviews beyond its superview is not a very elegant thing to do in the first place.
Custom cell rendering to fake a narrower width
To do this, you have to prepare special background images with horizontal margins, and you have to layout subviews of cells yourself to accommodate the margins.
In comparison, if you simply adjust the width of the whole cell, autoresizing will do all the works for you.
To do this in Swift, which does not provide methods to set variables, you'll have to override the setter for frame. Originally posted (at least where I found it) here
override var frame: CGRect {
get {
return super.frame
}
set (newFrame) {
let inset: CGFloat = 15
var frame = newFrame
frame.origin.x += inset
frame.size.width -= 2 * inset
super.frame = frame
}
}
If nothing works you can try this
Make the background colour of the cell as clear color and then put an image of the cell with required size. If you want to display some text on that cell put a label above the image. Don't forget to set the background color of the label also to clear color.
I found the accepted solution didn't work upon rotation. To achieve UITableViewCells with fixed widths & flexible margins I just adapted the above solution to the following:
- (void)setFrame:(CGRect)frame {
if (self.superview) {
float cellWidth = 500.0;
frame.origin.x = (self.superview.frame.size.width - cellWidth) / 2;
frame.size.width = cellWidth;
}
[super setFrame:frame];
}
The method gets called whenever the device rotates, so the cells will always be centered.
There is a method that is called when the screen is rotated : viewWillTransitionToSize
This is where you should resize the frame. See example. Change the frame coords as you need to.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
int x = 0;
int y = 0;
self.tableView.frame = CGRectMake(x, y, 320, self.tableView.frame.size.height);
}];
}
i do it in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
CGFloat tableBorderLeft = self.view.frame.origin.x + 10;
CGFloat tableBorderRight = self.view.frame.size.width - 20;
CGRect tableRect = self.view.frame;
tableRect.origin.x = tableBorderLeft;
tableRect.size.width = tableBorderRight;
tableView.frame = tableRect;
}
And this worked for me
In .h file add the delegate 'UITableViewDataSource'
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return size;
}
I had a lot of trouble resizing a UITableView to fit between an UINavigationBar and a UITabBar. My implementation involved creating a custom frame in viewDidAppear(), and then setting the UITableView to an appropriate frame. Although this solution works well, it doesn't work perfectly- the screen has a little spasm every time the view is loaded. I figured the issue was due to the UITableViewb becoming fullscreen, as it wants to, and then me resizing it, in front of the user's eyes. However, I have no idea how else to implement what I want to: resizing the UITableView to fit into the screen properly. Here's my implementation in viewDidAppear():
- (void)viewDidAppear:(BOOL)animated{
[self.view.superview addSubview:navigationBar];
CGRect frame = self.view.frame;
frame.size.height = self.view.frame.size.height - navigationBar.frame.size.height;
frame.origin.y = self.view.frame.origin.y + 44;
self.tableView.frame = frame;
[super viewDidAppear:animated];
}
It's very hard to see the effect when recorded on video, and probably terrible in GIF form, but here's a little GIF I recorded of the flash being induced.
Here is the result if I use that same code in viewWillAppear() instead:
Thank you!
I had this problem, turned out it was an issue with auto layout on the view. In the Interface Builder, switch to the File Inspector property view and make sure 'Use Autolayout' is unchecked.
After this, you can consistently resize your UITableView in the viewWillAppear method without the glitches.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGRect frame = [tableView frame];
frame.size.height = 365;
self.tableView.frame = frame;
}
Why using viewDidAppear, by the time this method gets called your view is visible on screen then you will of course receive a glitch.
What you have to do is change the method from viewDidAppear to viewWillAppear.
I'd like to have a gruped table where the first section has 2 row and 1 imageview like contacts app.
something like this: screeshot
How can I do that?
Thanks,
Max
The other solutions require you to create your own background images and use two tableviews which is not convenient. What I did was subclass UITableViewCell and indented the background views as such:
#define INDENT_WIDTH 84
...
- (void)layoutSubviews
{
[super layoutSubviews];
//Indent the background views.
CGRect frame = self.backgroundView.frame;
frame.origin.x = frame.origin.x + INDENT_WIDTH;
frame.size.width = frame.size.width - INDENT_WIDTH;
self.backgroundView.frame = frame;
self.selectedBackgroundView.frame = frame;
//Also indent the UIImageview that contains like a shadow image over the backgroundviews (in grouped tableview style only).
for (UIView *subview in self.subviews) {
if ([subview isKindOfClass:[UIImageView class]]) {
CGRect frame = subview.frame;
frame.origin.x = frame.origin.x + INDENT_WIDTH;
frame.size.width = frame.size.width - INDENT_WIDTH;
subview.frame = frame;
}
}
}
Since the content view has a transparent background color you can place a UIImageView (e.g on your storyboard cell prototype) on the left side and you should get the same effect as the "Add Contact" view in the Contacts App.
Please see this question:
Is it possible to adjust the width of a UITableViewCell?
It seems there's no convenient way to actually reduce the width of a cell (or cell group).
You can achieve the same in the screenshot by:
(1) A parent view controller with a view having a background color similar to that of a UITableViewStyleGrouped.
(2) Add the photo on a UIImageView which would be a subView to (1)
(3) Add the UITableView (Grouped Style) on the right side again as a subview to (1)
Set the frames of both subviews properly and accordingly for the layout in the screenshot and use delegation to "logically connect" both subviews.
Edit: The background color can be achieved using [UIColor colorWithPatternImage:(UIImage *)image]. Just crop the background from any sample app on the iphone simulator.
I've implemented Cocoa with Love's example for Multi-row selection which involves creating a custom UITableViewCell that initiates an animation in layoutSubviews to display checkboxes to the left of each row, like so:
- (void)layoutSubviews
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[super layoutSubviews];
if (((UITableView *)self.superview).isEditing)
{
CGRect contentFrame = self.contentView.frame;
contentFrame.origin.x = EDITING_HORIZONTAL_OFFSET;
self.contentView.frame = contentFrame;
}
else
{
CGRect contentFrame = self.contentView.frame;
contentFrame.origin.x = 0;
self.contentView.frame = contentFrame;
}
[UIView commitAnimations];
}
This works fine and for all intents and purposes my UITableView acts as it should. However I'm running into a small aesthetic issue: when scrolling my UITableView rows which have not previously been displayed will initiate their sliding animation, meaning the animation is staggered for certain rows as they come into view.
This is understandable, given that setAnimationBeginsFromCurrentState has been set to YES and rows further down in the UITableView have yet to have their frame position updated. To solve the issue, I attempted to use willDisplayCell to override the animation for cells which become visible while the UITableView is in edit mode. Essentially bypassing the animation and updating the rows frame immediately, so as to make it appear as if the cell has already animated into place, like so:
/*
Since we animate the editing transitions, we need to ensure that all animations are cancelled
when a cell is scheduled to appear, so that things happen instantly.
*/
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell.contentView.layer removeAllAnimations];
if(tableView.isEditing) {
CGRect contentFrame = cell.contentView.frame;
contentFrame.origin.x = EDITING_HORIZONTAL_OFFSET;
cell.contentView.frame = contentFrame;
} else {
CGRect contentFrame = cell.contentView.frame;
contentFrame.origin.x = 0;
cell.contentView.frame = contentFrame;
}
}
Unfortunately this doesn't seem to have any effect. Does anyone have any idea as to how I can solve this issue?
Not sure if you still need an answer to this question but I just ran into the exact same issue so I thought that I would share my solution. I implemented Multi-Selection the same way its described in the Cocoa with Love blog post that you mentioned.
In the cellAtIndexPath DataSource method when I create a new cell (not if the cell is already in the Queue of reusable cells) I check if the tableView is in editing mode and if it is I set a property on the cell (I created my own custom cell with an EnableAnimation property) to false so when it gets the SetEditing callback it will not animate the cell, instead it will just set the frame. In the constructor of the Cell class I set EnableAnimation to true, when the SetEditing callback is called I set EnableAnimation to the animate argument that is passed in. I hope this helps.
Basically, I want to create a button underneath a grouped table view, like contacts.app has to delete contacts.
I can create the button fine, I'm just a bit puzzled as to how to decide where to put it.
I thought I could just do:
CGRect bounds = [[self tableView] bounds];
Then place the button based on that.
However, when accessing the size.height of bounds I get zero! Is there a dynamic way to retrieve the tableView's height that I could be missing?
Any help is greatly appreciated.
Rich
You can create the size of your button like
CGRect buttonFrame = CGRectMake(0, 0, width, height);
Create the button with that frame, and then set the button as the tableView's footer
myTableView.tableFooterView = myButton;
You could try making a custom footer view with those buttons placed in that view by implementing these methods:
- (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
- (UIView *) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
That should let you put any number of buttons on your table underneath the section you want.
You can get the tablewViews heigh by looking at its frame
CGRect bounds= [[self tableView] frame];
float heigh= frame.size.height;