I have a tableView that present a list of Books, each of the table cells includes "Book name" and "Book description". The cell's height is determined by the length of the book description, so cells have different heights.
Every cell also has a background image that of course starches according to the cell's height.
I'm drawing the background image in the cell drawRect as follow:
- (void)drawRect:(CGRect)rect
{
UIImage *bgImage = [UIImage imageNamed:#"cell_BG.png"];
bgImage = [bgImage stretchableImageWithLeftCapWidth:60.0 topCapHeight:60.0];
[bgImage drawInRect:rect];
}
This code works, the problem is the scrolling performance, it's not smooth as I would like it to be.
I noticed that the main problem is the changing height, this seems to trigger a drawRect call for all cells, including the reusable cells.
(When I tried to set the same height for all cells the scrolling performance improved drastically, but I must use dynamic height...)
Is there a better approach to do this so the table scrolling will improve?
You probably don't want to override drawRect for a UITableViewCell's view since drawRect is pretty darn expensive.
Try placing a UIImageView on top of your prototype cell and setting its image (you can do so programatically or just drag in interface builder). You can then set the image view's frame size to match the dynamic height of its respective UITableViewCell. UIImageView is optimized for images so this approach should run smoother.
You can set the image and frame size of your imageView in the cellforRowAtIndexPath method in you UITableViewController.
UPDATE:
You'll probably also want to set the content mode to scale and fit your image.
From UIView class reference:
"contentMode - Provides layout behavior for the view’s content, as opposed to the frame of the view. This property also affects how the content is scaled to fit the view and whether it is cached or redrawn."
For example redraw calls drawRect anytime the view's frame changes.
It can be set programatically:
UIView* view = [[UIView alloc] initWithFrame:CGRectMake...etc];
view.contentMode = UIViewContentModeRedraw; // for example
or just by selecting the view in interface builder and setting the content mode attribute in the attributes inspector. I think your looking for UIContentModeScaleToFit or something like that. Also if using interface builder check the struts and springs of the UIImageView in the size inspector.
Related
I have created custom cell in which there are n number of image views. According to number of image views per row, i put the size of the imageview. for that, I need width of the UITableView in initWithStyle: method of the UITableViewCell. But the iPad returns the width of the UITableView as 320. My application is designed for the iPad only and I have put XIB for iPad only (I have checked the option "Targeted for iPad" or like).
Is there any way I can get the width of the tableview from the init method? I have used self.contentView.frame and self.frame but they didn't work.
Everything is correct. ;) As soon, as you init a tableRow, it's width is probably 320 by default. You have to use correct autoresizing flags for your imageView to resize automatically. Alternativly you could use the tableView delegate method willDisplayRow:atIndexPath: to customize the imageView, after the tableViewRow has been resized to its actual size.
I have a UITableView within a UIScrollView. It took me quite a lot of work to make it work.
The tableView is 640x350, I use the scroll view to scroll from one end of the cell to the next.
The scroll view is 320x350.
The scroll view's content size is 640x350
I'm running into this problem:
if I set scrollView's minimum zoom scale to 0.5, the tableview's width now fills the screen, but it's height is only half the screen. I would like the tableview to show more rows when I zoom out to 0.5.
First of all I would like to understand if this is the correct behavior, or the result of my tableView's content size and frame manipulations. The tableview has all springs and struts set in interface builder and should fill the frame available. This is my first attempt at zooming in months, and I don't remember how it works with zooming.
Can someone help me understand where and what do I need to adjust?
As far as I understand, I need to put the code into scrollViewDidZoom: that will manipulate the tableView's frame and content size.
PS. I"m returning the tableview from the viewForZooming: method of UIScrollView
What you are trying to achieve is pretty hard.
Solution 1 This solution uses the exact setup you have (UITableView inside UIScrollView).
You say that when you set the zoomScale to 0.5, you want your table view to fill the scrollView vertically. At 0.5, your table view must be 640x700 in order to fill the UIScrollView as you wish. For this to happen, on scrollViewDidZoom: you must resize the frame of the table view to 640x700
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
// No matter what the zoomScale is, the tableView will be zoomed accordingly
// Only zoom the height of the table
tableView.frame = CGRectMake(0, 0, 640, 350 / zoomScale);
// Also, update the contentSize
scrollView.contentSize = CGSizeMake(640, 350 / zoomScale);
}
If you run the code above for zoomScale = 0.5 you will get a frame size of 640x700.
This only changes the frame of the table and doesn't change the heights of the cells. This means that as you zoom out, you will also see more cells in the tableview.
Solution 2 Use only UITableView
UITableView is a subclass of UIScrollView. This means it has the ability to zoom and scroll around.
Start with a UITableView with the size that you want on the screen. Then, after the content is loaded modify the contentSize and make it wider than your frame width. This should enable horizontal scrolling.
However, UITableViewCells have their frame set automatically to the width of the tableview frame. You can bypass this by using a custom UITableViewCell, with clipsToBounds=false. Inside it you will insert a UIView with the frame set to the width&height you desire and with no autoresizingMask. When the tableview will resize UITableViewCell frame, this will not affect your inner UIView.
I've added an image to a UITableview using the following code. What I can't figure out is how to have that background image scroll with the table (not an image in each cell, but a large image behind the UITable). I need the background image to be scrollable and in synch with the UITable scrolling.
I've searched and all the examples I've seen simply add a static image.
here's the code:
[self.view setBackgroundColor:
[UIColor colorWithPatternImage:
[UIImage imageWithContentsOfFile:
[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:
#"background.png"]]]];
thanks for any help.
I had this same problem and didn't find any solutions. I rolled my own which I explain in more detail than can be easily given here. It's explained at UITableView that scrolls the background with dynamic content
The basic idea is the following:
create a second table view behind your table view that has dynamic cell heights (or heights that aren't a multiple of a background pattern image's height)
turn its .userInteractionEnabled property to NO (so it doesn't receive touch events)
have it listen to the 'front' table view's contentOffset property via KVO so that the background table view sets its contentOffset to the same value.
have this background table view be its own delegate (you have to make a subclass so to implement KVO listening handlers anyway), and it populates empty cells' contentView.backgroundColor = [UIColor colorWithPatternImage: ...]
make sure your 'front' table view cells have transparent backgrounds. i.e. backgroundView set to an imageView without an image and opaque set to NO, and backgroundColor set to clearColor.
worked for me quite fine, and didn't seem in any way slower. The tables were still quite snappy on an iPod 4G
Because few days ago I saw that -
http://www.appuicomponents.com/component/sbtv
I am guessing the answer is not trivial. But maybe you would like to try that ?
Any way, if you are using a pattern image, isn't that possible to add the pattern to the cells them selfs ?
I am trying to change frame sizes of an imageView. textLabel and detailTextLabel of UITableViewCell property on inside the UITableView. I tried with change the frame size, resizing mask, resizing subviews and so on, but there is no use. Is there any way to change default frame size? and I am using UITableViewCellStyleSubtitle.
Note: My images took their own image size.
I think is possible with a UITableViewDelegate method:
– tableView:willDisplayCell:forRowAtIndexPath:
you can set frame sizes, position, etc. Basically any layout should have effect there.
or you can subclass UITableViewCell and override layoutSubviews: method (don't forget to call [super layoutSubviews]; first)
Actually I am doing the second approach and works excelent.
Hope this helps ;)
In my opinion, the right way is to redesigned the cell.
2 possibilities:
Programmatically in tableView:cellForRowAtIndexPath: (see iOS guide)
with a custom UITableCellView (see iOS guide)
And for the cell height: tableView:heightForRowAtIndexPath: of the delegate
I am trying to scroll the content without scrolling the image in the background using UIScrollView.
I am using IB and setting the FileOwner View to point to the Scroll View (Image View is a child of the Scroll view). I have made the image height to be 960 pixels.
I have also set scrolling content size in the vierController that owns this UIView
(void)viewDidLoad {
UIScrollView *tempScrollView = (UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(320, 960);
}
My problem is that the Image only appears moves along with the content.
I have tried taking out the settings in viewDidLoad, but the scrolling cease to function.
I have also tried changing the location of the image and have it placed under VIEW instead of Scoll View (by the way Scroll View is a child of VIEW), but that resulted in the app breaking (termination error).
Any advice would be appreciated.
The easiest (and correct way) is to set an background image to your UIScrollView
UIImage *img = [UIImage imageNamed:#"image.png"];
[scrollView setBackgroundColor:[UIColor colorWithPatternImage:img]];
The easiest way is to set an UIImageView behind your UIScrollView(UIImageView and UIScrollView under UIView) and make your UIScrollView background color as clear color as mentioned by Janson. By this way you can scroll the content without scrolling the image in the background using UIScrollView.
Thanks. This was extremely helpful.
The one thing that I would add (pardon if it is obvious, but for people new to the platform (i.e., me), it took a bit of playing around).
I put the code from "unset"'s example after where I setup the contentSize=CGSizeMake in the viewDidLoad of the UIViewController , i.e.,:
// Setup the Scroll View
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(320, 720);
// Set Stationary Background, so that while the user scroll the background is
// fixed.
UIImage *img = [UIImage imageNamed:#"bg-body.jpg"];
[tempScrollView setBackgroundColor:[UIColor colorWithPatternImage:img]];
Then, I went into the ViewController .xib file and on the UIView that is inside of the UIScrollView, I set the background color to "Clear Color".
I sure that there is a way to do this through code at the same time as setting the background of the UIScrollView, but at least that is how you can do it through IB.
Jason