Custom UITableViewCell subview layout - iphone

I'm creating a custom UITableViewCell, similar in style to UITableViewCellStyleValue1 but with an editable text field on the right side instead of the detailTextLabel. I'm a little confused on how to size the edit field properly. I want to take the length of the textLabel into account, as well as the size of the contentView, and be able to do the Right Thing when its table view is in edit mode, or if an accessory view (like a disclosure arrow) is added.
But the width of the contentView seems to always be 320 (on iPhone in portrait mode) even for a grouped table. Within my UITableViewCell subclass, I see no way to get access to the table view to which it belongs so I can get the style of the table and adjust the margins accordingly.
I figure I can handle this in a custom fashion in the tableView's delegate -tableView:willDisplayCell:forRowAtIndexPath: method, but that completely defeats the purpose of having a reusable cell class.
I must be missing some key concept here, but I'm at a loss. Anyone?
Thanks!
randy

You may want to take control of your layout in your UITableViewCell subclass. For example:
- (void)layoutSubviews
{
CGRect b = [self bounds];
b.size.width += 30; // allow extra width to slide for editing
b.origin.x -= (self.editing) ? 0 : 30; // start 30px left unless editing
[contentView setFrame:b];
// then calculate (NSString sizeWithFont) and addSubView, the textField as appropriate...
//
[super layoutSubviews];
}

I think the margins are part of the cell, not the table, so that's why the contentView is always 320 wide. Maybe I don't understand the question.

Related

UITableView contentInset makes table view scroll horizontally in addition to vertically

I'm creating a UITableViewController in code and pushing it on top of the navigation stack.
It's table view is intended to just show a simple list of text items.
I need to add some contentInset to my table view which I add in the init method of my UITableViewController
self.tableView.contentInset = UIEdgeInsetsMake(7.0f, 5.0f, 7.0f, 5.0f);
However, when I load the table view it seems the left and right contentInset have actually stretched the width of my table view by 10. I'm now seeing a small horizontal scrollable area. I don't want any sort of horizontal scrolling on my table view. If I remove the contentInset code, my table view behaves plainly i.e. simply provides for vertical scrolling. How I can keep just like that but with my contentInset in place? I tried reducing my contentSize.width by 10 in viewWillAppear, it had no effect.
This seems to be a duplicate but with no acceptable answer: UITableView ContentInsets scrolling content horizontally
In the mock I have marked the desired contentInset with dashed line ---
Thanks.
I ended up setting just the top and bottom insets. To achieve the left and right inset look and feel, I created custom cell as wide as the screen. But the actual cell content was restricted to a slightly narrower subview within the custom cell. Thus, there was space leftover on the left and right of the subview.
Looks like you need to do 2 things:
Add the table view to a container view and make the table view frame thinner (to add the left and right borders).
Add thecontentInset only for the top and bottom.
Maybe you should set the bounces property of the scrollView to YES.
And do not set the contentInset.
Another way that could work, is that, instead of setting the tableView frame, you can set the frame for cell's contentView , something like this,
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect frame = self.contentView.frame;
frame.size.width = frame.size.width * 0.9; //90% of total width
frame.origin.x = self.center.x - (frame.size.width/2); //center the contentView
self.contentView.frame = frame;
}
The using the above, u can add any left or right or left padding u need for the cell. and all the subViews will be added to the contentView , hence no problems there.
happy coding..!

Cannot change height of UITableView

In the Apple iPhone Clock App, when a user adds a new alarm a modal view pops up. I am trying to create a UI similar to that.
I currently have a UITableViewController as the root view controller of a UINavigationController.
I also have a UIDatePicker added as a subview to the UINavigationController:
[self.navigationController.view addSubview:mydatePicker];
However, I have about 10+ rows in my UITableview (that of the UITableViewController) and as soon as I added the UIDatePicker I cannot scroll to view all the cells.
I realized that the UITableView size is the same size as it was before I added the UIDatePicker, and therefore I would need to change its size in order to be able to scroll to see all the table cells.
I have tried several things in order to change its size, all to no avail. In the code below I arbitrarily chose 50 for the new height.
First, tried changing the bounds height:
CGRect bounds = [self.tableView bounds];
[self.tableView setBounds:CGRectMake(bounds.origin.x,
bounds.origin.y,
bounds.size.width,
50)];
Then tried to change the frame height:
CGRect tvframe = [self.tableView frame];
[self.tableView setFrame:CGRectMake(tvframe.origin.x,
tvframe.origin.y,
tvframe.size.width,
50)];
Then after googling some more i tried changing the contentSize height:
CGSize thesize = self.tableView.contentSize;
thesize.height = 50;
self.tableView.contentSize = thesize;
None of these appeared to have any effect on the size of the UITableView. I still could not scroll to see all the cells.
I later tried some of the same methods as above but on the UINavigationController instead of the UITableView. I didn't have much luck with this either.
As a last resort, I tried to change the size of the UITableView in the Storyboard editor. I could not figure this out either.
Thanks for any help you can provide.
From the UITableViewController class reference, it:
creates an unconfigured UITableView object with the correct dimensions
and autoresize mask
And a quote from the Table View Programming Guide for iOS which specifically addresses this behavior:
Note: You should use a UIViewController subclass rather than a
subclass of UITableViewController to manage a table view if the view
to be managed is composed of multiple subviews, only one of which is a
table view. The default behavior of the UITableViewController class is
to make the table view fill the screen between the navigation bar and
the tab bar (if either are present).
If you don't want the table view controller setting the size of your tableView, then you need to use a UIViewController instead. See the link that I posted above to the Table View Programming Guide for iOS for other things to consider when going this route.
I had same problem as you mentioned.
I was unable to change the height of tableView of UITableViewController. I tried changing frame and centers of self.view and self.tableview. But failed.
Then I solved it by a trick, changing tableview's contentInset.
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 44.0f, 0); // here you can replace 44.0f with your height
You need to make the UITableView a subview of your main view in order to change its size reliably.
The frame is the correct value to alter once you have made this change.
I dont know what is your real Problem . but for change hight of your UITableView and will Display all rows in UITableView write following code.
self.tblView.frame = CGRectMake(0, 0, 320, 50);
please try it.
Your are taking uitableview controller, in place of that use uiviewcontroller in that add the uitabelview. Now you can the the size of uitableview.

