How to add a scrollable NSTableView programmatically - objective-c

I'm trying to add a tableview to a view in code instead of using Interface Builder and unfortunately it's causing some problems =(
Here's an example of how I'm doing it now.
NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:someRect];
NSTableView *tableView = [[NSTableView alloc] initWithFrame: scrollView.bounds];
resultsTableView.dataSource = self;
resultsScrollView.documentView = tableView;
[someView addSubview: scrollView];
So basically I'm just putting the tableView inside the scrollView (because that's what IB is doing) and then adding the latter as a subview of the someView. The result is that a tableView appears - but the no data is shown within the tableView. Debugging shows that the dataSource is being asked for how many rows are in the tableView but the method:
tableView:objectValueForTableColumn:row:
is never being called. I suspect that this is because of my way of creating the tableView.
I've tried google but no luck and the "Introduction to Table Views Programming Guide" on macdevcenter wasn't helpful either. What am I missing?
Thanks in advance...

I created the default sample project and then did the following:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSRect scrollFrame = NSMakeRect( 10, 10, 300, 300 );
NSScrollView* scrollView = [[[NSScrollView alloc] initWithFrame:scrollFrame] autorelease];
[scrollView setBorderType:NSBezelBorder];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:YES];
[scrollView setAutohidesScrollers:NO];
NSRect clipViewBounds = [[scrollView contentView] bounds];
NSTableView* tableView = [[[NSTableView alloc] initWithFrame:clipViewBounds] autorelease];
NSTableColumn* firstColumn = [[[NSTableColumn alloc] initWithIdentifier:#"firstColumn"] autorelease];
[[firstColumn headerCell] setStringValue:#"First Column"];
[tableView addTableColumn:firstColumn];
NSTableColumn* secondColumn = [[[NSTableColumn alloc] initWithIdentifier:#"secondColumn"] autorelease];
[[secondColumn headerCell] setStringValue:#"Second Column"];
[tableView addTableColumn:secondColumn];
[tableView setDataSource:self];
[scrollView setDocumentView:tableView];
[[[self window] contentView] addSubview:scrollView];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return 100;
}
- (id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
NSString* cellValue = [NSString stringWithFormat:#"%# %ld", [aTableColumn identifier], (long)rowIndex];
return cellValue;
}
You can grab the sample app TableViewInCode
(Oh, to the objective-c dot syntax, just say no. :-)

The result is that a tableView appears - but the no data is shown within the tableView. Debugging shows that the dataSource is being asked for how many rows are in the tableView but the method:
tableView:objectValueForTableColumn:row:
is never being called.
It's not asking you for the object values for any columns because it doesn't have any columns. Create some NSTableColumn instances and add them to the table view.

It doesn't appear (from your sample) that you're putting the tableView inside the scrollView. Is it getting added as a subview somewhere you're not showing us?
Also, are you sure you need a separate scrollview? Doesn't tableView implement scrolling already?

Related

Can we set backgroundImage for Section in UITableview?

Can we set Background image for UITableView Section like UITableViewCell backGroundView. As per my research Its not possible & we need to customize the row like section of it.
Cane we able to get better solution apart from this.
Thanks in advance!
In case anyone are still interrested, there is actually a pretty straigt forward solution to this. UITableView will tell you the frames of each of your sections using the selector rectForSection:
Adding a backgroud image to each section would then look something like this (Somewhere in the view controller):
for(int i = 0;i < [self numberOfSectionsInTableView:self.tableView]; i++) {
UIImage *img = [[UIImage imageNamed:#"background"] resizableImageWithCapInsets:UIEdgeInsetsMake(30.0, 30.0, 40.0, 40.0) ]; //In this example the image is stretchable
UIView *borderView = [[UIImageView alloc] initWithImage:img];
CGRect section_rect = [self.tableView rectForSection:i];
borderView.frame = section_rect;
[self.tableView addSubview:borderView];
}
Just remember that if you reload the data in the tableview you would have to redo this as well.
Yes, I am doing this by following way, I think it work for you also,....
-(void)addBackgroundViewForSectionIndex:(int)tagIndex {
for (UIView * subview in tableView.subviews) {
if(subview.tag == tagIndex)
[subview removeFromSuperview];
}
CGRect sectionFrame = [tableView rectForSection:tagIndex];
UIImageView *newView = [[UIImageView alloc]initWithFrame:sectionFrame];
newView.tag = tagIndex;
[newView setImage:[UIImage imageNamed:#"image.PNG"]];
[tableView addSubview:newView];
[tableView sendSubviewToBack:newView];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [collection objectAtIndex:indexPath.row];
[self addBackgroundViewForSectionIndex:indexPath.section];
return cell;
}
Let me know if any issue,...:)
No, this is not possible using UITableView as it was intended. Section headers, as others have suggested, won't work because they'll only be visible while the header is visible. As soon as it disappears while scrolling up, the background image would disappear.
Your two options are:
Add UIImageView instances directly as subviews to the table view. Not fun, as you'll have to size and position them manually, which is kind of hard to do.
Use UICollectionView, which supports decoration views (exactly what you're looking for).
The UICollectionView method is probably better, but to be honest, either option would require a lot of work.
Swift 5 bare-bones implementation of Jesper's answer.
for sectionIndex in 0..<tableView.numberOfSections {
let backgroundView = UIView() // replace UIView with anything else you want, whether it was UIImage, nibView, etc...
backgroundView.frame = tableView.rect(forSection: sectionIndex)
tableView.addSubview(backgroundView)
}
You can set the Background for Section of TableView.
Have a look at delegate method as below:
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIImageView *bgImgView = [[[UIImageView alloc] initWithFrame:CGRectMake(0.0,0.0,tableView.bounds.size.width,40.0)] autorelease];
bgImgView.image = [UIImage imageNamed:#"yourimage.jpg"];
return bgImgView;
}
Hope this will be helpful to you.
Cheers!
table= [[UITableView alloc] initWithFrame:CGRectMake(7,0, 307, 124) style:UITableViewStylePlain];
[table setSeparatorStyle:UITableViewCellSeparatorStyleNone];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tablebg_pt12.png"]];
imageView.frame=CGRectMake(0, 0, 307, 124);
imageView.image= [UIImage imageNamed:#"tablebg_pt12.png" ];
table.backgroundView = imageView;
[imageView release];
table.delegate = self;
table.dataSource = self;
// table.backgroundColor=[UIColor clearColor];
[viewTable addSubview:table];

Does it make sense to add ATMHud to tabBarController.view

When i try to add ATMHud to uitableviewcontroller subview it does work but it doesn't disable the scrolling and if the tableview is not on top i can't see the hud view. What i did was added to teh tabBarController.view that works but i want find out if this is a good idea or later on i might have issues with it.
Another question is tabBarController.view frame is that the whole screen or just the bottom part. How come atmhud shows in the middle of the screen?
Thanks in advance!
Yan
============
Found a blog post that shows how to reset self.view and add tableview separately in uitableviewcontroller
UITableViewController and fixed sub views
- (void)viewDidLoad {
[super viewDidLoad];
if (!tableView &&
[self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[[UIView alloc] initWithFrame:
[UIScreen mainScreen].applicationFrame] autorelease];
self.tableView.frame = self.view.bounds;
self.tableView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
[self.view addSubview:self.tableView];
UIView *fixedBar = [[UIView alloc] initWithFrame:
CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)];
fixedBar.backgroundColor = [UIColor colorWithRed:
0.0 green:1.0 blue:0.0 alpha:0.7];
[self.view addSubview:fixedBar];
[fixedBar release];
}
After this when add hud to self.view you will be able to disable the tableview on the bottom.
Let me know if this a good way to setup the tableview
The problem with using the tab bar is that the hud is now modal, and the user cannot change the tab.
It sounds like the tableview is not your primary viewm, as it can get "covered up". If its not the primary view, then add the ATMHud to self.view. If the tableView is the same as self.view, then add a new transparent view to it, then add the HUD to that view.
The tabBarController.view is the view that hosts the tabbed views - if you want to see its size (or frame) log it using NSStringFromCGRect(self.tabBarController.frame);
EDIT: I just did a test, the ATMHud DOES block the UI. All I can think of is that you have not inserted it where you need to (at the top of current view's subviews.) I have a demo project where I do this:
hud = [[ATMHud alloc] initWithDelegate:self];
[self.view addSubview:hud.view];
[hud setCaption:#"Howdie"];
[hud setActivity:YES];
[hud show];
[hud hideAfter:5];
A button under the hud is not active - in fact nothing in the view is active (probably the Nav Bar would be live though)
If you want an ARCified and field tested version, you can grab it here
EDIT2: The solution to your problem is below. Note that ATMHud blocks clicks from getting to the table, and the code below stops the scrolling:
- (void)hudWillAppear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = NO;
}
- (void)hudDidDisappear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = YES;
}
Dump the views:
#import <QuartzCore/QuartzCore.h>
#import "UIView+Utilities.h"
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end

Custom UITableViewCell does not appear on second load

I have a custom uitableview with custom uitableviewcell in my view cell. The cell doesn't show on second load. That is, when I go from this view to another and back to this view.
This is how I load my table in my view.
CropTableViewController *cropTblViewCon = [[CropTableViewController alloc]init];
self.cropTableViewController = cropTblViewCon;
cropTableViewController.view.frame = cropTblView.frame;
[cropTblView removeFromSuperview];
[self.view addSubview:cropTableViewController.view];
self.cropTblView = cropTableViewController.tableView;
This is how I go another view
AppDelegate_iPhone *appDelegate = [[UIApplication sharedApplication] delegate];
AddPestReportStepOne *report = [[AddPestReportStepOne alloc]init];
[appDelegate.navCon pushViewController:report animated: YES];
[report release];
This is how I load my table cell in my custom table view.
static NSString *CellIdentifier = #"CustomCropCell";
CustomCropCell *cell = (CustomCropCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
tableView.scrollEnabled = NO;
// tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
NSArray *topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:#"CustomCropCell" owner:nil options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]) {
cell = (CustomCropCell *) currentObject;
break;
}
}
}
//if (counter<6 ) {
CropEntity *crop = [[CropEntity alloc] init];
crop=[ cropList objectAtIndex:counter];
NSString *imgStr = [NSString stringWithFormat:#"%#%#%#",domainName,cropImagePath, [crop cropImage]];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imgStr]]];
CGSize size = CGSizeMake(80, 80);
[cell setBackgroundColor: [UIColor clearColor]];
image = [Utilities scale:image toSize:size ];
[cell.columnOne setTag: [[crop cropId] integerValue] ];
[cell.columnOne setTitle:[crop cropName] forState:UIControlStateNormal];
[cell.columnOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[cell.columnOne setTitleEdgeInsets:UIEdgeInsetsMake(0.0, -image.size.width, -75.0, 0.0)]; // Left inset is the negative of image width. counter = counter+ 1;
[cell.columnOne setImage:image forState:UIControlStateNormal];
[cell.columnOne setImageEdgeInsets:UIEdgeInsetsMake(-15.0, 0.0, 0.0, -cell.columnOne.titleLabel.bounds.size.width)]; // Right inset is the negative of text bounds width.
[cell.columnOne setBackgroundColor: [UIColor clearColor]];
counter = counter + 1;
It seems that the rows are not removed. My cellforrowat indexpath keep increasing...
Okay, i'm assuming you want to add a UITableView to a ViewController. Here are the steps for this:
(1) You have create an UIViewController, whether by code or interface builder
(2) Create an UITableView, and add it to your UIViewController
UITableView *tableView = [[UITableView alloc]
initWithFrame:CGRectMake(0, 0, 320, 440)
style:UITableViewStylePlain];
// Set up the tableView delegate and datasource
[self.view addSubview:tableView];
[tableView release];
I'm sure there is a reason why you are adding the tableView to a UIViewController (there is not reason to have an extra UITableViewController. If not just use a UITableViewController, and set up a UITableView.
Also, keep in mind where you create the tableView at. For instance, if you create it in init or viewDidLoad and using a UINavigationController, when you hit the back button on the UINavigationController the ViewDidLoad or init isn't getting called. Try it yourself, put a NSLog statement to test.
So either use viewDidAppear or [tableView reloadData];
Edit:
Think about your code you create a UITableViewContoller then you remove its UITableView from it's super view (does not make sense) and then you add the UITableViewControllers view (the UITableView) to self.view which is i'm guessing a UIViewController. Surely this can't be what you are trying to do.
I would recommend reading Apple's View Programming guide for a better understanding of UIViewControllers and Views.
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaViewsGuide/Introduction/Introduction.html

How to position a UIToolbar in a UIWebView

I've a sample project, where I have created a custom UIWebView named WebView. They are added to the view in a UIViewController. Two WebView's are initialized in the viewDidLoad and added to an array list. The first one is added as subview på self.view. The Storyboard contains a UIBarButton, and when this is tapped, the second WebView is added as subview to the self.view.
- (void)viewDidLoad
{
[super viewDidLoad];
WebView *webView1 = [[WebView alloc] initWithFrame:self.view.bounds];
WebView *webView2 = [[WebView alloc] initWithFrame:self.view.bounds];
self.webViews = [NSArray arrayWithObjects: webView1, webView2, nil];
UIWebView *webView = [self.webViews objectAtIndex:0];
[self.view addSubview:webView];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://m.google.com/"]]];
}
Here is the implementation of the WebView where a toolbar is added to the bottom (-50px) of the view:
#implementation WebView
- (void) initToolbar {
UIToolbar *toolbar = [UIToolbar new];
toolbar.barStyle = UIBarStyleBlackTranslucent;
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[toolbar sizeToFit];
toolbar.frame = CGRectMake(0, self.frame.size.height-80, 320, 30);
[self addSubview:toolbar];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self initToolbar];
}
return self;
}
#end
The problem is, that the toolbar does not have the same position in the two views (they could be positioned like the first one). Why are they not positioned equally?
You can download the small sample project here:
http://uploads.demaweb.dk/UIWebView.zip
My notes: As mentioned, the two WebView's are currently initialized in the viewDidLoad. If I instead wait and first initialize then when I need them, it seems to work as expected.
The thing here is that self.frame.size.height on viewDidLoad is not the same when you initialize it via the button click. If you add the UIWebView directly in viewDidLoad, the UINavigationBar of your UINavigationController is not loaded yet and the frame of self.view is 'perceived' to be (not really, because it is) larger.
This explains the difference of 40.0 (?) points.
One possible solution to this problematic behaviour is to initialize and add (at least the first) instance of UIWebView in the viewWillAppear:animated method. (UIViewController does already implement this method)

NSOutline View Drag-n-Drop Problem

Dear All,
I am fighting with NSOutline View to perform drag-n-drop within the table since last 2-3 day but couldn't get what i am doing wrong,
This is what i have done so far,
Requirement,
1 -- I want to have a transparent or with some background image NSoutlineview in my view, to do that, i need to overwrite drawRect method of NSOutlineView, this is what i have done
in header file
#interface MyCustomOutlineView:NSOutlineView{
NSImage *pBackgroundImage;
}
- setBackgroundImage:(NSImage *)pImage;
In source file, i just overwrite drawRect and some other stuffs to draw the background image or to make it transparent and this is working fine,
Now in my view, i have declared the NSOutlineView object like that,
/*
* My Custom view will have capability to draw the gradient and other effects
*/
#interface OutlineParentView:MyCustomView<NSOutlineDataSource>{
MyCustomOutlineView *pOutlineView;
}
#property(nonatomic,retain)MyCustomOutlineView *pOutlineView;
In source file, implemented following method ,
This method will be called from the initWIthFrame
#define OutlineViewPrivateDataType "MyOutlinePrivateData"
-(void)InitOutlineView{
NSRect scrollFrame = [self bounds];
NSScrollView* scrollView = [[[NSScrollView alloc] initWithFrame:scrollFrame] autorelease];
[scrollView setBorderType:NSNoBorder];
[scrollView setHasVerticalScroller:YES];
[scrollView setHasHorizontalScroller:NO];
[scrollView setAutohidesScrollers:YES];
[scrollView setDrawsBackground: NO];
NSRect clipViewBounds = [[scrollView contentView] bounds];
pOutlineView = [[[CommUICustomOutlineView alloc] initWithFrame:clipViewBounds] autorelease];
NSTableColumn* firstColumn = [[[NSTableColumn alloc] initWithIdentifier:#"firstColumn"] autorelease];
ImageTextCell *pCell = [[ImageTextCell alloc]init];
[firstColumn setDataCell:pCell];
[pCell setDataDelegate:self];
[firstColumn setWidth:25];
[pOutlineView addTableColumn:firstColumn];
[pOutlineView setRowHeight:30];
[pOutlineView setDataSource:self];
/* setData delegate implemented in the MyOutlineView to handle some of event in this
interface if i don't write this, then i can't handle the menu event on the
Outlineview
*/
[pOutlineView setDataDelegate:self];
**/* On this line i am getting one warning, saying OutlineParentView doesn't implement
NSOutlineView delegate protocol */**
[pOutlineView setDelegate:self];
[scrollView setDocumentView:pOutlineView];
/* I don't want group row to be highlighted */
[pOutlineView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
[pOutlineView registerForDraggedTypes:
[NSArray arrayWithObjects:OutlineViewPrivateDataType,nil]];
[pOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
[scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
[self addSubview:scrollView];
[self setAutoresizesSubviews:YES];
[self log:#"Outline view created "];
}
Other Important method related to Drag-n-Drop implemented as below
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteb oard:(NSPasteboard *)pboard{
[self log:#"write Items"];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:items];
[pboard declareTypes:[NSArray arrayWithObject:OutlineViewPrivateDataType]
owner:self];
[pboard setData:data forType:OutlineViewPrivateDataType];
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
NSLog(#"validate Drop");
return NSDragOperationEvery;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)item childIndex:(NSInteger)index{
[self log:#"inside accept drop for NSView "];
return YES;
}
I checked apple DragnDrop Sample code, but couldn't get what i am doing wrong,
i believe, some problem with the
[pOutlineView setDelegate:self]
Function, but how to solve that, that i don't know,
I upgraded recently from MyTableView to MyOutlineView, recently i was able to perform Drag-nDrop on the Custom Table view,
Remaining things are working fine, like DataSource etc...
Thanks in Advance
Kind Regards
Rohan
i was setting ColumnWidth so drag-n-drop working for the width which has been set, not on the full row my mistake :(
[firstColumn setWidth:25];
Removing this line working fine
But guys facing some other problem
Regarding NSoutlineView and WriteItem | Drag-and-Drop Problem