#All Hello
Its quite interesting problem i have.
Actually i have subviews which can be larger in height then cell height itself (Its required for my design). For example cell "A" height is 40 while subview height= 70.
I can show larger subview but when the cell A goes off the screen (i scroll to top) then its subview also disappear (Obvious) result. But that gives undesired effect as larger subview which before extends to cell say "B" beneath container cell suddenly disappear.
I have tried to set cell background as transparent in willDisplayCell delegate method but no luck.
Below is my related method if anyone wants to see
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSArray *newArray = [[dataDictionary allKeys] sortedArrayUsingSelector: #selector(compare:)];
[cell.contentView addSubview: [[[dataDictionary objectForKey:[newArray objectAtIndex:indexPath.section]] objectForKey:#"DayView"] objectAtIndex:indexPath.row]];
return cell;
}
Pardon me if i am not very much clear but this is best i can explain my situation.
I want to show views like http://postimg.org/image/e5ok5hybl/ image.
If you must do this, you can use a simple trick:
Move the y-origin of the table to a negative value equal to the amount your view extends below the cell, e.g. origin -30px.
Make the table height taller by the same amount, i.e. make it 30px taller.
Increase the top content inset of the table by the same amount, i.e. increase by 30px.
What you've effectively done is extend the table view off-screen while maintaining the original position of the cells. Since the table view extends off-screen, the cell will not be dequeued until the part that extends below the cell has scrolled off screen.
Here is a sample project demonstrating the trick.
Related
I have an old objective c project which has an UITableView. All the UILabels in each cells have been created by code. This is my cellForRowAtIndex
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *metadataListTableIdentifier = #"MetadataListTableViewCell";
MetadataTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:metadataListTableIdentifier];
NSMutableDictionary *dict = [theListData objectAtIndex:indexPath.row];
[MetrixListScreenManager setCellDataDictionary:dict];
if (cell == nil || cellReloadCount <= cellReloadLimit) {
cell = [MetrixListScreenManager generateCellForListScreen:self withReuseIdentifier:metadataListTableIdentifier andScreenId:self.screenId];
cellReloadCount++;
}
[SkinApplicationUITableViewController applySkinColorToRelevantControlsForCell:cell];
[MetrixListScreenManager populateCellDataForListScreenId:self.screenId usingCell:cell andDataRow:dict];
return cell;
}
According to this implementation, in generateCellForListScreen method, all the labels are creating by giving fixed height and width. Then in populateCellDataForListScreenId method all the texts are setting for previously created UILabels. Now we want to make to adjust cell height according to the content height. So what I did was in generate cell method I got the text height and replace the predefined height with that. But my problem is when I scroll some UILabel's height getting increased and rest of the UILabels are going beyond the cell bottom margin. What is the proper way to do this? Please help me.
Thanks
I am trying to add the vibrancy effect to the text label of my table view cell and it sort of works, but not exactly right.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
NSDictionary *jobDictionary = [self.jobs objectAtIndex:[indexPath row]];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"UITableViewCell"];
}
if (cell) {
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.text = [jobDictionary objectForKey:#"job"];
UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
UIVisualEffectView *blurView = [[UIVisualEffectView alloc]initWithEffect:blur];
blurView.frame = cell.bounds;
[cell addSubview:blurView];
UIVisualEffectView *vibrantView = [[UIVisualEffectView alloc]initWithEffect:[UIVibrancyEffect effectForBlurEffect:blur]];
vibrantView.frame = blurView.bounds;
[vibrantView.contentView addSubview:cell.textLabel];
[blurView.contentView addSubview:vibrantView];
}
return cell;
}
I think I see two major issues with your code. The first issue seems to be the fact that cells in cellForRowAtIndexPath assume a width of 320 when dequeued for display on an iPhone 4 or 5 screen size. If that screen shot is taken from a 6 or 6+, this would explain the weird gap. Somewhere after this method, the cell resizes to accommodate the full width of the table. That means that when you set blurView.frame = cell.bounds, the bounds at this point are actually too narrow. Hypothetically you could fix this by moving that code into the following method with one major caveat.
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
While adding your blur view here should get you the proper frame, adding a subview in either of these methods will lead to major problems as the cell is recycled. Every time that cell is dequeued, a new subview will get added to it and they will continue to stack up over time. This will cause visual issues if they aren't totally opaque and it will also leave the potential for your cell to require a HUGE amount of memory because you could in theory be stacking hundreds of subviews on a cell as the table scrolls.
I think the best solution to your problem would be to subclass UITableViewCell and add the view on -initWithStyle:reuseIdentifier:. There you can also constrain that view to top, bottom, leading, and trailing of the superview to ensure it will always resize correctly. An alternative is setting the frame of the subview in -layoutSubviews of your cell subclass.
Doing this ensures the view is added only once and the frame will be what you expect.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
Movie *movie = [self.movies objectAtIndex:indexPath.row];
cell.title.text = movie.title;
cell.subtitle.text = movie.subtitle;
cell.subtitle.numberOfLines = 0;
[cell.subtitle sizeToFit];
return cell;
}
I am calling reloadData from two places. One is from the end of a loadInitialData function, which is called from viewDidLoad.
A second one is being called from viewDidAppear, although this is inconsequential to my problem, because it existed before it and exists without it.
I initially load 3 rows of sample data, with titles and subtitles. Now what happens is my subtitle text is vertically centered when this window first launches. If I grab the table and scroll is high up, all of a sudden my [cell.subtitle sizeToFit] goes into action, and my text goes to the top vertically, which is desired.
So my issue is... why is the text vertically centered from the beginning? reloadData doesn't work either. When I return from adding a new row, all rows but the newly added row are vertically aligned to top as they should. The new row is incorrectly vertically centered.
Why doesn't this work? Everything seems good. New data is added etc. Via NSLog statements, I have verified numberOfRowsInSection is immediately called after reloadData is called.
So why does the aligning of the text vertically to the top not work?
Thanks!
This is probably because the UITableViewCell has not yet been layed out and so it does not have a size yet. Try doing the sizeToFit in this UITableViewDelegate method
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
I am not sure this will work, but it worth trying.
Add [cell setNeedsLayout]; before you return the cell so it will layout the cell before presentation.
So I've made some custom table view cells and they draw correctly and look great, however once I scroll past the edge of the visible cells they start being reused, which is fine, except that when I scroll back the reused cells are still shown and don't redraw. Specifically all the cells look the same except for the top-most cell.
Pictures detailing the occurrence:
How I have this coded up, is when the cells get made if the indexPath.row is greater than 0 add an "overlap effect" which is just a gradient on a uiview placed underneath the custom drawing on the UITableViewCell's contentView.
This is how I add the overlap effect in the UITableViewController's tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"APostCell";
PostCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
CustomPost *aPost = [self.posts objectAtIndex:indexPath.row];
if (indexPath.row > 0) {
[cell addOverlap];
}
cell.postDateLabel.text = [aPost datePostedAsString];
return cell;
}
How would I implement this [cell removeOverlap]?
Try this
if (indexPath.row == 0) {
//remove overlap here
} else {
[cell addOverlap];
}
beacuse, except 1st cell all have overlap.On scrolling the reused cell have the overlap. So for first cell remove the overlap if present.
So after I posted the question I figured it out and, since I had the question and had previously not found any information on the subject figured I would share.
So whenever
PostCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]
is called, the table view either creates a new cell or reuses an old one. When a new cell is created and it is not the top cell (indexPath.row == 0) it adds the overlap to the UITableViewCell. And if it reuses the cell, that method still gets called, regardless what cell is being reused. So naturally once the cell created at the top is reused, the gradient view still gets added to cell.contentView and it stays there even when I'm reusing for the topmost cell again.
In fact adding the overlap view in this way will stack multiple overlap views into the same cell.
So what has to be done (if you intend to customize the cell appearance this way) is to remove the added views before each reuse of the cell. So you have to overwrite the custom tableviewcell's prepareForReuse method and do just that like so.
- (void) prepareForReuse {
[super prepareForReuse];
[self removeOverlap];
}
Be SURE the cell has the overlap view otherwise your app will break by trying to remove views not there. so have something like
- (void) removeOverlap {
if ([self.contentView.subviews count] > 1) {
//This method works based on the assumption [cell addOverlap] adds new view
//underneath existing views - like [self.contentView insertSubview:overlappedView atIndex:0];
[[self.contentView.subviews objectAtIndex:0] removeFromSuperview];
}
}
I am trying to use a UITableView with a .xib file. I have done it in the past with storyboards, where you declare a reuse id in a dynamic prototype. I have this code inside the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath function which should work:
NSString *ReuseId = #"DefaultCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ReuseId];
if (cell == nil) {
NSLog(#"cell == nil");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ReuseId];
}
However, when I run this, instead of printing cell == nil once it prints it for every row.
Why??
Thanks.
How many rows do you have? It should create up to to 11 or 12 at first on iPhone. Depending on the height of the tableview and the heights of the cells.
So if you have less rows than cells fit on the view, cell reuse will never happen and is not needed.
if (cell == nil) {
NSLog(#"cell == nil");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ReuseId];
} else {
NSLog(#"We have a reused cell!");
}
try to repeat your rows several times and scroll slowly. Now every time you are just about to scroll the first pixel of a new cell on the view, it should print "We have a reused cell!".
The first time when you open table view there will be no cells to reuse because all of them will be actually in use. Cells start being reused when you start scrolling the table and some cells start disappearing from the top.
update
Let's say you have a table view that can partially display 6 rows (5.5 by height). When UITableViewController loads the table with the cells, it creates 6 cell instances because all of them must be displayed at the same time.
When you start scrolling and the first cell is hidden, it gets added to reusable cell set. That's when creating 8th cell (because 7th will be created newly, 'cause 1st one will still be visible by half height) the first one will be reused.