Can i make a table's tableHeaderView position fixed as I scroll?

I have a table view and have attached to its tableHeaderView a UISegmentedControl. How can I make the tableHeaderView fixed so that i can always view the UISegmentedControl in the same position even when i am scrolling the table view?
tableView:ViewForHeaderInSection: is your option to achieve your task. In plain table this will somehow looks like Address Book app with first char of name in section, but you will have your segmented control
I would suggest placing the UISegmentedControl in a separate view on top of the UITableView rather than in the tableHeaderView. You might also want to set yourTable.bounces = NO; in order to keep the header view from bouncing when you get to the top of the table.
First lower the tableview's frame(make space on top of tableview). Then during scrollViewDidscroll, fix the tableviewheader, properly, so it doesn't scroll with it.
Thats the summary of it.
To expand on #mskw's answer:
You can use the UITableViewController (keep the niceties such as UIRefreshControl support and keyboard avoidance). You just have to embed your toolbar in a plain view and place that in your tableHeaderView. Then implement this scroll view delegate method to lock.
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect rect = self.toolbarContainerView.frame;
rect.origin.y = MIN(0,scrollView.contentOffset.y + scrollView.contentInset.top);
self.toolbarContainerView.frame = rect;
}
Note that if you also use section headers you will have to send those views behind your tableHeaderView otherwise they will float over the tableHeaderView.

iOS: how to change the size of the UIScrollView content?

