Is there any way to set a background view on a UITableViewController?
I try with the code I am using on a UIViewController, but the view comes over all the contents of the table view. If I add the background view in the cellForRowAtIndexPath-method, it is not showing at all. Has anyone done this before or have an idea on how it can be done?
Here is the code I am using:
UIImage *image = [UIImage imageNamed: #"background.jpg"];
UIImageView *backImage = [[UIImageView alloc] initWithImage: image];
[self.view addSubview: backImage];
[self.view sendSubviewToBack: backImage];
I know it's been a long time, but just for the record..
I Think I found a better solution using UITableView.backgroundView:
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"lisbon.png"]];
self.tableView.backgroundView = imageView;
[imageView release];
I tried with an image size of 320x480 on iPhone, and works perfect (I have tried with .jpg also).
(This is basically the same as Hans Espen's solution above, but uses convenience methods for brevity)
Put this in your -[UITableViewControllerSubclass viewDidLoad] method:
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"BackgroundPattern.png"]];
There's no point in avoiding a couple of autoreleases in a viewDidLoad method, since it only gets called rarely (when the view actually loads) and will therefore have negligible impact on performance.
N.B. You should always use PNG images on the iPhone, not JPEG or any other format.
Actually, I got it working! :)
NSString *backgroundPath = [[NSBundle mainBundle] pathForResource:#"background" ofType:#"jpg"];
UIImage *backgroundImage = [UIImage imageWithContentsOfFile:backgroundPath];
UIColor *backgroundColor = [[UIColor alloc] initWithPatternImage:backgroundImage];
self.tableView.backgroundColor = backgroundColor;
[backgroundColor release];
For Swift use this,
self.tableView.backgroundView = UIImageView(image: UIImage(named: "backgroundImage.png"))
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"yourImage.png"]];
In C# for a static UITableViewController with sections you can use:
using System;
using Foundation;
using UIKit;
using CoreGraphics;
using CoreAnimation;
namespace MyNamespace
{
public class CustomTableViewController : UITableViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
SetGradientBackgound();
}
private void SetGradientBackgound()
{
CGColor[] colors = new CGColor[] {
UIColor.Purple.CGColor,
UIColor.Red.CGColor,
};
CAGradientLayer gradientLayer = new CAGradientLayer();
gradientLayer.Frame = this.View.Bounds;
gradientLayer.Colors = colors;
gradientLayer.StartPoint = new CGPoint(0.0, 0.0);
gradientLayer.EndPoint = new CGPoint(1.0, 1.0);
UIView bgView = new UIView()
{
Frame = this.View.Frame
};
bgView.Layer.InsertSublayer(gradientLayer, 0);
UITableView view = (UITableView)this.View;
view.BackgroundColor = UIColor.Clear;
view.BackgroundView = bgView;
}
// Setting cells background transparent
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
var cell = base.GetCell(tableView, indexPath);
cell.BackgroundColor = UIColor.Clear;
return cell;
}
// Setting sections background transparent
public override void WillDisplayHeaderView(UITableView tableView, UIView headerView, nint section)
{
if (headerView.GetType() == typeof(UITableViewHeaderFooterView))
{
UITableViewHeaderFooterView hView = (UITableViewHeaderFooterView)headerView;
hView.ContentView.BackgroundColor = UIColor.Clear;
hView.BackgroundView.BackgroundColor = UIColor.Clear;
}
}
}
}
The result can be something like this:
Related
I'm using a custom sectionheader class with a tableview, and getting some unexpected behavior after rotation. Here's the use case:
Tap on cell in UITableView
View pushed onto stack.
Rotate the view to landscape.
Rotate back to portrait.
Pop the view.
On the iPhone 3G only, a landscape-sized section header now appears stuck somewhere down the middle of the view (in addition to the portrait-sized section header, which appears, as it should, at the top of the tableview). The extraneous header scrolls with the UITableView cells, and switching away from and back to the view (the UITableView is nested within a UITabBarController) doesn't fix the problem.
I can't reproduce this problem on the iPhone 4, or in the Simulator. It seems that, for some reason, a landscape oriented sectionheaderview is being added to the uitableview after popping the second level view, but why would this be? Note that the same problem is reproduced when the default (and not a custom) header is used. I've also checked whether it's a problem with device orientation being returned incorrectly, and that does not appear to be the case.
Here's the init code for the custom SectionHeaderView class, if it's helpful:
-(id)initWithFrame:(CGRect)frame title:(NSString*)title delegate:(id <SectionHeaderViewDelegate>)aDelegate {
self = [super initWithFrame:frame];
if (self != nil) {
float lineHeight = 0.5f;
// check line sizing for retina/non-retina
if (![Utilities hasRetina])
{
lineHeight = 1.0f;
}
// Set up the tap gesture recognizer.
delegate = aDelegate;
// Create and configure the title label.
CGRect titleLabelFrame = self.bounds;
titleLabelFrame.origin.y -= 12.5;
titleLabel = [[UILabel alloc] initWithFrame:titleLabelFrame];
titleLabel.text = title;
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.font = [UIFont fontWithName:#"Georgia" size:15.0];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
[self addSubview:titleLabel];
// add thin white line to top of section header
UIView *topBorder = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.bounds.size.width, lineHeight)];
[topBorder setBackgroundColor:[UIColor whiteColor]];
[self addSubview:topBorder];
[topBorder release];
// Set the colors for the gradient layer.
static NSMutableArray *colors = nil;
if (colors == nil) {
colors = [[NSMutableArray alloc] initWithCapacity:3];
UIColor *color = nil;
color = [UIColor colorWithRed:57.0/255.0 green:56.0/255.0 blue:105.0/255.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
color = [UIColor colorWithRed:54.0/255.0 green:53.0/255.0 blue:95.0/255.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
color = [UIColor colorWithRed:57.0/255.0 green:56.0/255.0 blue:105.0/255.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
}
[(CAGradientLayer *)self.layer setColors:colors];
[(CAGradientLayer *)self.layer setLocations:[NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.48], [NSNumber numberWithFloat:1.0], nil]];
}
return self;
}
Why would an additional landscape version of the custom SectionHeaderView be added in the portrait view, only on the iPhone 3G?
Thanks in advance for any help.
Still no clue what's causing this problem, but I eventually solved it by adding a check in viewWillAppear to make sure the old header was removed.
I'am trying to setup a png image as my tableview's background. With the following code all are fine! But only on iPhone Simulator. If I try to run the application on an iPhone device the background of tableview remains white (or clear). Do you thing thing that is something about the way I tried to set the background color. I have been trying many ways until the following, but all have the same issue.
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.opaque = NO;
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"TableViewBackground.png"]];
Thank you in advance!
Please use following code.
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"TableViewBackground.png"]];
[tempImageView setFrame:self.tableView.frame];
self.tableView.backgroundView = tempImageView;
[tempImageView release];
Thanks,
I think this approach cleaner:
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"TableBackground.jpg"]];
self.tableView.backgroundColor = background;
[background release];
Simple swift version will be
let tempImageView = UIImageView(image: UIImage(named: "yourImage"))
tempImageView.frame = self.tableView.frame
self.tableView.backgroundView = tempImageView;
Is your image actually named TableViewBackground.PNG (note the capitals)? You need to have the case match exactly on an iOS device, whereas it doesn't need to match exactly in the Simulator.
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"TableViewBackground.png"]];
[tempImageView setFrame:self.tableView.frame];
self.tableView.backgroundView = tempImageView;
[tempImageView release];
This works perfect. Thanks to Ravin by Jona
An IBDesignable tableview subclass that will let you attach an image from interface builder
import UIKit
#IBDesignable
class DesignableTableView: UITableView {
#IBInspectable var backgroundImage: UIImage? {
didSet {
if let image = backgroundImage {
let backgroundImage = UIImageView(image: image)
backgroundImage.contentMode = UIViewContentMode.ScaleToFill
backgroundImage.clipsToBounds = false
self.backgroundView = backgroundImage
}
}
}
}
[TableView setBackgroundView:nil];
[TableView setBackgroundView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"apple.png"]] ];
This works perfectly fine, also if you want to use a pattern image for your background.
UIImage *image = [UIImage imageNamed:#"something.png"];
self.tableView.backgroundView = nil;
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
A little late but maybe for all the others looking for a solution. I could get that work by using the following code in the viewDidLoad method of the UITableViewController:
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
self.tableView.backgroundColor = [UIColor clearColor];
or with using just a background color:
self.parentViewController.view.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
self.tableView.backgroundColor = [UIColor clearColor];
It took me a while to figure that out but now it works like a charm.
Objective-c version:
cell.backgroundColor = [UIColor clearColor];
Also see this:
How to create a UITableViewCell with a transparent background
Thanks #Ravin for your answer.
In Swift 5.0:
let tempImageView = UIImageView(image: UIImage(named: "justin_bieber_topless.png"))
tempImageView.frame = self.tableView.frame
self.tableView.backgroundView = tempImageView;
UIImageView *imageviewTemp = [[UIImageView alloc] init];
[(UIImageView *)imageviewTemp sd_setImageWithURL:[NSURL URLWithString:self.stringOfPassedImage]];
[imageviewTemp setFrame:self.tableView.frame];
self.tableView.backgroundView = imageviewTemp;
I've got a UIImageView in a page that gets its image from the Interface builder and I'm trying to put small icons on the top of it (it's a small map and I want to put icons on it). I know it's probably very simple but I tried to look it up in the documentation but it pretty much got me more confused.
Using Interface Builder, can't you just drag a UIImageView into an existing UIImageView? In effect, you end up with one UIImageView embedded within another.
You should also be able to easily set the hidden property of the "small map" UIImageView in code, depending on if that UIImageView is needed or not.
Hope this helps. Good Luck.
Let It Be Known
you could compose your own UIView by adding both the large and small UIViewImage views.
I have illustrated my approach below with the Pseudocode .
-(id) initwithFrame:(CGRect) frame
{
if(self = [super initWithFrame:frame])
{
iContainer = [[UIView alloc] initWithFrame:frame];
[iContainer addSubViews:iLargerUIImageView];
[iContainer addSubViews:iSmallUIImageView];
[self.view addSubViews:iContainer];
}
return self;
}
-(void) layoutSubviews
{
CGRect myRect = self.frame;
iContainer.frame = myRect;
//Give the location to iLargerUIImageView as per your requirement.
iLargerUIImageView.frame = CGRectMake(...,...,...,...);
//Give the location to iSmallUIImageViewas per your requirement.
iSmallUIImageView.frame = CGRectMake(...,...,...,...);
}
-(void) dealloc
{
[iContainer release];
[iLargerUIImageView release];
[iSmallUIImageView release];
}
try this code:
UIImageView *backgroundImageView = (UIImageView *)[self viewWithTag:kBckGndImag];
if(!backgroundImageView){
UIImage *imageName = [UIImage imageNamed:kpointsChartBig];
backgroundImageView = [[UIImageView alloc] initWithFrame:CGRectMake(15, 15, imageName.size.width, imageName.size.height)];
backgroundImageView.image=imageName;
[backgroundImageView setTag:kBckGndImag];
[pointImageView addSubview:backgroundImageView];
[backgroundImageView release];
}
UIImageView *foregroundImageView = (UIImageView *)[self viewWithTag:kForGndImage];
if(!foregroundImageView){
foregroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:kpointsColoredChartBig]];
foregroundImageView.contentMode = UIViewContentModeLeft;
foregroundImageView.clipsToBounds = YES;
[pointImageView addSubview:foregroundImageView];
[foregroundImageView release];
}
It's my first iphone app, and i have trouble with styling my tableView.
I have two images (png), one for standard cell state, and one for selected state.
In my subclassed cell, I tried the following :
1) setting up front the backgroundView and selectedBackgroundView
UIImage *ib = [UIImage imageNamed:#"tab.png"];
UIImageView *back = [[UIImageView alloc] initWithImage:ib];
self.backgroundView = back;
[back release];
UIImage *is = [UIImage imageNamed:#"selected_tab.png"];
UIImageView *selected = [[UIImageView alloc] initWithImage:is];
self.selectedBackgroundView = selected;
[selected release];
The standard cell is fine, but when selected, the two images are shown.
2) just playing with background view on selection :
// storing the 2 uiviews in class attributes
UIImage *ib = [UIImage imageNamed:#"tab.png"];
UIImageView *back = [[UIImageView alloc] initWithImage:ib];
self.storedStandard = back;
[back release];
UIImage *is = [UIImage imageNamed:#"selected_tab.png"];
UIImageView *selected = [[UIImageView alloc] initWithImage:is];
self.storedSelected = selected;
[selected release];
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
if (selected) {
self.backgroundView = self.storedSelected;
}
else {
self.backgroundView = self.storedStandard;
}
}
It nearly works, but the images don't fit the cell, i don't know to stretch them to the size of the cell.
For me, the first solution should have been the one, based on the properties' names, and the second solution seems like a hack (like 90% of the tutorials i seen btw), so i'm a bit frustrated.
To sum up : why the first one doesn't work, and how could i force images to take all the cell space ?
Thanks a lot :)
if you have a UITableViewDelegate, you should be able to just change the backgroundView's image in the willSelectRowAtIndexPath: method and then change it back in the didSelectRowAtIndexPath: method. This is a bit of a hack however.
I'm trying to place various size images inside imageView of UITableViewCell. I get the image data asynch'ly, create the image, set the content mode of imageView and finally set bounds of imageView. But the code seems insensitive to any changes I made. I want the images to be centered in a 75x75 area. I wrote the below code for this purpose
UIImage* image = [UIImage imageWithData:data];
[holder.imageView setContentMode:UIViewContentModeCenter || UIViewContentModeRedraw];
[holder.imageView setImage:image];
[holder.imageView setBounds:CGRectMake(0,0,75,75)];
[holder.imageView setFrame:CGRectMake(0,0,75,75)];
[holder setNeedsLayout];
Where holder is the UITableViewCell. The result I get is always the same. All images have 75px height and different widths. Can someone help me solve this problem?
I have realized that setting contentMode and bounds properties does not have any effect in that code. I have added an NSLog after the last line and got the results as below:
NSLog(#"imageview:%# bounds and contentMode:%# %#",[holder imageView],[holder.imageView bounds],[holder.imageView contentMode]);
imageview:<UIImageView: 0x39ab8a0;
frame = (0 0; 75 75); opaque = NO;
userInteractionEnabled = NO; layer =
<CALayer: 0x39a92b0>> bounds and
contentMode:(null) (null)
Still no solution
Done, I finally found the solution, it cost me 3 hours though =)
The solution is to change properties like bound,frame,contentMode in -(void)layoutSubviews method of the custom UITableViewCell class. The "trick" is to write layout code in this method, otherwise the code does not have any effect.
Below code did the work for me. It makes rows of the table vertically aligned.
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.bounds = CGRectMake(0,0,75,75);
self.imageView.frame = CGRectMake(0,0,75,75);
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
CGRect tmpFrame = self.textLabel.frame;
tmpFrame.origin.x = 77;
self.textLabel.frame = tmpFrame;
tmpFrame = self.detailTextLabel.frame;
tmpFrame.origin.x = 77;
self.detailTextLabel.frame = tmpFrame;
}
So the problem with UITableViewCell's is that you have no control over the size of the built-in objects (namely imageView, contentView, accessoryView, backgroundView). When the table changes, your customizations get trampled over.
You can, as Behlul pointed out, force the sizes to be correct by using layoutSubviews, but the problem with that is that layoutSubviews is called every time the table scrolls. That is a lot of unnecessary re-layout calls.
An alternate, method is to add all of your content to the contentView. Similarly if you are customizing the background, you can create a transparent backgroundView and add your custom background view (eg myBackgroundView) as a subview of backgroundView.
This way you can place and size your items how you want them.
The down side is the stock messages are no longer received from the accessory or image views. You just have to create you own.
Hope that helps!
// This code is not tested
// MyCustomTableViewCell
- (id) init{
self = [super initWithStyle: UITableViewCellStyleDefault reuseIdentifier:#"MyReuseIdentifier"];
if(self){
//image view
my_image_view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"default_image.png"]] retain];
[my_image_view setFrame:CGRectMake(10,10,30,30)];
[self.contentView addSubview:my_image_view];
//labels
my_text_label = [[[UILabel alloc] initWithFrame:CGRectMake(50,10,100,15)] retain];
[self.contentView addSubview:my_text_label];
//set font, etc
//detail label
my_detail_label = [[[UILabel alloc] initWithFrame:CGRectMake(50,25,100,15)] retain];
[self.contentView addSubview:my_detail_label];
//set font, etc
//accessory view
//Whatever you want to do here
//attach "accessoryButtonTapped" selector to button action
//background view
UIView* background_view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 50)] autorelease];
[background_view setBackgroundColor:[UIColor greenColor]];
background_view.layer.cornerRadius = 17;
background_view.layer.borderWidth = 3;
background_view.layer.borderColor = [UIColor whiteColor].CGColor;
[self setBackgroundView:[[[UIView alloc] init] autorelease]];
[self.backgroundView addSubview:background_view];
}
return self;
}
- (void) setLabelText: (NSString*) label_text{
[my_text_label setText:label_text];
}
- (void) setDetailText: (NSString*) detail_text{
[my_detail_label setText: detail_text];
}
- (void) accessoryButtonTapped{
//call table view delegate's accessoryButtonTappedForRowWithIndexPath method
}
"UIViewContentModeCenter || UIViewContentModeRedraw" is equivalent to 1. It's also not a bitfield. You want UIViewContentModeCenter.
UITableViewCell.imageView is managed by the cell. If you want custom layout, try adding a view to contentView (I'm guessing what you mean by "centered in a 75x75 area"):
UIImageView * iv = [[[UIImageView alloc] initWithImage:image] autorelease];
iv.frame = (CGRect){{0,0},{75,75}};
iv.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin| UIViewAutoresizingFlexibleRightMargin;
iv.contentMode = UIViewContentModeScaleAspectFit;
[holder.contentView addSubview:iv];
try changing the "contentMode" property of imageView to 'UIViewContentModeScaleAspectFit' or 'UIViewContentModeScaleAspectFill'
Create subclass of UITableViewCell:
#interface UITableViewCellSubClass : UITableViewCell
#end
#implementation UITableViewCellSubClass
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake(0,4,32,32);
self.textLabel.frame = CGRectMake(42,4,300,32);
}
#end