I try to change the with of a cell in a tableview, I don't do a custom cell, I just subclass uitableviewcell.
This is the class
#implementation customCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]) {
CGRect nouveauframe = CGRectMake(0.0, 0.0, 44,44);
self.frame = nouveauframe;
}
return self;
}
-(void)dealloc
{
[super dealloc];
}
#end
and this is when I create my cell in the cellForRowAtIndexPath:
static NSString *CellIdentifier = #"customCell";
customCell *cell = (customCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[customCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
[[cell textLabel]setText:[[[[Mission singletonMission] getObjectDataHistoireEncours] objectAtIndex:indexPath.row] valueForKey:[[langue singletonLangue] valeurBalise: #"_nom_label"]]];
cell.detailTextLabel.text = [[[[Mission singletonMission] getObjectDataHistoireEncours] objectAtIndex:indexPath.row] valueForKey:[[langue singletonLangue] valeurBalise: #"_valeur"]];
cell.userInteractionEnabled = FALSE;
retour = [cell retain];
but the width of my cell don't change, why?
Table views change the frame of cells when they are added to the table view. If you want to change the width of a cell, you should either change the width of the table, or change the width of the contentView in the cell.
If you want to change the height of the cell the implement the delegate method tableView:heightForRowAtIndexPath:.
If you want to change the width then you should only change it visually (set transparent background for all cell's subviews except the ones that shouldn't be) or, if all the cells should have the same width, you might change the entire table view's width, as #Jerry Jones has advised...
Related
What makes scrolling so choppy on the UITableView? In my mind following code is a culprit. I am having very hard time to replace this logic with something other.
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview]; }
This is what I am doing.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
BGMArticleAbstract *articleAbstract = [self.section.articleAbstracts objectAtIndex:indexPath.row];
[cell.contentView addSubview:[self getHedlineFromArticleAbstract:articleAbstract]];
[cell.contentView addSubview:[self getThumbnailImageFromArticleAbstract:articleAbstract]];
[cell.contentView addSubview:[self getAbstractParaFromArticleAbstract:articleAbstract]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell; }
I am doing, addSubview to contentview because I am creating a dynamic cell height. Is there any way I can make this scroll view work smooth ? Thank you for your help.
You should design your cell as you need it. Add labels and whatever you need to the cell, and then change the content of these already available subviews.
If you need to display an image, add once an UIImageView to the cell and only change the image property of it. Same for text fields and so on.
The way you do it makes the built-in cache useless, because you regenerate all subviews again and again..
To boost the performance even more, you can do the drawing of the cell by yourself.
Apple has a quite nice example project:
http://developer.apple.com/library/ios/#samplecode/AdvancedTableViewCells/Introduction/Intro.html
You are right that the problem is caused by how you return cells. The correct pattern is as follows...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// see if cell contains our image views. A reused cell will, but a new cell won't
UIImageView *imageViewA = (UIImageView *)[cell viewWithTag:32];
UIImageView *imageViewB = (UIImageView *)[cell viewWithTag:33];
UIImageView *imageViewC = (UIImageView *)[cell viewWithTag:34];
if (!imageViewA) {
// the cell must be new, so create it's image views
// you should be able to borrow most of this code from your getHeadline/thumbnail/etc methods.
// the good news is that this relatively expensive code runs only for new
// cells and there are only a few of those - only enough to fill the visible frame
imageViewA = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewA];
imageViewA.tag = 32;
imageViewB = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewB];
imageViewB.tag = 33;
imageViewC = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewC;
imageViewC.tag = 34;
// this too, need only be done upon creation
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// now, whether it's a new cell or a reused cell, we have image views
BGMArticleAbstract *articleAbstract = [self.section.articleAbstracts objectAtIndex:indexPath.row];
// change your methods getHeadline... getThumbnail... etc to answer UIImages
// not UIImageViews, which are setup only for new cells
imageViewA.image = [self getHedlineFromArticleAbstract:articleAbstract]];
imageViewB.image = [self getThumbnailImageFromArticleAbstract:articleAbstract]];
imageViewC.image = [self getAbstractParaFromArticleAbstract:articleAbstract]];
// as a side note, once you get these methods returning images (more like model objects)
// rather than image views (view objects) they might be more appropriately placed
// in the BGMArticleAbstract class rather than the view controller
return cell;
}
when adding an image to table cell, as default it goes to left:
cell.imageView.image = [UIImage imageNamed:[arrImages objectAtIndex:indexPath.row]];
how can I change it that every image in the UITableViewCell will go automaticlly to the right and the textLabel will be 10px to the left of the image.
Thanks alot!
Another way is to create a custom cell and override layoutSubviews method.
#interface CustomCell : UITableViewCell
#end
#implementation CustomCell
- (void)layoutSubviews
{
[super layoutSubviews];
// grab bound for contentView
CGRect contentViewBound = self.contentView.bounds;
// grab the frame for the imageView
CGRect imageViewFrame = self.imageView.frame;
// change x position
imageViewFrame.origin.x = contentViewBound.size.width - imageViewFrame.size.width;
// assign the new frame
self.imageView.frame = imageViewFrame;
}
#end
Rembember that in cellForRowAtIndexPath you need to create and reuse CustomCell and not UITableViewCell.
Hope it helps.
Edit
#import "CustomCell.h"
// other code here...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
return cell;
}
Find the solution here code.
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"foo.png"]];
cell.accessoryView = imageView;
For your reference.
UITableViewCell with image on the right?
try this:
cell.imageView.frame = CGRectMake(cell.frame.size.width - cell.imageView.frame.size.width, cell.imageView.frame.origin.y, cell.imageView.frame.size.width, cell.imageView.frame.size.height);
[cell.yourTexLabel sizeToFit];
cell.yourTexLabel.frame = CGRectMake(cell.imageView.origin.x - cell.yourTexLabel.frame.size.width - 10, cell.yourTexLabel.frame.origin.y, cell.yourTexLabel.frame.size.width, cell.yourTexLabel.frame.size.height);
Found a better answer from #TomSwift here https://stackoverflow.com/a/31616694/1884707
cell.contentView.transform = CGAffineTransformMakeScale(-1,1);
cell.imageView.transform = CGAffineTransformMakeScale(-1,1);
cell.textLabel.transform = CGAffineTransformMakeScale(-1,1);
cell.textLabel.textAlignment = NSTextAlignmentRight;
By applying a transform on the contentView you can place the imageView on the right.
in swift3 and swift4, we can use this:
cell.accessoryView = UIImageView(image:UIImage(named:"imageNmae")!)
One solution is to use a custom UITableViewCell. The steps are:
Create a new objective-C class that is a subclass of UITableViewCell, for example LabeledImageTableViewCell. Declare ivars and properties for a UILabel and a UIImageView.
In Interface Builder, set the content of the UITableView to Dynamic Prototypes. Drag a UIImageView and a UILabel to a table view cell and position them. Set the cell's class to LabeledImageTableViewCell. Connect the outlets of the cell to the UILabel & UIImageView objects of LabeledImageTableViewCell.
In the delegate for UITableView (usually a UITableViewController, sometimes a UIViewController) implement the datasource methods, for example:
//#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return (NSInteger)[rowData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"tvcLabeledImage";
LabeledImageTableViewCell *cell = (LabeledImageTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[LNCCorrelationInfoTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.myImage = [UIImage imageNamed:#"imageForThisRow.png"];
cell.myLabel = "imageForThisRow";
return cell;
}
Also, check out the Apple videos from WWDC 2011, UITableView Changes, Tips & Tricks and Introducing Interface Builder Storyboarding (Login required: https://developer.apple.com/videos/wwdc/2011/.)
I am trying to resize the height of my row in UITableView based on the text length. I have the following code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellText =[[topics objectAtIndex:indexPath.row] name];
UIFont *cellFont = [UIFont fontWithName:#"ArialMT" size:17.0];
CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
return labelSize.height + 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:#"ArialMT" size:17.0];
}
}
However, it messes up with the UIImageView and the UIDetailText, image shown below:
How do I fix this?
I've tried:
[cell.imageView setContentMode:UIViewContentModeScaleToFill];
[cell.imageView setFrame:CGRectMake(0, 0, 16,16)];
[cell.imageView setBounds:CGRectMake(0, 0, 16,16)];
[cell.imageView setAutoresizingMask:UIViewAutoresizingNone];
[cell.imageView setAutoresizesSubviews:NO];
and none seems to work
The work of changing cell's subviews' frames is done in - (void)layoutSubviews of UITableViewCell class, so if you want alter that behavior you can subclass common UITableViewCell and then do smth like:
#implementation MyTableViewCell
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake( -- your own size -- );
}
#end
Instead of subclassing as suggested by others, you could also add your own subviews to the cell’s content view.
From Customizing Cells:
If you want the cell to have different
content components and to have these
laid out in different locations, or if
you want different behavioral
characteristics for the cell, you have
two alternatives. You can add subviews
to the contentView property of the
cell object or you can create a custom
subclass of UITableViewCell.
You should add subviews to a cell’s content view when your content layout can be specified entirely with the appropriate autoresizing settings and when you don’t need to modify the default behavior of the cell.
You should create a custom subclass when your content requires custom layout code or when you need to change the default behavior of the cell, such as in response to editing mode.
See this example:
#define CUSTOM_IMAGE_TAG 99
#define MAIN_LABEL 98
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UIImageView *customImageView = nil;
UILabel *mainLabel = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
customImageView = [[[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 40.0f, 40.0f)] autorelease];
customImageView.tag = CUSTOM_IMAGE_TAG;
[cell.contentView addSubview:customImageView];
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(60.0f, 10.0f, 100.0f, 21.0f)] autorelease];
mainLabel.tag = MAIN_LABEL;
mainLabel.numberOfLines = 0;
[cell.contentView addSubview:mainLabel];
} else {
customImageView = (UIImageView *)[cell.contentView viewWithTag:CUSTOM_IMAGE_TAG];
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAIN_LABEL];
}
// Configure the cell.
CGRect frame = mainLabel.frame;
frame.size.height = ... // dynamic height
mainLabel.frame = frame;
return cell;
}
Obviously, you still need to implement tableView:heightForRowAtIndexPath:.
I think the built in imageView will ignore your attempts to resize it. Subclass UITableViewCell and add your own custom UIImageView to it. Then you can control all aspects of your image view.
-- wisenomad's solution will work without having to add your own custom image view and labels. --
You will also have to change the frame of the textLabel. Here is an example.
- (void)layoutSubviews {
[super layoutSubviews];
float sideLength = self.frame.size.height;
self.imageView.frame = CGRectMake(0.0, 0.0, sideLength, sideLength);
CGRect textLabelFrame = self.textLabel.frame;
self.textLabel.frame = CGRectMake(44.0, textLabelFrame.origin.y, textLabelFrame.size.width - 44.0 + textLabelFrame.origin.x, textLabelFrame.size.height);
}
I'm trying to figure out how to place a subview to a custom UITableViewCell with centered position. As stated in the documentation (Customizing Cells) one should "...add subviews to the contentView property of the cell object or ...". As I noticed it works fine with UITableViewStylePlain. In UITableViewStyleGrouped tables, subviews can not be placed centered. They are shifted to the right hand side.
If the subview is added to UITableViewCell directly, it's fine with both modes. The same is true, if I subclass the UITableViewCell and load the cell from XIB.
Unfortunately, I can't upload screenshots. Can anyone help fix the issue? Or do I miss something vital, as the misalignment seems to match the dimension to be shrunken in grouped table.
Many thanks,
El
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier1 = #"AddToCell";
static NSString *cellIdentifier2 = #"AddToContentView";
static NSString *aVeryLongLine = #"---------------------------------------------";
UITableViewCell *cell = nil;
if (indexPath.section == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier1];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier1] autorelease];
CGRect frame = cell.frame;
CGRect labelFrame = CGRectMake((frame.size.width-270)/2, (frame.size.height-40)/2, 270, 40);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.textAlignment = UITextAlignmentCenter;
label.text = aVeryLongLine;
[cell addSubview:label];
[label release];
}
}
else if (indexPath.section == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier2];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier2] autorelease];
CGRect frame = cell.contentView.frame;
CGRect labelFrame = CGRectMake((frame.size.width-270)/2, (frame.size.height-40)/2, 270, 40);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.textAlignment = UITextAlignmentCenter;
label.text = aVeryLongLine;
[cell.contentView addSubview:label];
[label release];
}
}
else {
}
return cell;
}
Instances of UITableViewCell resize their content views under a number of circumstances (for example, when temporarily adding a delete button to allow the user to remove a row).
When cells are displayed in a grouped style table view, they're resized to provide a margin between the cells and the left and right edges of the table view. So for your subviews to stay positioned correctly, you'll need to set their autoresizing masks appropriately, something like this:
mySubview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
(or
[mySubview setAutoresizingMask:(UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin)];
for folks who prefer the old syntax.)
Did you check the frame's value, which come from cell.contentView.frame or cell.frame ?
When the cell is initialized with style and identity, it maybe have a CGZeroRect for his frame value.
Is there a way to set the UITableViewCell.image to display on the right hand side of the cell instead of the left? Or will I need to add a separate UIImageView on the right side of the cell layout?
No. But you can easily add an image view as the accessory view to a table cell for the same effect.
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"foo.png"]];
cell.accessoryView = imageView;
[imageView release];
For simple cases you can do this:
cell.contentView.transform = CGAffineTransformMakeScale(-1,1);
cell.imageView.transform = CGAffineTransformMakeScale(-1,1);
cell.textLabel.transform = CGAffineTransformMakeScale(-1,1);
cell.textLabel.textAlignment = NSTextAlignmentRight; // optional
This will flip (mirror) the content view placing any imageView on the right. Note that you have to flip the imageView and any text labels also otherwise they themselves would be mirrored! This solution preserves the accessory view on the right.
Here is an example in Swift with the approach of using accessoryView:
private let reuseIdentifier: String = "your-cell-reuse-id"
// MARK: UITableViewDataSource
func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell
if (cell == nil) {
cell = UITableViewCell(style:UITableViewCellStyle.Subtitle, reuseIdentifier:reuseIdentifier)
}
cell!.textLabel!.text = "Hello"
cell!.detailTextLabel!.text = "World"
cell!.accessoryView = UIImageView(image:UIImage(named:"YourImageName")!)
return cell!
}
If you don't want to make a custom cell and will work with standard one, you have as minimum two ways:
To use accessoryView.
cell.accessoryView = UIImageView(image: UIImage(named: "imageName"))
cell.accessoryView.frame = CGRectMake(0, 0, 22, 22)
If you want to have the right image + accessoryView, then you can add UIImageView outlet to ContentView (example name: rightImage) and change background color of textLabel as Clear.
cell.rightImage.image = UIImage(named: "imageName")
cell.textLabel.backgroundColor = UIColor.clearColor()
in swift3 and swift4, we can use this:
cell.accessoryView = UIImageView(image:UIImage(named:"imageNmae")!)
Subclass UITableViewCell and override layoutSubviews and then just adjust the frames of the self.textLabel, self.detailTextLabel and self.imageView views.
This is how it might look like in code:
MYTableViewCell.h:
#import <UIKit/UIKit.h>
#interface MYTableViewCell : UITableViewCell
#end
MYTableViewCell.m:
#import "MYTableViewCell.h"
#implementation MYTableViewCell
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.imageView.image) {
self.imageView.frame = CGRectMake(CGRectGetWidth(self.contentView.bounds) - 32 - 8,
CGRectGetMidY(self.contentView.bounds) - 16.0f,
32,
32);
CGRect frame = self.textLabel.frame;
frame.origin.x = 8;
self.textLabel.frame = frame;
frame = self.detailTextLabel.frame;
frame.origin.x = 8;
self.detailTextLabel.frame = frame;
}
}
#end
To Add image # Right Hand side in the Cell, I would suggest you to create a Custom cell with imageview on right hand side , it will be very useful for you .
and add an empty view to link this nib with customcell class.
Now in your cell's nib file remove the view,add tableViewcell and in that cell drag & drop an imageView to right hand side.
Now go to the TableViewCell's class say DemoCell , create an outlet and set it with the imageview in the tablecell's nib
Now,in tableview's cellforrowatindexpath method reference your cell and use it with the nib name like this
static NSString *CellIdentifier = #"Cell";
DemoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[SettingCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell = [[[NSBundle mainBundle]loadNibNamed:#"DemoCell" owner:self options:nil] lastObject];
}
and set the image as per your requirement
cell.imageVw.img ....
You can resize image in the accessoryview by calling setFrame method of imageview like this: [imageView setFrame:CGRectMake(0, 0, 35.0, 35.0)];
This Soln is for adding different image in each cell....Just a Try
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if(indexPath.row == 0) {
cell.image = [UIImage imageNamed:#"image.png"];
}
else if (indexPath.row == 1) {
cell.image = [UIImage imageNamed:#"image1.png"];
}
It's unnecessary to create your own image, just edit cell.tintColor.
There is a way to set the position programmatically. Here is the Swift version of the solution:
image.frame = CGRect.init(
x: self.view.frame.width - image.frame.width*1.1,
y: image.frame.origin.y,
width: image.frame.width,
height: image.frame.height)
This will position your image on the right side of the cell.
This solution is adjusting automatically the position according to screen size.
The only down side is when you rotate the device you need to reload your data, but you can just override in your UITableView class the didRotate listener method:
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
_tableView.reloadData()}