Here are my 2 NSTableCellViews:
The 1st is bigger than the 2nd (this one is used when the user is searching the tableview and there are no results) but when i run my app the 2nd gets the size of the 1st:
Why is this happening? Here's my part of the code
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
if (noResults){
return 1;
}else{
return [array count];
}
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
if (noResults){
NSTableCellView *result = [tableView makeViewWithIdentifier:#"NoResults" owner:self];
result.textField.stringValue = [NSString stringWithFormat:#"No results for \"%#\"", _searchTXT.stringValue];
return result;
}else{
SearchTableCell *result = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
result.textField.stringValue = #"Name";
result.textField2.stringValue = #"Last Name";
return result;
}
}
You need to implement the tableView:heightForRowAtIndexPath: method. Otherwise the cell will all be the height of the table views rowHeight property.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (noResults){
// return NSTableCellView height here;
}else{
// return SearchTableCell height here;
}
}
Hope this helps you.
For a view based NSOutlineView, implement the delegate method outlineView:heightOfRowByItem: to return the desired row height.
To avoid constants within your code, consider determining the height from the associated view:
- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
NSView* view = [self outlineView:outlineView viewForTableColumn:nil item:item];
return (view ? NSHeight(view.frame) : outlineView.rowHeight);
}
Related
I am building an app for downloading files from server, I have a NSTableViewController with custom cell with progess indicator in it, but i have a problem with drawing cells for each row/downloadable file. When i start downloading it seems the progress cell is just a copy of a first created cell and progress updating is a bit fuzzy and when i select multiple rows to download it displays only one progress on the last selected row. If anyone can help telling me where I did wrong?
Here is the code for drawing the cells in -(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row method:
if([identifier isEqualToString:#"status"]) {
if ([selectedIndexes count] >0) {
for (indexNumber in selectedIndexes) {
ProgressBarCell *statusCell = [tableView makeViewWithIdentifier:#"StatusCell" owner:self];
progressCellArray = [self populateArrayOfProgressBarCells:selectedIndexes with:statusCell];
if ([indexNumber integerValue] == row) {
if (downloadTask != nil) {
[statusCell.imageView
setImage:[NSImage imageNamed:#"downloading"]];
[statusCell.textField setStringValue:#"downloading"];
for (int i = 0; i < statusCell.progressBar.maxValue; i++) {
[statusCell.progressBar setDoubleValue:[self getProgressPercentageForRowIndex:[indexNumber integerValue]]];
[statusCell.progressBar displayIfNeeded];
[statusCell.progressBar setUsesThreadedAnimation:YES];
[statusCell.progressBar
startAnimation:statusCell.progressBar];
}
if (statusCell.progressBar.doubleValue == statusCell.progressBar.maxValue) {
[statusCell.textField setStringValue:#"downloaded"];
[statusCell.imageView setImage:[NSImage imageNamed:#"finishedDownload"]];
}
return statusCell;
}
return notSelectedStatusCell = statusCell;
}
}
}
return notSelectedStatusCell;
}
tableView:viewForTableColumn:row: doesn't draw. NSTableView asks the delegate for a cell view by calling tableView:viewForTableColumn:row:. The cell view is added as subview of the table view. Invisible cell views are reused. You can't return the same cell view for multiple rows. tableView:viewForTableColumn:row: should return a cell view for the row and do nothing else. The values of the subviews of the cell view are set. Example:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
DownloadItem *item = self.data[row];
if ([tableColumn.identifier isEqualToString:#"status"]) {
StatusCellView *statusCell = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
statusCell.progressIndicator.doubleValue = item.progress;
if (item.finished) {
statusCell.textField.stringValue = #"downloaded";
statusCell.imageView.image = [NSImage imageNamed:NSImageNameMenuOnStateTemplate];
}
else
if (item.downloading) {
statusCell.textField.stringValue = #"downloading";
statusCell.imageView.image = [NSImage imageNamed:NSImageNameMenuMixedStateTemplate];
}
else {
statusCell.textField.stringValue = #"paused";
statusCell.imageView.image = nil;
}
return statusCell;
}
else {
NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
cellView.textField.stringValue = item.title;
return cellView;
}
return nil;
}
Reload the cell when the values change and the cell view should be updated. Example:
NSInteger row = [self.data indexOfObjectIdenticalTo:item];
NSInteger column = [self.tableView columnWithIdentifier:#"status"];
[self.tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row] columnIndexes:[NSIndexSet indexSetWithIndex:column]];
I have strange problem with tableViewHeader which I resize on scroll.
After first scroll to top, I have space between tableHeader and cells and after each next scroll, space increasing.
In tableViewHeader custom class, after scrolling I change height and return back, then resetting it, so UITableView will update frame size.
Also I have 0.1f height for first section view, UITableViewController,
self.automaticallyAdjustsScrollViewInsets = NO;
I double checked that tableViewHeader have right height.
I have tried many solutions, but nothing works for me.
What happens? Who is adding extra space and why?
EDIT: Table delegate and data source methods
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 0.001;
}
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 0.001;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 0) {
return [self nameCell];
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 0) {
return 60;
}
return 0;
}
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0) {
UIView* view = [[UIView alloc] initWithFrame: CGRectMake(0.0f, 0.0f, self.tableView.frame.size.width, 0.001f)];
return view;
}
return nil;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == self.tableView) {
[_tableHeader didScroll:scrollView.contentOffset];
}
}
Found a solution.
First of all, don't set tableViewHeader in custom class. Do it in controller where tableView inserted.
Second: wrap tableViewHeader set in beginUpdates, endUpdates.
I don't know how "updates" for cells used with tableViewHeader, but it works
i fixed that by putting the header(auto layout) into a wrap view which is a fixed UIView as subview. the gap will be gone.
self.header = [[NSBundle mainBundle] loadNibNamed:#"FriendDetailHeaderView"
owner:nil
options:nil][0];
self.header.frame = CGRectMake(0, 0, ScreenWidth, ScreenWidth/16*9+25);
UIView *aView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenWidth/16*9+25)];
aView.backgroundColor = [UIColor blackColor];
[aView addSubview:self.header];
self.tableView.tableHeaderView = aView;
the auto layout tableViewHeader sometimes can not work out. but in my previous project, set the auto layout view to tableView.tableViewHeader it works perfectly
I have a NSTableView with 10 cells. They are all the same cells and I want to reuse them, however I can't seem to get the table view to do so.
Currently, each time a new cell is needed, the delegate cannot seem to find the previous cell with the same identifier and has to recreate it.
Below is my code, any suggestions on what I might be doing wrong?
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 10;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
static NSString *cellIdentifier = #"Name";
NSTableCellView *cellView = [tableView makeViewWithIdentifier:cellIdentifier owner:self];
if (cellView == nil)
{
NSLog(#"A cell");
NSRect cellFrame = [_scrollView.contentView bounds];
cellFrame.size.height = 65;
cellView = [[NSTableCellView alloc] initWithFrame:cellFrame];
[cellView setIdentifier:cellIdentifier];
}
return cellView;
}
I did some testing and noticed that the table will continually create new cells until the table cannot display all cells at the same time.
At this point, the table will reuse the cells that are not visible.
I am making an settings screen in which you can select stations via a uisearchbar. I have a sectioned tableview, with the first letter of a station as the header and every station is categorized by it's first letter. So far so good.
I habe 2 NSMutableArray's with, per section, the stations. One is the unfiltered array (Which I use when I don't have it filtered) and the other one, when I am searching for something. (I do this via a predicate). On every keypress on the keyboard I do a [self.tableView reloadData]; this works, HOWEVER the scrollview stays too long! So you can scroll way past how many results are actually in the selected array. This causes a crash, because it's trying to get objects that don't exist.
So it seems like the tableview isn't counting the array right or something?
Is anyone familiar with this problem?
Here is some code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (self.searching) {
return [self.tableFilterd count];
} else {
return [self.tableData count];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Rows for section");
// Return the number of rows in the section.
if (self.searching) {
NSLog(#"Editing section: %i, count %i", section, [[self.tableFilterd objectAtIndex:section] count]);
return [[self.tableFilterd objectAtIndex:section] count];
} else {
NSLog(#"Not editing");
return [[self.tableData objectAtIndex:section] count];
}
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
SettingsHeaderCell *cell = [[[SettingsHeaderCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"HeaderCell"] autorelease];
cell.labelLetter.text = [[self.tableLetters objectAtIndex:section] capitalizedString];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 40;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 52;
}
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
SettingsCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[SettingsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (self.searching) {
StationObject *object = (StationObject *)[[self.tableFilterd objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
[cell setStationObject:object];
} else {
StationObject *object = (StationObject *)[[self.tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
[cell setStationObject:object];
}
return cell;
}
You might have solved this by now but I suspect you aren't emptying either arrays. In the method:
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
//Remove all objects first
[self.tableFiltered removeAllObjects];
[self.tableData removeAllObjects];
Also you only need to call [self.tableView reloadData]; in textDidChange, not in the other three methods. Hope this helps.
I am making an application with a UITableView that has a few sections (2), and when I run, the table view has this annoying gray index bar on the side, like the one in the "iPod" application, that has but 2 options in it. My question is, how do I hide the "index bar," because it is an unnecessary waste of space?
Example:
Code snippets:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [sections count];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return sections;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return 2;
}
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [sections objectAtIndex:section];
}
// 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];
}
// Configure the cell.
cell.textLabel.text = [content objectAtIndex:(indexPath.row + [[sectionAmounts objectAtIndex:indexPath.section] intValue])];
tableView.showsVerticalScrollIndicator = NO;
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
content = [NSArray arrayWithObjects:#"Sphere", #"Cylinder", #"Circle", nil];
sections = [NSArray arrayWithObjects:#"3d", #"2d", nil];
sectionAmounts = [NSArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:2], nil]; //Second number is objects in first section... odd huh?
self.tableView.showsVerticalScrollIndicator = NO;
[content retain];
[sections retain];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
(Mind my odd comments...)
HiGuy
I tried this, and it didn't work for me.
so i went through the table view properties, and got this.
self.tableView.showsVerticalScrollIndicator = NO;
works like a charm.
*for any one who wants to do this in the future.
That "scroll bar" is your index bar, assuming you're talking about the giant grey thing.
Return nil from sectionIndexTitlesForTableView: and it'll go away.
I had similar issue, however had to deal with my header/footer. Essentially I just removed the following methods
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #" "; //#"Top";
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
return #" "; //#"Bottom";
}
You just use the below code and gray bar will go....
tableViewBrowse.sectionIndexTrackingBackgroundColor = [UIColor clearColor];
Use sectionIndexBackgroundColor property of UITableView to set the color of index bar to clear color as hiding scroll bar is going to hide the indexes as well.
Add it to your viewDidLoad: as following:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor]; //Replace it with your desired color
}