Background image that's scrollable and in synch with the UITable scrolling - iphone

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 ?

Related

UITableViewCell with background image and dynamic height

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.

How to set UITextView's content inset like Notes App

I am working in an app in which I need to give feature like Notes App in iphone. as shown in first screen shot , initially , notes leaves a tab before the content starts, I also wanted to do the same and for that when I set Left Content inset (of UITextView) by 25 , it shows like in screenshot 2, here you may see the image also gets shifted. I have set image as background. I don't know how to solve this problem.
I also tried by adding image as subview of UITextview but it won't repeat the lines, while scrolling (image of lines) like notes app.
I'm setting the background of Textview by following code.
[textView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"line_image.png"]]];
Please tell me if I am going wrong or any extra effort needed to get desired output.
Thanks
UITextView is UIScrollView subclass so all relevant delegate method are available for you (e.g. scrollViewDidScroll:) - you can adjust your custom background in that method.
There's very nice post on Dr.Touch blog about recreating Notes app interface - you can get general idea about how it is done from it. Basically what is done there is adding custom view that draws background behind the text view and adjust it in text view's delegate methods and also using KVO on its 'contentSize' property.
#Dinesh gave nice solution but it doesn't sound to be generic as I want to use image of lines instead of drawing them. Image has some special effects that can not be achieved by drawing. So to solve it I created a table view below the textview keeping textview's background transparent. Now just added the image of line to my tableview's custom cell and set content offset of UItableview same as of the scrollview (subview of text view ,refering to the answer of #Vladimir ) .
And used the following code to scroll my tableview with scrolling the textview and got the desired output.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
tableView.contentOffset =scrollView.contentOffset;
}
Keeping my tableview's number of rows at a very large number.
PS: instead of setting the content inset of textview, i set its frame's X position and decreased the width relaively.

UIImageView in my UITableViewCell changes size on click