I'm now trying to create my own Text panel (with code highlighting and so on).
In fact everything is ready except one thing - scrolling
What I've done:
created UIScrollView and inserted my own view as a subview using Interface builder.
in ViewController viewDidLoad method I've pointed initial textfield size to be the UIScrollView content size.
And when user writes too much into my text field. I call delegate (which is ViewController) to change size.
To do that I simply write
[scrollView setContentSize:newSize];
And what I get is increasing of the scroll view but not my text field - just blank lines appears. I think I need to set my view's size too but I can't figure out how...
And a second part of my question:
Every time I call [textField setNeedsDisplay] it calls drawRect: method with rectangle which is equal to the whole size of my view (which is much bigger than it's visible part). What will it look like if I try to use my view to modify file which size is more than 3 mb? How can I force it to redraw only visible part?
Thanks for your attention.
Part 1:
The scroll view's content size is not actually related to the size or position of the views it contains. If you want to change the size of the content view as well as the scroll view's content, you need to call two different methods.
CGSize newSize;
UIScrollView *scrollView;
// assume self is the content view
CGRect newFrame = (CGRect){CGPointZero,newSize}; // Assuming you want to start at the top-left corner of the scroll view. Change CGPointZero as appropriate
[scrollView setContentSize:newSize]; // Change scroll view's content size
[self setFrame:newFrame]; // Change views actual size
Part 2:
setNeedsDisplay marks the entire view as needing display. To cause it to display only the visible part, you need to use setNeedsDisplayInRect:visibleRect.
Assuming the view is at the top-left corner (its frame's origin is 0) and the scroll view does not allow zooming, the visible rect can be found using the scroll view's content offset and bounds size.
CGRect visibleRect;
visibleRect.origin = [scrollView contentOffset];
visibleRect.size = [scrollView bounds].size;
[self setNeedsDisplayInRect:visibleRect];
You could also choose to draw a part of the visible rect if only part changes.
It's simpler than you think, for example you have an UITextView called "textDesc" inside your UIScrollView, and you want to know the size of content, so next step will looks like that:
int contentHeight = textDesc.frame.size.height + textDesc.frame.origin.y;
After calculating the size of textDesc, just set it:
[scrollView setContentSize:(CGSizeMake(320, contentHeight))];
That's all, now your scrollView know the size of your text inside him, and will resize automatically, hope this helps, good luck.
Set your text field autoresizingMask property to flexible height and width:
[textField setAutoResizingMask:UIViewAutoResizingFlexibleHeight | UIViewAutoResizingFlexibleWidth];
This should expand the view automatically when you change it's parent's size (the scrollView's contentSize)
Otherwise try:
[textField setFrame:CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height)];
just after you change the scroll view's contentsize.

UIButton in a UITableView header ignores most touches

I've got a button that I'm adding as a subview of a table view's tableHeaderView. The button appears fine, and tap-and-holding on it works intermittently - for the most part, though, it's unresponsive. I've tried adding it as a subview of the table itself; the effect is about the same. I thought the problem might be with the scroll view's touch interception, but disabling scrolling on the table has no effect either.
Am I doing something wrong? Has anyone else encountered this?
edit - to clarify, I'm talking about the main table header, not a section header, in a grouped-style table; think basically modeled after the "Contact" screen.
I had the same problem. In my case I had a container view instantiated in IB (that was applied as the table view header in code), with a UIImageView occupying the entire frame of that container. The misbehaving button resided in the image view.
Turns out I needed to have sizing struts in IB set as follows...
Container View: exterior anchors all on, interior resizing - all off
Sub Image View: all struts on (interior and exterior)
I had several different table views, all using header views. Some would respond to touch events correctly, some were flaky. This solved my problem
I had a similar problem - a textfield and button inside a view set as the table header view which would not respond to touch events. setAutoResizing programmatically worked for me.
My controller extends UITableViewController, and viewDidLoad looks like this:
- (void)viewDidLoad
{
[super viewDidLoad];
MYCustomWidget *headerView = [[[NSBundle mainBundle]
loadNibNamed:#"MYCustomWidgetView" owner:self options:nil]
objectAtIndex:0];
[headerView setAutoresizingMask:UIViewAutoresizingNone];
self.tableView.tableHeaderView = headerView;
}
('MYCustomWidget' extends UIView, and 'MYCustomWidgetView' is a XIB file).
I completely disagree with Wisequark -- there's absolutely nothing wrong with putting a button in the tableHeaderView, and including one would not risk your app being rejected from the app store. The tableHeaderView is designed to be an arbitrary view containing whatever elements you choose.
As far as your issue, it could be that you've got a view obscuring your button, or, it may simply be a bug that should be reported to Apple.
Strangely enough, but the table header view is apparently resized incorrectly.
I use auto layout, so autoresizing mask was not an option for me. After inspecting my view hierarchy:
and noticed that my custom header view had incorrect height, so only less then half of it was tappable (see highlighted view):
Manual updating of its height fixed the problem:
- (void)viewDidLayoutSubviews {
CGRect frame = self.tableView.tableHeaderView.frame;
frame.size.height = 116.0;
self.tableView.tableHeaderView.frame = frame;
}
Also, the table view header height can become invalid after the orientation is changed. This problem also can be fixed with the provided solution.
My situation was similar to Danny Hall's (the table header view was a UIImageView, and there was a UIButton which was a subview of the UIImageView). In my case, the problem appears to have been caused by the button being a subview of the image view. What worked for me was creating a UIView "containing" view, such that both the image view as well as the button were subviews of the "containing" view. strange.
tableHeaderView has 0 height while it is processing draw in UITableView
use this UIView subclass to set the strong constant height and ignore UITableView processing
#import <UIKit/UIKit.h>
#interface CustomHeaderCell : UIView
#end
//-----
#import "CustomHeaderCell.h"
#implementation CustomHeaderCell
-(void)setFrame:(CGRect)frame {
frame.size.height = 43; // !!! constant height
[super setFrame:frame];
}
#end
I have the same problem UIButtons actions not working in UITableView's header view. First i tried setAutoresizingMask to .None which not works then after reading the answers of #Davyd and #Alexey i realise that i did not set the height of headers view then i set it like:-
self.tablevwMain.tableHeaderView?.frame = CGRect(x: 0, y: 0, width: width_view, height: your_height)
And all UIButton'sinside UITableView's header view works correctly.
For me UIControl like UIButtons on headers only worked if I add it to the cell's contentView
addSubview(stackView) //Does not work
contentView.addSubview(stackView) //Works
Don't forget to set the footer height in:
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
You should consider that this is not the intended sue of the headerView and that an implementation such as that might result in rejection from the AppStore as a result of a HIG violation. Given that the dimensions of a header are intended to be small, it is probably better to consider a restructuring of your view. Having said that, there is no easy way to do it short of hand detecting touch events and determining the geometry yourself, then executing a selector based on the geometry - in short, rolling your own button class.