I have a UITableView with UITableViewCells that contains a MKMapView.
The Problem: if the table cell ever gets selected, then move the map, you see the mapview is all white and you only see the "Legal" label.
Has anyone experienced this before?
Here is the entire code:
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.table.backgroundColor = [UIColor clearColor];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 70;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 220, 70)];
MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.01);
CLLocationCoordinate2D logCord = CLLocationCoordinate2DMake(47.606, -122.332);
MKCoordinateRegion region = MKCoordinateRegionMake(logCord, span);
[map setRegion:region animated:NO];
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"aaaa"];
[cell.contentView addSubview:map];
return cell;
}
I have experienced this.
In my case, the map becomes white like this if its tableView or cell has a backgroundColor and its cell has either a gray or blue selection style and the cell is recycled through dequeue.
I think that the map won't turn white like this if
cell.selectionStyle = UITableViewCellSelectionStyleNone;
I have experienced this as well.
My map had white background when it was touched after pushing/popping another detail view controller. TableView has no color/background configured yet, everything is default.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
...actually helped.
Related
Ever since the new iOS 11 update, I have an app that will show blank tableview rows on the simulator and device. Even the row separators will not show for any of the rows that are supposed to be there. If I change the simulator to an older iOS version, the rows will show fine. No changes to code or storyboard.
The rows still have the data, meaning I can tap on one of the blank rows and it will execute the code and contain the information I was expecting.
It appears that other scenes that I have where the tableview is placed on a view and I don't use the built in text label work fine. Just this tableview class using the built in text label.
Here is my code for the tableview class...
#interface BunkPickTableViewController ()
#end
#implementation BunkPickTableViewController
#synthesize appDelegate, delegate, bunkPassedValue;
- (void)viewDidLoad {
[super viewDidLoad];
UIView *backgroundView = [[UIView alloc] initWithFrame:self.view.bounds];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
CAGradientLayer *bgLayer = [BackgroundLayer tanGradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];
self.tableView.backgroundView = backgroundView;
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
self.title = #"Bunk Codes";
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[self navigationController] setNavigationBarHidden:NO animated:NO];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [appDelegate.bunkArray count];
}
- (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];
cell.textLabel.textAlignment = NSTextAlignmentCenter;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.backgroundColor = [UIColor clearColor];
}
Bunk *bunkObj = [appDelegate.bunkArray objectAtIndex:indexPath.row];
cell.textLabel.text = bunkObj.bunkId;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
Bunk *bunkObj = [appDelegate.bunkArray objectAtIndex:indexPath.row];
[delegate dismissBunkPop:bunkObj.bunkId];
[self.navigationController popViewControllerAnimated:YES];
}
#end
TableView Settings Image
I had this issue as well with IOS 11 showing blank cells.. but in IOS 10 was fine. My issue was that I was using a gradient which for whatever reason stopped the cell text from being shown. Removing the gradient resolved the blank cells.
This is probably because your tableView gets under bgLayer.
The problem seems to be in self.view.layer insertSublayer:bgLayer atIndex:0. I was using insertSubview at index 0 and I had the same problem. This is probably a bug in iOS 11 - if your tableView is defined in storyboard, it always gets pushed to back.
The best solution is to put the bgLayer inside the tableView.backgroundView.
NOTE:
You could also solve it by calling sendSubviewToBack on the bgLayer in viewDidAppear, but unfortunetaly, tableview cells are moving to back on every tableview reloaddata, so it is not a good solution.
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.tableView.bounds;
gradient.colors = #[(id)[UIColor blackColor].CGColor, (id)[UIColor
grayColor].CGColor, (id)[UIColor
lightGrayColor].CGColor];
UIView *bgView = [[UIView alloc]
initWithFrame:self.tableView.bounds];
[self setBackgroundView:bgView];
[bgView.layer insertSublayer:gradient atIndex:0];
[self.tableView setBackgroundView:bgView];
Setting gradient layer for tableview's background view solved the problem for me. Upto iOS 10 we can directly insert sublayer to tableView but in iOS 11 layer should be inserted to UITableVIew's background view only.
In tandem with the aforementioned tableview subviews manipulation, this problem can also occur if your project existed pre Xcode 9 and you then checked Use Safe Area Layout Guides on your storyboard. Try unchecking that and see if it works.
I'm populating data into an array which is then being inserted into a UITableView. However once the screen gets filled, new cells won't show up because they get appended to the bottom. Is there a way to have it auto-scroll to the bottom upon adding an item? Also, the scrolling works but it isn't ideal. For example, to get to the last item, the user has to scroll and hold down that gesture to make the item appear. IE. My UITableView can hold up to 17 items in its view. After 17 the user can then scroll, however they would not be able to select item 18 because they would have to hold down their scroll gesture. In order to select item 18 they'd have to add say another 10 items.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
// Return the number of rows in the section.
// Usually the number of items in your array (the one that holds your list)
return [_items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//Where we configure the cell in each row
static NSString *CellIdentifier = #"trap";
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell... setting the text of our cell's label
cell.textLabel.text = [_items objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"test");
}
If you have to hold your drag gesture to show 18rd item, I think the problem is your tableView's height didn't set properly. Try to set height to your visible frame height.
When the tableView was loaded,you can set contentOffset manually because you can get the tableViewContentSize this time.
You can not show the last item of the table.
The problem most likely is that your tableview’s height is bigger than
you screen size. Or it can be auto layout issue. Try to make your tableview's height smaller.
Is there a way to have it auto-scroll to the bottom upon adding an item?
[self.items addObject:[NSString stringWithFormat:#"Trawl %d", count]];
[self.tableView reloadData];
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:self.item.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]
The following is my whole test Controller
#interface DPCalendarTestCreateEventViewController ()<UITableViewDelegate, UITableViewDataSource, DPCalendarTestOptionsCellDelegate>
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) NSMutableArray *items;
#end
#implementation DPCalendarTestCreateEventViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.items = #[#"TEST", #"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST",#"TEST"].mutableCopy;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneButtonSelected)];
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
self.tableView.dataSource = self;
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.tableView];
}
- (void) doneButtonSelected{
[self.items addObject:[NSString stringWithFormat:#"Trawl %d", self.items.count]];
[self.tableView reloadData];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:self.items.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//Where we configure the cell in each row
static NSString *CellIdentifier = #"trap";
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell... setting the text of our cell's label
cell.textLabel.text = [_items objectAtIndex:indexPath.row];
return cell;
}
#end
I need to display a centered 200x150 image in a UITableViewCell. I was able to add the image to a standard cell type (it shrunk it to fit - that wasn't working). I then tried redrawing it by setting the bounds and frame for the image (this caused overlap between my image and the other rows).
I have a custom class inheriting from UITableViewCell:
#import "WCPictureViewCell.h"
#implementation WCPictureViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.frame = CGRectMake(5,5,210,160);
self.bounds = CGRectMake(5,5,210,160);
self.imageView.frame = CGRectMake(0,0,200,150);
self.imageView.bounds = CGRectMake(0,0,200,150);
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
This code produces picture overlap with the rest of my table:
Here is my tableView:cellForRowAtIndexPath: method in my controller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
if(cellPropertyMap>0) {
static NSString *CellIdentifier = #"DetailCell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
[[cell textLabel] setText: (NSString *)[[self displayLabels]objectAtIndex:cellPropertyMap]];
[[cell detailTextLabel] setText: (NSString *)[[self displayData]objectAtIndex:cellPropertyMap++]];
} else {
static NSString *CellIdentifier = #"PictureCell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//if(cell == nil) {
//}
// Configure the cell...
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: [cat friendlyURLPath]]];
cell.imageView.image = [UIImage imageWithData: imageData];
cellPropertyMap++;
return cell;
}
return cell;
}
How do I force my table cells to respect eachother's sizes and not overlap? How do I get my image to center?
You need to use
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath)
{
// add logic to determine if this indexPath is an image...
if (indexPath.row == 0) // first row in a section is an image?
return (150.0f); // this row is an image
else
return (44.0f); // this is a standard data row
}
to return the correct height of your TableView row.
Second step is to get the image to center, there are various techniques. Try
UIImageView *yourImage = ...;
// set frame and auto-resizing mask
yourImage.frame = CGRectMake(tableView.bounds.size.width / 2) - (yourImage.size.width / 2), 0, yourImage.size.width, yourImage.size.height);
yourImage.autoResizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
// add UIImage to the cell contentView
[cell.contentView addSubview:yourImage];
don't set the cell.imageView property, which defines a left justified image in the cell.
Lastly, and off-topic from your question, you should really consider lazy-loading the images, using initWithContentsOfURL on the UI thread will not yield a good user experience.
I have a view that adds another view on top in this manner:
- (void)showAreaEditView {
NSLog(#"SHOWING AREA EDITOR VIEW");
if (self.thisAreaEditorView == nil) {
// Create View
AreaEditorView *tmpViewController = [[AreaEditorView alloc] initWithNibName:#"AreaEditorView" bundle:nil];
self.thisAreaEditorView = tmpViewController;
[tmpViewController release];
// Hide the back button
self.thisAreaEditorView.navigationItem.hidesBackButton = YES;
}
self.thisAreaEditorView.myInspectionID = self.myInspectionID;
self.thisAreaEditorView.loggedIn = loggedIn;
self.thisAreaEditorView.loggedInGroup = loggedInGroup;
// Slide view up
[self.view addSubview:thisAreaEditorView.view];
CGRect endFrame = CGRectMake(self.view.frame.size.width/2 - thisAreaEditorView.view.frame.size.width/2,
self.view.frame.size.height/2 - thisAreaEditorView.view.frame.size.height/2,
thisAreaEditorView.view.frame.size.width,
thisAreaEditorView.view.frame.size.height);
CGRect startFrame = endFrame; // offscreen source
// new view starts off bottom of screen
startFrame.origin.y += self.view.frame.size.height;
self.thisAreaEditorView.view.frame = startFrame;
// start the slide up animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.6];
thisAreaEditorView.view.frame = endFrame; // slide in
[UIView commitAnimations];
}
I'm sure you can just ignore the slide part, I feel the addSubview is relevant.
Then in thisAreaEditor I have the view with the table and buttons and such. UITableView delegate/datasource is going to File's Owner as normal.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"numberOfRowsInSection returning %d", [tableData count]);
[tableData count];
}
This function numberOfRowsInSection returns 4
- (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];
}
// Configure the cell...
NSString *thisText = [tableData objectAtIndex:indexPath.row];
cell.textLabel.text = thisText;
NSLog(#"looking at cell %d text:%#", indexPath.row, thisText);
return cell;
}
But cellForRowAtIndexPath never gets called.
I'm at a loss here, I have no idea how it can seem to work fine but one of the delegate functions simply not be called.
I have tried [bigTable reloadData] and so on, the table just never gets populated and no logs from the function output.
Thanks in advance.
You might have just edited this out, if so I'm sorry, but it looks like you forgot to return tableData's count.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"numberOfRowsInSection returning %d", [tableData count]);
return [tableData count];
}
It seems you're missing UITableViewDelegate.
If you're using Interface Builder, right click the table view outlet and drag both delegate and datasource to File's Owner.
And if not using Interface Builder add this where you init your tableView
bigTable.delegate = self;
bigTable.dataSource = self;
Remember to import the UITableViewDelegate and UITableViewDataSource protocols, just as Srikar says.
Hope this is to any help.
Cheers!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is also not called when the tableview's height is not set.
Maybe you did not set the tableView delegate as self or the datasource as self. Add this code & see if it works now -
[tableView setDelegate:self];
[tableView setDataSource:self];
Also in your header file inherit these delegates - UITableViewDelegate, UITableViewDataSource
#interface yourViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
Hope this helps.
This is a older link, but I wanted to update this with putting info on how I resolved this issue.
For me the issue was the Array to populate the table had 0 rows so cellForRowAtIndexPath was never called.
Make sure that the Array you are using to populate the table has data in it.
I have looked around to find a solution for setting the background color of the accessoryView to the same background color as the cell´s contentView.
cell.contentView.backgroundColor = [UIColor colorWithRed:178/255.f green:14/255.f blue:12/255.f alpha:0.05];
cell.accessoryView.backgroundColor =[UIColor colorWithRed:178/255.f green:14/255.f blue:12/255.f alpha:0.05];
There is a solution that works but only let me use one color for all cells.
cell.contentView.superView.backgroundColor = [UIColor redColor];
Is the only solution to not use the accessoryView and use an image instead?
Thanks!
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [UIColor greenColor];
}
Using this UITableViewDelegate method, you can set the color of cells to different colors. Note that Apple explicitly advise you to make changes to the backgroundColor property within the tableView:willDisplayCell:ForRowAtIndexPath: method in the docs, which state:
If you want to change the background color of a cell, do so in the tableView:willDisplayCell:forRowAtIndexPath: method of your table view delegate
Indeed, in iOS 6, changes to the property from anywhere else (like the tableView:cellForRowAtIndexPath: method) would have no effect at all. That no longer seems to be the case in iOS 7, but Apple's advice to modify the property from within tableView:willDisplayCell:ForRowAtIndexPath: remains (without any explanation).
For alternating colors, do something like this example:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row % 2) {
cell.backgroundColor = [UIColor yellowColor];
} else {
cell.backgroundColor = [UIColor redColor];
}
}
I struggled with this one for a little while too and resorted to creating a custom image with the accessory. But I just found this solution that works well and doesn't require a custom image. The trick is to change the cell's backgroundView color not the backgroundColor.
UIView *myView = [[UIView alloc] init];
if (indexPath.row % 2) {
myView.backgroundColor = [UIColor whiteColor];
} else {
myView.backgroundColor = [UIColor blackColor];
}
cell.backgroundView = myView;
No need to change the accessoryView or contentView background colors. They'll follow automatically.
Note for 2014. Very typically you wold use -(void)setSelected:(BOOL)selected animated:(BOOL)animated
So, you'd have a custom cell class, and you'd set the colours for the normal/selected like this...
HappyCell.h
#interface HappyCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *mainLabel;
etc...
#end
HappyCell.m
#implementation HappyCell
-(id)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
}
return self;
}
-(void)awakeFromNib
{
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if(selected)
{
self.backgroundColor = [UIColor redColor];
.. other setup for selected cell
}
else
{
self.backgroundColor = [UIColor yellowColor];
.. other setup for normal unselected cell
}
}
#end
// to help beginners.......
// in your table view class, you'd be doing this...
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return yourDataArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tv
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger thisRow = indexPath.row;
ContentsCell *cell = [tv
dequeueReusableCellWithIdentifier:#"cellName"
forIndexPath:indexPath];
// "cellName" must be typed in on the cell, the storyboard
// it's the "identifier", NOT NOT NOT the restorationID
[cell setupForNumber: thisRow];
cell.mainLabel.text = yourDataArray[ thisRow ][#"whatever"];
cell.otherLabel.text = yourDataArray[ thisRow ][#"whatever"];
return cell;
}
hope it helps someone.
This worked for me:
cell.contentView.backgroundColor = [UIColor darkGreyColor];
For all lines with the same color
cell.backgroundColor = [UIColor colorWithRed:6.0/255.0 green:122.0/255.0 blue:145.0/255.0 alpha:1.0f];
For 2 colors
cell.backgroundColor = [UIColor colorWithRed:6.0/255.0 green:122.0/255.0 blue:145.0/255.0 alpha:1.0f];
if ((cell.backgroundColor = (indexPath.row % 2 == 0 ? [UIColor colorWithRed:6.0/255.0 green:122.0/255.0 blue:145.0/255.0 alpha:1.0f] : [UIColor colorWithRed:2.0/255.0 green:68.0/255.0 blue:80.0/255.0 alpha:1.0f]))){
cell.textLabel.textColor = [UIColor whiteColor];
}
For anyone else who might stumble on this and wants to set their UITableViewCell background to a pattern or texture rather than a solid color, you can do so like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"pattern.png"]];
}
The best option to have different backgrounds and what not would probably be to make your own TableViewCell implementation, in there you can put the logic to show whatever you want based on content or index etc.