I am adding my own UILabels to the contentView of a UITableViewCell because I need more control over the layout than the default UITableViewCellStyles provide. In essence I want the detailLabel have priority over the textLabel so the textLabel gets truncated.
I have the following code in my UITableViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * const kCellIdentifier = #"CustomCell";
UITableViewCell * cell =
[tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
UILabel * titleLabel, * dateLabel;
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:kCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
titleLabel = [[[UILabel alloc] init] autorelease];
titleLabel.tag = kTitleLabelTag;
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
dateLabel = [[[UILabel alloc] init] autorelease];
dateLabel.tag = kDateLabelTag;
dateLabel.textColor = [UIColor blueColor];
dateLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[cell.contentView addSubview:titleLabel];
[cell.contentView addSubview:dateLabel];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)pCell
atIndexPath:(NSIndexPath *)pIndexPath
{
const float kHeight = 44.0, kLeftIndent = 8.0, kOverallWidth = 293.0,
kGap = 1.0;
UILabel * titleLabel, * dateLabel;
titleLabel = (UILabel *)[pCell.contentView viewWithTag:kTitleLabelTag];
dateLabel = (UILabel *)[pCell.contentView viewWithTag:kDateLabelTag];
NSString * dateText = #"9:39 AM";
// Calculate the size of dateLabel
CGSize dateSize = [dateText sizeWithFont:[dateLabel font]
constrainedToSize:CGSizeMake(kOverallWidth, kHeight)];
const float dateXPos = kOverallWidth - dateSize.width;
dateLabel.frame = CGRectMake(dateXPos, 0.0, dateSize.width, kHeight);
titleLabel.frame = CGRectMake(kLeftIndent, 0.0,
dateXPos - kLeftIndent - kGap, kHeight);
titleLabel.text = #"Some potentially very long text which will be wrapped.";
dateLabel.text = dateText;
pCell.contentView.backgroundColor = [UIColor purpleColor];
}
The code above produces incorrect results. When the table view is initially shown, it looks like figure 1) in this image of the renderings.
So there is a unwanted gap on the right of all the dateLabels. (the purple background is just for better visibility what is going on)
When dragging the tableview up like in 2) in the image, it then bounces back and looks like 3).
The first row has now exactly the layout I wanted and which calculated in configureCell:atIndexPath:. I guess this behavior happens because the cells get re-used and then configured again.
So it feels like I am missing some kind of initialization, I have tried calling setNeedsLayout and layoutSubviews of pCell and pCell.contentView but never achieved an initial correct rendering.
Only when I set the autoresizingMask of titleLabel and dateLabel to UIViewAutoresizingNone I get a correct initial rendering, then however the swipe to delete does not work because the delete button gets rendered over the dateLabel.
What do I have to change in my code so that all cells get rendered initially like the first cell in the third picture?
Thanks!
PS: I would like to have inlined the pictures but unfortunately I do not have enough reputation for that.
A good, and maybe simpler way to do this is to:
First Create a custom UITableViewCell subclass which you can setup using Interface Builder. If "MyTableViewCell" is your custom cell view you initialize it in CellForRowAtIndexPath like this:
MyTableViewCellClass *cell = (MyTableViewCellClass *)[tableView dequeueReusableCellWithIdentifier:#"MyTableViewCellClass"] autorelease];
if (!cell)
cell = [[[MyTableViewCellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyTableViewCellClass"] autorelease];
// Call specific methods on your cell to pass information to it, not for display
[cell setProperties:...];
Then implement the layoutSubviews method in your custom UITableViewCell subclass. For instance:
-(void) layoutSubviews
{
// You must call this first to make sure your cell gets current parent information
[super layoutSubviews];
// Retrieve the content view bounds. This will include the edit symbols when present (delete button and ordering symbol
float inset = 5.0;
CGRect bounds = [[self contentView] bounds];
// Keep on going here with your own view layout.
}
Doing this you basically separate the cell model (CellForRowAtIndexPath) from the cell view (your custom implementation of cell drawing). If you later change the implementation (layout) of your cell you can do this easily simply by changing your cell layout without worrying about the CellForRowAtIndexPath method.
If you work with a storyboard , you should disable the "Use Auto Layout" in the File Inspector!
Then set the cell's property autoresizesSubviews
- (void)awakeFromNib
{
// Initialization code
self.autoresizesSubviews=YES;
}
The final step is configure the frame of the Label , overriding the method layoutSubviews of the UITableViewCell class
-(void)layoutSubviews{
[super layoutSubviews];
CGFloat top=VerticalPadding;
CGFloat left=HorizentalPadding;
CGFloat width=CGRectGetWidth(self.frame)-2*HorizentalPadding;
CGFloat height=CGRectGetHeight(self.frame)-2*VerticalPadding;
CGRect rect=CGRectMake(left, top, width, height);
self.Label.frame=rect;
}
Related
I want to have my text in my UITableViewCell to be a little bit to the right. In other words I want to have an x-offset. Is this even possble? Do I have to create a custom cell just because of this?
You could use cell.indentationLevel and if needed cell.indentationWidth instead of custom UITableViewCell for this.
You can try this :
[cell setIndentationLevel:SOME_NUMBER];
[cell setIndentationWidth:SOME_OTHER_NUMBER];
A simple solution is you can change the frame of the textLabel.
CGRect textLabelFrame = cell.textLabel.frame;
textLabelFrame.origin.x += xOffset;
textLabelFrame.size.width -= xOffset;
cell.textLabel.frame = textLabelFrame;
I've also done this by creating a custom UILabel that supports edgeInsets similar to a UIButton. This is a better solution b/c you can layout the label to correct size but the above will work if you have simple needs.
[EDIT 1/2: fixed typo w/ CGRect]
[EDIT 3: fixed typo setting modified frame]
[EDIT 4: need a simple subclass]
Mea culpa. I was wrong that you can do this in tableView:cellForRowAtIndexPath. The UITableViewCell layout happens after the tableView delegate/datasource has a chance to customize the cell. I've tested the implementation below, it works.
Do as I say above but create a (simple) subclass of UITableViewCell that adds the xOffset in layoutSubviews. If you do this, you can also add an xOffset property that you can set in tableView:cellForRowAtIndexPath:.
#implementation XOffsetCell
// assumes property xOffset is defined and synthesized
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect textLabelFrame = cell.textLabel.frame;
textLabelFrame.origin.x += self.xOffset;
textLabelFrame.size.width -= self.xOffset;
cell.textLabel.frame = textLabelFrame;
}
#end
The solution that suggested adding a custom UILabel to cell.contentView is also a good solution. I saw your comment that it obscures the built-in textLabel but that's the whole point. You would not use the built-in label anymore, use the custom label instead.
I'm not trolling for votes, but wanted to show what the code provided by #iPhone monster "should" look like. His solution is a valid option. If you add the label to the cell after the if (cell == nil) as he did you will be continually adding labels to dequeued cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(50.0f, 10.0f, 150.0f, 20.0f)];
lbl.tag = OffsetLabelTag; // define this as a constant
[cell.contentView addSubview:lbl];
[lbl release];
}
UILabel *lbl = (UILabel *)[cell.contentView viewWithTag:OffsetLabelTag];
[lbl setText:#"test text"];
return cell;
}
You can do that with Autolayouts:
UITableViewCell *cell = [UITableViewCell new];
cell.textLabel.translatesAutoresizingMaskIntoConstraints = NO;
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(indentation)-[textLabel]-(indentation)-|"
options:0
metrics:#{#"indentation": #35}
views:#{#"textLabel": cell.textLabel}]];
Or using Parus lib:
[cell.contentView addConstraints:(PVVFL(#"H:|-(indentation)-[textLabel]-(indentation)-|")
.withViews(#{#"textLabel": textLabel})
.metrics(#{#"indentation": #35}).asArray)];
Other way:
- (NSInteger)tableView:(UITableView *)tableView
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
return intOffset; // but is like '\t', not points
}
There is another not very pretty and smart way : ) Position of Label in TableViewCell depends on size of image assigned to cell.imageView.image property. So if you want your text to move right you can add several blank pixel columns to image in cell.
Based off of https://stackoverflow.com/a/5659826/1058199, here is a Swift version.
This works within the cell to ONLY move the textLabel to the right. Swift 5.4
override func layoutSubviews() {
super.layoutSubviews()
var textLabelFrame = self.textLabel?.frame
textLabelFrame?.origin.x += 32
textLabelFrame?.size.width -= 32
self.textLabel?.frame = textLabelFrame ?? CGRect.zero
}
Will cell.textLabel.textAlignment = UITextAlignmentCenter; be enough for you. It could align the text to the center creating that space for you
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.
I have a tableview cell with a custom textview in it, I am now left wondering how do I possibly access the text in the textbox after text has been edited/added.
I would normally know how this is done when I draw the textfield through IB, but my textviewcell is dynamically drawn.
(i.e. I would like to capture the data that is updated in detailLabel.text)
Here is the related code to adapt to your answer.
Thanks again!
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
//Big Text Box
UITextView *detailLabel = [[UITextView alloc] initWithFrame:CGRectMake(30, 80, 500, 150)];
detailLabel.tag = 20;
[cell.contentView addSubview:detailLabel];
detailLabel.layer.borderWidth = 1;
detailLabel.layer.borderColor = [[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.9] CGColor];
detailLabel.layer.cornerRadius = 10;
detailLabel.font = [UIFont fontWithName:#"Helvetica" size:17];
[detailLabel release];
}
UITextView * detailLabel = (UITextView *) [cell.contentView viewWithTag:20];
switch (indexPath.row) {
case 0:
detailLabel.text = #"no";
break;
default:
detailLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
detailLabel.hidden = NO;
}
You'll want to listen for messages sent by the UITextView. So look to implement the UITextViewDelegate protocol and register the implementing class with the detailLabel using its delegate property.
When your delegate is notified of a change in the UITextView you'll have to identify the cell which currently owns the UITextView. In doing so you must remember that cells can be reused.
I would start by looking at the following method in the UITableView class:
- (NSArray *)visibleCells
We know that if the user has made a change to the UITextView's contents it must currently be on screen and therefore be present in the pre-mentioned array. To find it we use the pointer to the UITextView which changed (it's a parameter in the textViewDidChange protocol method). So simply iterate over the visibleCells array and retrieve the UITextView and compare it against the UITextView which changed.
- (void)textViewDidChange:(UITextView *)textView {
....
cellsLabel = (UITextView *) [cell.contentView viewWithTag:20];
if (cellsLabel == textView)
...
You'll now have a handle to a cell in the UITableView. To find the index use the following UITableView method:
- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell
I've got an annoying problem in my tableview. I was able to achive color-changing cells (blue/white/blue/...), but now I'm in trouble with my text, which has a white background on the blue cells.
I've tried for testing to set a background color to red:
// try to set the backgroundcolor of the text ???
cell.textLabel.text.backgroundColor = [UIColor redColor];
which doesn't work; hmph.
Please have a look at my code below; can anybody tell me what's wrong and how I can solve my problem by giving the text a transparent background?
// 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:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell
cell.textLabel.text=[RssFeedNodes objectAtIndex:indexPath.row];
// try to set the backgroundcolor of the text ???
cell.textLabel.text.backgroundColor = [UIColor redColor];
// show image in cell
NSString *imageName=#"rss.png";
cell.imageView.image=[UIImage imageNamed:imageName];
// changing colors in cells
NSInteger row = [indexPath row];
if (row % 2){
cell.contentView.backgroundColor = [UIColor whiteColor];
}
else {
cell.contentView.backgroundColor = [UIColor colorWithRed:0.90f green:0.95f blue:1.0f alpha:1.0f];
}
return cell;
}
Your answer is found (and described very well) here: http://undefinedvalue.com/2009/11/02/easy-gradient-backgrounds-uitextviewcells
My brief summary of the solution: Subclass the UITableViewCell, and then use your subclass when creating instances in cellForRowAtIndexPath.
You then need to override just one method (setSelected) in your subclass UITableViewCell:
(void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
for (UIView *view in self.contentView.subviews) {
view.backgroundColor = [UIColor clearColor];
}
}
The reason appears to be that the built-in UITableViewCell class will set the label background to white (or selected color) when being displayed based on the selection state in the table in the setSelected method. Substitute your own, call the base class implementation, then set your subview backgrounds to clear in order to let your contentView background shine through.
text has no background, but textLabel has. so
[[cell textLabel] setBackground:[UIColor redColor]];
You'll need to add your own UILabel label onto the cell, and set the background colour of that to transparent. For some reason the label that a table cell has does not have a settable background colour.
Something like:
UILabel* label = [[UILabel alloc] init];
label.frame = CGRectMake( 20, 10, 200, 22 );
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
label.text = #"your text here:";
[cell addSubview:label];
[label release];
In this example I've set the frame for the label fairly arbitrarily (well not, actually, this was modified from some of my own real code). You may need to be more dynamic with the sizing, in which case you'll probably need to subclass the cell and override setFrame to keep the label's frame in sync. But hardcoded values should get you going for now.
#define LABEL_TAG 99
// whatever your label rect size should be... change as appropriate
UIlabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300.0, 30.0)];
label.tag = LABEL_TAG;
// set up alignment, font, autoresizemask, etc.
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
[cell.contentView addSubview:label];
[label release];
Something to watch out for is that you're not adding your own label to a reuseable table cell more than once. By setting a known view.tag property you can get at (or discover existence of) the UILabel view. [cell viewWithTag:LABEL_TAG]
Whenever you dequeue a reuseable cell, first get the reference to your label view, then do what you would normally do if you were using the UITableCell's textLabel.
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()}