I have a fairly vanilla UITableView in my app used to display an image and text in the default/standard way. The first time a UITableViewCell is requested I return it with a placeholder image and start an asynchronous download of the real image. When the download is complete I replace the placeholder image.
If a download fails, the placeholder image remains. Clicking on such a row acts normally. If the download is successful, clicking on a row with the intended image leads to the UIImageView expanding to the height of the row (and the width increases at scale). The UIImageView never returns to normal size. Crude attempts to set the frame of the UIImageView do not alleviate the issue of mysterious resizing.
// from my - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; method
// after boilerplate cell dequeuing code
cell.textLabel.text = [selectedNoun title];
// add placeholder image
UIImage *placeholderImage = [UIImage imageNamed:#"placeholder.png"];
cell.imageView.image = placeholderImage;
[cell.imageView setContentMode:UIViewContentModeScaleAspectFit];
//...
// If the image has been downloaded I set it
cell.imageView.image = iconDownloader.image;
This is driving me nuts. It actually only happens in one of two tables in my app, but after comparing them line or line I can't see any difference. Hoping that someone has come across this before.
Thanks!
EDIT: I don't have a good explanation for my solution other than to say that images over a certain size appear to lead to this behavior and the use of actual thumbnails (even images somewhat bigger than the UIImageView's frame) do not exhibit this behavior.
If you have custom UITableViewCell then make sure that your UIImageView is not named with "imageView"
The only things that come to mind that effect the size & appearance of a view within its superview are:
Are you changing the frame/bounds/center properties anywhere? Where/how is the frame set initially?
imageView.autoResizingMask should be set to UIViewAutoResizingNone
imageView.clipsToBounds should be set to YES
EDIT: more suggestions
I'm shooting in the dark b/c your posted code looks fine and if you've set imageView.clipsToBounds that should constrain the drawn image to the imageView frame. Here are a couple more things to try:
Implement tableView:willDisplayCell:forRowAtIndexPath: and set the imageView properties there. If imageView.frame is the problem, this likely won't fix it.
Add your own UIImageView to the cell configured how you want it and don't use the built in imageView property. If the behavior of the default cell is causing the problem this should work.
EDIT: large image problems
I don't know exactly how big the "really big images" are that you are currently using but they are likely the issue. From the UIImage docs (emphasis is mine):
You should avoid creating UIImage objects that are greater than 1024 x
1024 in size. Besides the large amount of memory such an image would
consume, you may run into problems when using the image as a texture
in OpenGL ES or when drawing the image to a view or layer. This size
restriction does not apply if you are performing code-based
manipulations, such as resizing an image larger than 1024 x 1024
pixels by drawing it to a bitmap-backed graphics context. In fact, you
may need to resize an image in this manner (or break it into several
smaller images) in order to draw it to one of your views.
This answer helped me. But I had to make sure to call [cell layoutSubviews] in the method that actually does the setting, like this:
cell.imageView.image = image;
[cell layoutSubviews];
Hope this can be of use to you!
My issue was slightly different, I had a custom UITableViewCell with own UIImageView and when cell disappeared and reappeared, the image would be incorrect size. My problem was that I was setting cell.imageView in one place and cell.thumbnail (custom image) in another, so I changed all references to cell.thumbnail.
Hopefully it helps someone in the future with similar issue.
In these situations I use this Image loader framework. It includes a method to set a placeholder image of your choosing, while downloading images in the background, and as an added benefit it caches images guaranteeing the same image won't ever have to be downloaded twice. Its a great piece of work that I've found very useful for tableview image loading.
SDWebImage:
https://github.com/rs/SDWebImage
I had the same problem, and I didn't figure out the reason for that. Anyway, it's something related to the placeholder image: if you load an image of the same size that the placeholder, no resize will be performed, but if the sizes don't match, the loaded image will be resized to the placeholder dimensions, and resized again when clicked.
So, if you want to avoid the problem, use a placeholder that matches the row height.
follow these steps:
Select the ImageView on your custom cell
go to Show to Identity Inspector
Scroll all the way to the end and uncheck the "User Interaction Enabled" checkbox.
This is pretty unlikely, but you should try to look into what happens to the frames of the UITableViewCell's subviews when its isSelected property switches from NO to YES (I.e. what happens when you tap a cell). I doubt that will help much, but it's worth looking into (if you can find anything...that's all under the hood of UITableViewCell I would imagine).
You should also look into the imageview's clipsToBounds property. Maybe that has something to do with it?
doing something like
CGRect bounds = [self bounds];
[self setImage:image];
[self setBounds:bounds];
when setting image fixes the problem for me
If you reload the tableview when it finish loading, the image get the size that it was suppose to have
[self.tableview reloadData];
I fix the problem with:
cell.selectionStyle = .none
In my case, I faced this issue in iOS 12 however iOS 13 works fine.
I changed UIImageView to UIButton and set background image as like below which fixes my issue.
cell.imageButton.setBackgroundImage(UIImage(named: "name_of_the_image", for: UIControl.State.normal)
I know this is way too late to post but someone might find it helpful.

Stretchable and Pattern UIImage at the same time

I would like to code a shelf and I don't want to think about resizing and changing background images on a rotation and depending on the screensize (iPad/iPhone). Is it possible to create an image, that would stretch horizontally but repeat vertically?
By now, I've only found the [UIColor colorWithPatternImage:] and [UIImage strechableImageWithLeftCapWidth:topCapHeight:] or the new [UIImage resizableImageWithCapInsets:]. But I didn't manage to let them work together, obviously.
I hope the illustration helps understanding my issue:
Do you have any idea how to accomplish the above, so that it will work with a single image for different sizes and orientations? Thanks!
I also needed to set UIView background from image and change its size at the same time. What I did was:
Created image within frame of my view size
Set view background using [UIColor colorWithPatternImage:(UIImage*)]
And here is the code :
UIGraphicsBeginImageContext(self.followView.frame.size);
[[UIImage imageNamed:#"background_content.png"] drawInRect:self.followView.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIColor *bgColor = [UIColor colorWithPatternImage:image];
[followView setBackgroundColor:bgColor];
[UIColor colorWithPatternImage:] can take up an extreme amount of memory when working with a large number of rows. I ended up creating a single image view that was one row larger than the entire view using [UIColor colorWithPatternImage:], then offset that view up or down a row as necessary when the view was about to scroll offscreen. Since the view is only moved at row boundaries, the performance was much better than I expected.
However, a better option would be to create a pool of individual UImageViews using [UIColor colorWithPatternImage:] and tile them, similar to what UITableView does will table view cells.
Apple has sample code which illustrates this technique in the ScrollView Suite sample project and the Designing Apps with Scroll Views video from WWDC 2010.
Why not use a stretchable image of one shelf and then set it as the background for every cell on the tableview?
EDIT:
My knowledge of AQGridView is limited but sounds like you could get access to each individual 'grid tile'.
Try having three images per row:
- The image for the left most grid tile to show the left corner of your shelf
- The image for the center part of the shelf that is applied to all tiles except for the first and the last tile
- The image for the right most grid tile to show the right corner of your shelf.
Also, you should probably mention you're using AQGridView in your question so that other users won't think you're using a UITableView.

How do I draw to the contentView of a UITableViewCell?

I'm trying to draw a line on a custom UITableViewCell. When I draw inside the overridden drawRect and use the current graphics context I don't see anything.
I know I can't see anything because the draw rect is drawing to the UIView and not the contentView. So my question is, how do I draw to the content view using CG? Say, grabbing the graphics context to the contentView?
I have played with this in the past and what i have ended up doing is creating my own subclass of UIView and adding iot to a custom subclass of UITableViewCell and drawing to it that way. I like the control that this gives me.
For some reason (I don't know why, but I did notice this) if you "custom-draw" (ie, redefine drawRect) on what's in the 'contentView' of your cell, it does not show up on the table cell. However, the view that you assign to cell.backgroundView and cell.selectedBackgroundView show up perfectly well...
You could put your custom view in cell.backgroundView, put nothing in cell.contentView and it will show up fine (except for when you select the row, because then your view disappears and is replaced by cell.selectedBackgroundView).
So, what you can do is:
Use cell.contentView to show a custom view without any background
Use cell.backgroundView and cell.selectedBackgroundView to show a fancy background for your cell...
Or:
Make your custom view flexible enough so that it can show both the selected and non-selected state, and use 2 instances of your custom view: one in cell.backgroundView and one in cell.selectedBackgroundView
I found my answer here. Basically the super class ABTabeViewCell sets up the context so you can easily draw in the drawContentView function.