UITableViewCell's contentView's width with a given accessory type - iphone

On an iPhone, how do you figure out the width of a table view cell's content view when it is showing a certain accessory view (disclosure indicator, etc)?
I need this in order to calculate the correct cell height for cells that contain wrapping, variable-length text. But when the table view delegate is asked for a cell height, it doesn't actually have the actual cell instance, so it can't just query the content view bounds directly.
I can easily hard-code a 20-pixel margin on the right which appears to be accurate for a plain style table view in portrait orientation with a disclosure indicator, but would prefer to do it the Right Way so that it keeps working if Apple decides to tweak the margin.
(This is related to this question.)

Personally, I would just hard code the values -- simpler and things will break in a predictable way.
But were I to do this programmatically, I would create a UITableViewCell, set up the editing properties / accessory views you need to measure, and then ask it how big its contentView is.
Of course I would probably heavily cache this -- doing allocations when asking UITableView asks you for height information sounds to me like it would be slow (check with a profiler first though, as always).

I would have a subclass of UITableViewCell that holds all its subelements. You can cange the frame of certain elements when the cell enters and exists editing mode. There is a good example of this in Apple's Table View Programming guide under the section on creating a custom table view cell.

I believe the UITableViewCell's contentView property is the view that contains your labels etc., so the width of that should be your available size to use.

Related

Drawing really long text on iPhone

Currently I have UITableViewCell's that hold sometimes really long text (up to 50,000 pixels in height after drawing). However the UITableView delegate documentation says that cells shouldn't be higher than 2009 pixels in height (any ideas why?).
It's only the first section in my table view that has the really long cell, so instead of using a cell for the first section, I thought I'd create a UIScrollView, put a UITextView as the first "cell" and add it to the scrollView, and then add the tableView to the scroll view as well (under the textView). However, having a 50,000 px high UITextView is causing huge memory problems.
What are my options? I know I could use a UITextView that scrolls, but to have a scrollable UITextView with a tableView just causes complicated scrolling behavior. I want to mimic the scrolling of a tableView.
I didn't know it would be an issue to have a 50,000 px high view in a UIScrollView. I thought that's what UIScrollView's are for? Do I have any alternatives?
I would seriously question the UI design where you must render text that large as part of a table cell. The best option would be to put a reasonably-sized summary in a cell with cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;, build a separate view for the long text, and let the user navigate to that view by clicking the disclosure indicator.
As a side note, you could also put a scroll view inside the initial table cell (not all cells must be of the same type; you can make one with a scroll view in it, and use it for the cell at index zero). It's not going to be as usable as the regular cell with a disclosure indicator, though.

Automatically reposition views after UITextview resizes - iOS

For a simple example lets say I have a UITextView with a Button underneath it. These two controls are siblings both embedded in a parent UIView.
I now change the text within the UITextView and resize it accordingly. Is there a way to make the button automatically move to have the same relative distance to the bottom of the UITextView? This may seem trivial for this case, but I will have a longer hierarchy with multiple UITextViews that change and it would be nice not to have to calculate the height of every object manually.
One way to approach this would be with a table view: if you place each of your text views within its own table view cell, the table view will automatically calculate its total height from individual calls to its delegate’s -tableView:heightForRowAtIndexPath: method and lay itself out accordingly. Whenever the height of one of your text views needs to change, you can call -reloadData on the table view to make it lay itself out again. A disadvantage of this approach is that it’s really difficult to animate the height changes; if that’s essential to the effect you’re going for, I’m afraid you’re stuck with doing the entire layout manually.
Try the autoresizingMask property of UIView.

Adding a dynamic-height UITableView into a scrolling view?

