I set my tableview's separatorStyle like below:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
But my last custom cell in 0 section have a separator:
the last cell appears separator
As you see the last cell in second section did not have a separator.
Why the last cell in first section have one?
I reveal into the view hierarchy as below shows, WYRealNameInfoCell is the last cell appears separator, it have two Separators!
the view hierarchy
If I add codes in the cell's implementation like below:
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
for (UIView *view in self.subviews) {
if (view != self.contentView) {
[view removeFromSuperview];
}
}
}
There will only one _UITableViewCellSeparatorView.
Why does it appears separator, and how to avoid such issues?
Related
I have a UITableViewCell with a description label pinned to the bottom as shown below:
Tapping on the description label toggles the numberOfLines between 3 and 0:
- (void)awakeFromNib {
[super awakeFromNib];
[self setupView];
}
-(void) setupView
{
UITapGestureRecognizer * gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(toggleNumberOfLines)];
self.jobDescriptionLabel.userInteractionEnabled = YES;
[self.jobDescriptionLabel addGestureRecognizer:gestureRecognizer];
}
- (void) toggleNumberOfLines {
if(self.jobDescriptionLabel.numberOfLines != 0){
self.jobDescriptionLabel.numberOfLines = 0;
}else{
self.jobDescriptionLabel.numberOfLines = kNumberOfLines;
}
[self.jobDescriptionLabel sizeToFit];
[self layoutIfNeeded];
}
When I tap on the label, the number of lines does change but the cell does not expand to accommodate the new number of lines. How do I fix this?
Collapsed (Default):
Expanded:
If you have your constraints set up correctly, you do not need to reload the data --- not the whole table, not even the affected rows.
Best method is to add a delegate function back to your tableview controller, and just call these lines back-to-back:
tableView.beginUpdates()
tablebleView.endUpdates()
That will tell auto-layout to re-calc the row heights.
Edit: Check my answer - which includes a link to a demo project - here: Expand UILabel inside UITableView with "more" button like Instagram
When the cell lays out it's subviews, the table view doesn't actually have any way of knowing anything has changed. You manually have to tell the table view to recalculate.
You probably want to reload the table view, or at least the cell the changes are happening in.
Take a look at reloadData for reloading the whole table view, or reloadRowsAtIndexPaths: if you want to just reload specific indexes in the Apple reference docs.
You can update the tableview cell height in heightForRowAtindexPath:.
Call reloadRowsAtIndexPath Method to update single row of UITableView.
self.dataTableView.beginUpdates()
self.dataTableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: UITableViewRowAnimation.automatic)
self.dataTableView.endUpdates()
I have UITableViewCell that contains UIView (lets call it CPView) which is created while cellForRowAtIndexPath is called. CPView is just a plain coloured view and for every cell its width is different (that's why needed to create in cellForRowAtIndexPath).
Problem is
1)The CPView 's colour gets darker every time cell loads (May be due to every time that cell creates the same view so overlapping effect).
2) The cell overlaps / inherits other cell's CPView (we can see this because of light and dark colour of two CPView).
How can I prevent cell to recreate if it already exist or creation of this CPView again?
Edit
- (void)configureCell:(CreditDebitCell *)cell atIndexPath:(NSIndexPath *)indexPath {
//other code
UIView * CPView;
if (CPView){
CPView =nil;
}
else
{
CPView = [[UIView alloc] initWithFrame:CGRectMake(cell.bounds.origin.x, cell.bounds.origin.y, cell.frame.size.width*[self.percentArray[indexPath.row] floatValue] ,cell.frame.size.height )];
[CPView setClipsToBounds:YES];
[CPView setBackgroundColor:[UIColor colorWithRed:107/255.0 green:15/255.0 blue:47/255.0 alpha:0.5]];
[cell addSubview: CPView];
}
}
The issue here is reuse of the cells - and therefore you get multiple views added to your cell view.
You can:
-remove subview
-check if subview exists and do/don't do anything.
You can check if the subview is there by going through subviews:
for (UIView *v in cell.contentView.subview) {
if ([v isKindOfClass:[CPView class]]) {
// remove or flag that it exists
}
}
But I think that you should handle this in your cell - not your view controller that implements table view delegate. Better tell cell to use some view/hide some view based on some kind of logic then to do that inside cellForRowAtIndexPath
According to your i question(without cellforRowAtIndexpath) i can assume that you should check every time something like in cellForRowAtIndexPath
if(cpView){
cpView = nil;
}
// alloc again with required size for particular row.
Make a subclass of your UITableViewCell and make a property of it that will reference your CPView. This will now let you have a better control whether your subclassed cell does / doesn't have any CPView that needs to be added.
I know this question has been asked before. But no person on the internet had a working and sufficient answer.
EDIT Obviously people don't read questions anymore, on SO. So I'm trying to clarify: I want to remove the SEPARATOR. The separator is neither the space above the section, nor the tableViewHeader or tableViewFooterView. It is only the thin line above (fully from left to right).
I have a grouped UITableView (I don't want to use a plain styled for many other reasons, take it as it is) which has multiple groups.
The first section should not have the separator line on top. Setting the separator style of the tableView is not an option, because I do need the other separators.
Setting the tableViews tableFooterView is something I often read, but it never worked.
I used the tableView with static content before and I was able to remove the separator in -[UITableViewController viewDidLoad] using this:
- (void)viewDidLoad {
[[[self headerTableCell] valueForKey:#"_topSeparatorView"] removeFromSuperView];
}
Since I now had to change the tableView to a dynamic one, the IBOutlet property won't work anymore (obviously).
So I tried everything, -[id tableView:willDisplayCell:atIndexPath:], -[UITableViewCell initWithStyle:reuseIdentifier:, prepareForReuse, awakeFromNib] and some others.
In any case, this separator is nil. So I need a method that gets called when the complete view hierarchy of the cell is setup.
what i get from your situation you have a grouped UITableView you want the first section without separator and you want to keep the separator in the other sections so
remove the separator from the whole tableview from the attributes inspector make Separator : None
create custom UITableviewCell in storyboard for other sections and add View at the end of it with height 1 and width the whole screen (like default separator)
it's maybe not the best idea but this will allow you to have the first section without separator
I faced a similar problem, wanted to remove the last line of the section in grouped table view, I am calling following method in view will appear and on every table reload. This is not the exact answer but problem can be solved by just changing y value of dummy view.
+(void)removeLastSectionSeparatorForTableView:(UITableView *)tableView
{
UIView *oldSeparatorView = [tableView viewWithTag:kTagDummySectionSeparator];
if (oldSeparatorView != nil)
{
[oldSeparatorView removeFromSuperview];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(),
^{
UIView *view = [[UIView alloc] init];
view.tag = kTagDummySectionSeparator;
view.backgroundColor = [UIColor colorWithRed:239.0/255 green:239.0/255 blue:244.0/255 alpha:1.0];//Group table background color
view.frame = CGRectMake(0,
tableView.contentSize.height-40,
tableView.bounds.size.width,
2);
[tableView addSubview:view];
});
}
Maybe this problem is the same as mine before.
Finally, my way to solve this problem: set table view delegate's method (CGFloat)tableView:(UITableView *)tableView heightForHeaderAtSection:(NSInteger)section, then return CGFLOAT_MIN;
add this override function in your Custom Cell Class
override func layoutSubviews() {
super.layoutSubviews()
for subview in subviews where (subview != contentView && abs(subview.frame.width - frame.width) <= 0.1 && subview.frame.height < 2) {
subview.removeFromSuperview()
}
}
In my table view, I have three sections, of which the first section contains a image cell, the second section contains segment control cell, and the third section contains some label cells.
What I am doing is when the user scrolls up the table view, everything will scroll up but the position of the segment control cell will be fixed at the upper margin of the screen.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSIndexPath *indexPathOfCurrentHeaderCell = [NSIndexPath indexPathForRow:0 inSection:0] ;
UITableViewCell *headerCell = [self.tableView cellForRowAtIndexPath:indexPathOfCurrentHeaderCell];
if (headerCell.frame.origin.y < self.tableView.contentOffset.y)
{
self.cellHead.hidden = NO;
self.cellHead.frame = CGRectMake(0, self.tableView.contentOffset.y, self.cellHead.frame.size.width, self.cellHead.frame.size.height);
}
[self.tableView bringSubviewToFront:self.cellHead];
}
But the function bringSubviewToFront: does not seem to work here (the second section will be covered by the third section). I think it is because the cells are not the subviews of the table view.
What can I do if I want to pull the segment control cell to the front?
You should add the segment control as a header instead of a cell in the tableview, using
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
then, you would have 2 sections,
1. image cell
2. segment control as header, labels as the cells
I've got this issue. I'm using a collection view as a subview of the main view of a UIViewController. The collection view is pinned to the superview size, thus it has 4 constraints for lead,trail, top and bottom with constants equal to 0.
The cell is a subclass to UICollectionViewCell and is composed by:
first header view
second header view
UITableView
The collection view cell is loaded from xib and the interface of the views is made for 4 inches devices.
The first header view is pinned at top, trail, lead with constant 0 and fixed height to its superview.
The second header view is constrained to first header view with vertical spacing equal to 0, fixed height, pinned trail, lead with constant 0 to its superview.
The table view is constrained to second header view with vertical spacing equal to 0 and pinned trail, lead and bottom with constant 0 to its superview.
On 4 inches screen everything is OK, but when I load on 3.5 I have some problems, the fact is that I want to create UITableViewCell with a dynamic height. The height should be the height of the UITableView dived by the number of rows, in this way they will appear on screen.
The table view delegate and datasource are valorized only when I set the data that need to be loaded and that happens after creating it, but before the collection view cell is returned from the data source method.
In the -layoutSubviews method of the UICollectionViewCell subclass I set the tableview row height, to the desired value that is
- (void) layoutSubviews {
[super layoutSubviews];
self.answerTableView.rowHeight = self.answerTableView.bounds.size.height / self.quizSection.answers.count;
}
The fact is that here the table view is stil not resized thus the resulting rowHeight is wrong, the value is the same I receive in 4 inches display. The superview (the contentView of the collection view cell) is ok, but the table view has a size that is not correct. When displayed the collection view is fine except for the fact that the table view's cells are wrong in size.
So I started to trace the cycle of the collection view cell.
In the initWithFrame methods the collection view cell has the same size of the original xib (4 inches screen)
In the view controller if I ask the size of the collection view cell right after dequeuing, if resized to the correct screen size, but the table view inside not
After loading the data and setting delegate and datasource, collection view is ok, but tableview not
In the -updateConstraints of the collection view cell the table view size is still wrong
In the -layoutSubviewsof the collection view cell the table view size is still wrong
The first call of the dtasource method of the table view returns a correct size
I've found the solution that is use the delegate methods - (float) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath, but I'm really curios why the other approach doesn't work can someone explain why?
THX
[CODE FOR HELP]
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) { // Initialization code
NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
if ([arrayOfViews count] < 1) { return nil; }
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) { return nil; }
self = [arrayOfViews objectAtIndex:0];
[self.answerTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:AnswerCellIdentifier];
}
return self;
}
- (void) layoutSubviews {
[super layoutSubviews];
self.answerTableView.rowHeight = self.answerTableView.bounds.size.height / self.quizSection.answers.count; //WRONG
}
- (void) updateConstraints {
[super updateConstraints];
self.answerTableView.rowHeight = self.answerTableView.bounds.size.height / self.quizSection.answers.count; //WRONG
}
#pragma mark -
#pragma mark custom getter/setter
- (void) setQuizSection:(QuizSection *)quizSection {
if (_quizSection == quizSection) {
return;
}
_quizSection = quizSection;
//Set data
self.questionLabel.text = _quizSection.question[KEY_TEXT];
self.answerTableView.delegate = self;
self.answerTableView.dataSource = self;
}
#pragma mark -
#pragma mark TableViewDelegate TableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.quizSection.answers.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:AnswerCellIdentifier];
NSDictionary * answerDict = self.quizSection.answers[indexPath.row];
cell.textLabel.text = answerDict[KEY_TEXT];
return cell;
}