Hello all – I'm getting into iPhone development and have hit my first confusing UI point. Here's the situation:
My app is tab-based, and the view that I'm confused about has a static featured content image at the top, then a dynamic list below into which X headlines are loaded. My goal is to have the height of the headline table grow as elements are added to it, and then to have the whole view scroll (both featured image on top and headline list below). So, I guess my question comes in two parts:
1) First, how do you set up a dynamic-height table view that will grow as cells are added to it. So far I've only been able to have my tables handle their own scrolling.
2) Then, what is the root NIB view that the featured image and the table should live in to enabled scrolling? I've dropped oversized content into a UIScrollView now, although did seem to have any success with having it automatically scroll.
Thanks in advance for any help on this subject!
To the first:
As i understand your situation:
You want to add a image to the top of the UITableView and the image should scroll with the UITableView, shouldn't?
The UITabeView has a property called tableHeaderView. It's just a view, so you can set a UIImageView to it.
(I have no xCode at the current time, you need to edit the code)
UIImage *image = [UIImage imageNamed:#"myCoolPic.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame =CGRectMake(0,0,width,height);
tableView.tableHeaderView = imageView;
[imageView release];
What you're asking is probably doable with Interface Builder (or not, I don't know) but I know the code way to do it.
To change the height of the table all you do is set the frame of the UITableView object. The default height of a UITableViewCell is 44 I believe, so set it to multiples of that depending on how many cells you have. Of course your cells can be any height so you will need to keep track of what you report in heightForRowAtIndexPath and set the table frame accordingly.
UITableView will certainly live in a UIScrollView and both components can scroll. The table view needs to become a subview of the scroll view, so does the image. Then you will scroll the table if you drag on it directly or scroll the scroll view if you drag the image or the scroll view.
For the first question, I'm a little confused by the way you ask it: "how do you set up a dynamic-height table view that will grow as cells are added to it." Table views have a function that it calls before the table is fully loaded with data called "numberOfRowsInSection." So the number of cells is based on that function, and should you update the variable used to determine the return value of that function (usually [myArray count]) it should automatically find the right size for the whole table.
However, variable height cells are something that I found kinda tricky and I've solved it using the following:
There are some UIKit NSString additions that you might find useful.
http://developer.apple.com/iphone/library/documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html
Particularly the sizeWithFont: functions.
Table views also have a 'heightForRowAtIndexPath:' function that is called 'numberOfRowsInSection' amount of times. Each call determines the height of the cell at the indexpath.
So, for example: (assuming myArray is an array of NSStrings)
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [[myArray objectAtIndex:indexPath.row] sizeWithFont:myFont];}
This will return a height based off of your actual data, piece by piece. There are other functions to specify how the text wraps and truncates, etc. as well.
It doesn't feel like a great solution because you end up fetching your data twice, once to determine the height, and then again when you configure the cell in 'cellForRowAtIndexPath:' However, it does work!
I've learned a lot in the past few weeks and have gone through a few iterations of addressing this problem. My first solution was to manually measure the table height, then set the table rect to display at that height, and finally to set the scrollView's content rect to encompass the the table and top feature. What that solution did basically work, I started encountering some display issues when branching out into new views with different toolbar configurations. It seemed that my manual frame size was interfering with iPhone's native content scaling.
So, I scrapped the manual sizing and went to just making that top feature block be a custom table cell that displayed within its own section at the top of the table. I made a hard logic definition that section 0 only had one table cell, and that cell was my custom layout that I linked in through Interface Builder. I was then able to get rid of ALL my messy custom scaling logic, and the whole system is cleaner, smoother, and works reliably.

Content of custom table view cells not drawing correctly

I have several parts in my app where I use custom table view cells.
Their content is created with subviews.
The problem is that on some of these cells, the content does not appear at all or does not appear correctly until after the cell was selected for the first time.
One example is a custom cell which has a custom subview which can be set after its creation. This view does not appear at all before I selected the cell and its views were redrawn. Calling -[setNeedsDisplay] in the subview's setter method does not help either.
The problems was that I was using the cells themselves to calculate their height. For some reason, the subviews (which were part of the cell used to calculate the height) weren't appearing correctly in the cells that were used for the actual displaying.
Therefore my advice: Never use a UITableViewCell to calculate its own height. This may work in principle (it doesn't crash), but might bite you later in unexptected and hard-to-debug ways.

Is it possible to resize a UITableViewCell without using UITableViewDelegate?

I want to resize my table view cells from inside the cell instead of from the UITableViewDelegate. I am resizing them based on asynchronous content, so I can't size them in the delegate.
I tried setting self.frame inside the cell, but the table view was really unhappy about that. Cells were overlapping and all kinds of craziness was going on.
You simply have to use the table view to control height. You can tell the table a cell has altered by using the calls to remove and then re-add specific cells, so you don't have to reload the whole table - but the height has to be fetched using the delegate callback tableView:heightForRow:atIndexPath:
I don't see why this is not practical though. You can have any number of asynch systems running that update a central height cache held by the table view delegate - every time you create a cell you can assign it the delegate as a reference so it has a way to talk back to the table and let it know cells need reloading and what the new heights are.
If you think about it, the poor table view is a scroll view that has to manage all these separate cells and keep them together visually - so it's really unkind of a cell to go rogue and start altering frames without letting the table view know what is going on anyway. It's best to let the table drive and tell it what to do.
No you can not set the cell's size without using the UITableViewDelegate. Changing the size of the cell with actually change the size of the cell, but it will not change the offsets that the UITableView draws the cells with. Which will result in overlaps, and gaps all over the place.
Your friend is tableView:heightForRowAtIndexPath:, and it should be fast. If you override it, then the table view can no longer make the assumption that all rows are of the same height. And thus it must query all rows for their height each time it fetches cells to draw.
You should try to manage the cells contentView propertys frame, instead of the cells frame itself
heres a reference http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UITableViewCell_Class/Reference/Reference.html#//apple_ref/occ/instp/UITableViewCell/contentView