What are the correct steps to create a single column tableview with a fixed number of checkboxes. For example the column could have the following (X indicates the checkbox checked, _ indicates the checkbox unchecked. I also desire text headings in the same column.):
Heading one:
X item 1
_ item 2
X item 3
X item 4
Heading two:
X item 5
_ item 6
I prefer to do this using Cocoa bindings if possible. Also I need to know how to get the on/off checked states of any items that the user checks or unchecks. I need to know how to set the title text of the checkboxes to "item 1", "item 2" etc.
What I'm trying to do is use tableview to create a listbox of items with checkboxes like can be done in Microsoft MFC. Please be explicit in code explanations and describing IB steps as I'm very new to Cocoa and Objective-C.
Thanks.
OK, I have made this project for you and recorded in a screencast how I have made it.
Everything is so laggy just because it is too hard to screencast for my old 2008y MacBook
Project: Download
Screencast: Download
I'm writing from an iPad, so sorry for any mistakes, I can't test the code
1) in IB put a nstableview, make it 1 column in inspector, make it view based, name the column MainCoumn. Put checkbox in the tableviewcell.
2) select yor table view, open the forth tab in the inspector and connect delegate and datasource with AppDelegate.
3) in your AppDelegate.h add this:
<NSTableViewDelegate, NSTableViewDataSource>
After : NSObject
4) in your AppDelegate.m add this:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
if( [tableColumn.identifier isEqualToString:#"MainColumn"] )
{
NSArray *subviews = cellView.subviews;
NSButton *checkbox = [subviews objectAtIndex:1];
cellView.textField.stringValue = #"checkbox";
// [checkbox state]; - check is it checked
// [checkbox setState:0]; - 0 is to set it unchecked, 1- checked.
// if you need to make the second one checked, other - unchecked:
if (row == 1) {
[checkbox setState:1];
} else {
[checkbox setState:0];
}
return cellView;
}
return cellView;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return 6
// here you type the number of rows
}
5) profit111
Related
{
MainTitle 1
{
Subtitle 1
( item 1
item 2
item 3 )
},
{
MainTitle 2
{
Subtitle 2
( item 1
item 2
item 3)
}
}
There is JSON data format that I have to display in UITableview. The data is restaurant's menu. I create Table 1 for MainTitle display and Table 1 cell inside another UITableview Table 2 for Subtitle and item Subtitle set as header and item as row.
Tableview cell height is dynamic so I set it UITableViewAutomaticDimension for both tableview. Table 1 cell height is set according to inside it Table 2 height. Table 2 is not scrollable, it's height is according to content height.
So, I want to set Table 1 cell height after loading Table 2 all data.
You could use proper UITableView sections and rows. Add "MainTitle" as Table Section and MainTitle's "Items" as Section Rows.
I'd recommend using one single tableview as mentioned by #trungduc and #Raj D
You should be able to use a custom tableview cell to layout the items the way you want, and you can always use buttons for items that need to be clickable (i.e. if you need to click on the menu items and show another view controller).
Here's a basic mockup of what I mean:
You'll want to use a stack view within the cell and then dynamically generate the menu items based off your backing data model (this should allow it to obtain the correct intrinsic content size for UITableViewAutomaticDimension to size the cells correctly).
Here's an example of what I mean by dynamically adding the menu items when setting the submenu item of the custom cell:
- (void)setupMenuItemsStack:(NSArray <RPMenuItem *> *)menuItems {
for (UIView *subview in self.menuItemsStack.arrangedSubviews) {
[NSLayoutConstraint deactivateConstraints:subview.constraints];
[subview removeFromSuperview];
}
for (RPMenuItem *menuItem in menuItems) {
UIButton *menuItemButton = [UIButton buttonWithType:UIButtonTypeSystem];
[menuItemButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[menuItemButton setTitle:menuItem.title forState:UIControlStateNormal];
[self.menuItemsStack addArrangedSubview:menuItemButton];
}
}
Depending on how you're structuring your model, the tableview methods would look something along these lines:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.menuList.menus.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.menuList.menus objectAtIndex:section] subMenus].count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[self.menuList.menus objectAtIndex:section] title];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RPMenuTableViewCell *cell = (RPMenuTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"RPMenuCell" forIndexPath:indexPath];
RPSubMenu *subMenu = [[[self.menuList.menus objectAtIndex:indexPath.section] subMenus] objectAtIndex:indexPath.row];
[cell setSubMenu:subMenu];
return cell;
}
Where the menu list is a top level list of menus and it cascades down from there (i.e. menu list holds an array of menus, menus hold an array of submenus, submenus hold an array of menu items).
#property (strong, nullable) RPMenuList *menuList;
Adding the ability to expand and contract (accordion style) to show the menu items would probably be a nice touch as well:
In my UIActionSheet I have a button which mark the touched array as favorite. When an array is favorite, I have a star that shows before the array's name. The favorite icon has an alpha 0, and by touching the "Add as Favorite" button the alpha changes to 1. The arrays are located inside an UIViewController, which shows 1 array in each cell.
The problem I have is that I have to reopen the ViewController for the star to show.
How can I fix so the star shows immediately when I press the "Add as Favorite" button, without reopening the ViewController?
The Favorite Icons alpha is updated under:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
And this is the code that updated the alpha:
if ([FavoriteArray containsObject: [mainArray objectAtIndex:indexPath.row]])
{
favoriteImage.alpha = 1;
}
Thanks!
You need to monitor when the action sheet has been actioned on, and update the collection view accordingly. An example implementation is as follows:
UIActionSheet* actionSheet = ...;
// Set yourself as the action sheet delegate, so you can monitor when events occur
actionSheet.delegate = self;
...
// This is called when a user selects an item within the action sheet
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
// kFavouriteButtonIndex is the index of the action sheet item to favourite
if (buttonIndex == kFavouriteButtonIndex) {
// Reload your collection view to update the cells
[self.collectionView reloadData];
}
}
Instead of calling reloadData, if you know the indexPath of the item which is being favourited, then you can call reloadItemsAtIndexPaths:#[indexPath] to make the process more efficient.
You will want to update the image's alpha when a button is selected. You can do this by implementing the UIActionSheetDelegate protocol in your UIViewController. You can do this in you View Controller's .m file:
#interface MyViewController : UIViewController <UIActionSheetDelegate>
Then override the actionSheet:clickedButtonAtIndex: method in the .m file:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
//make sure that the button pressed is the one which should change the image alpha:
if(buttonIndex == 2){ //put the button index in the place of "3"
//your code to update the alpha here
}
}
Make sure that you set the UIActionSheet's delegate to self:
myActionSheet.delegate = self;
I have a NSTableView, its data source and delegate have been set. And I want to customize the cell, so I dragged a view-based cell view from the library. Then I created a class ServiceCell which inherits from NSTableCellView in order to fully control my special cell. After that, I control-drag from the nib file to the cell class to create the IBOutlet properties of the image and text field in the cell.
In the NSTableView's delegate methods, I wrote this:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
// Get a new ViewCell
ServiceCell *cellView = [tableView makeViewWithIdentifier:#"ServiceCell" owner:self];
NSLog(#"Field = %#", cellView.textField); //which turns out to be null!!!
if( [tableColumn.identifier isEqualToString:#"ServiceColumn"] )
{
cellView.serviceImage.image = nil;
cellView.nameLabel.stringValue = #"Hello";
return cellView;
}
return cellView;
}
As you can see, the text field is null! But makeViewWithIdentifier: has found the cell in Interface Builder and displayed the cell in the app window. I just cannot set it's value, Why?
The problem is you are accessing your textfield but not accessing its textvalue. Try your log statement like this below:-
NSLog(#"Field = %#", cellView.textField.stringValue);
in Table view select cell and give identifier name (same as you are using in code, for your snipped it will be #"ServiceCell"), your code part is right it will work.
I have an NSDictionary that holds all the data:
One title (not important for this question)
One link (not important for this question)
One array of NSDictionary containing again 1 title and 1 link
I'm displaying this data in a view based table view like this:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
if (tv == _downloadTable)
//I use this "if" because I have another tableView that has nothing to do
//with this one
{
return [[myDictionary objectForKey:#"myArray"] count];
}
}
I want 2 columns in this tableView, one to display the title and one with a checkbox, that would do something letting me know which row is checked.
- (NSView *)tableView:(NSTableView *)tv viewForTableColumn :(NSTableColumn *)tableColumn row :(NSInteger)row
{
if (tv == _downloadTable)
{
if (tableColumn == _downloadTableTitleColumn)
{
if ([[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"])
{
NSString *title = [[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"];
NSTableCellView *result = [tv makeViewWithIdentifier:tableColumn.identifier owner:self];
result.textField.stringValue = title;
return result;
}
}
if (tableColumn == _downloadTableCheckColumn)
{
NSLog(#"CheckBox"); //I wanted to see exactly when that was called
//But it didn't help me :(
NSButton *button = [[NSButton alloc]init];
[button setButtonType:NSSwitchButton];
[button setTitle:#""];
return button;
}
}
}
Right now when I run it and click on the checkbox it does nothing
(of course because I don't know how to make it do something.
Where should I put the code that should do something?
The main goal is an editable list of downloads, right now the list is displayed, with the checkbox right next to the title at each lines.
I would like to know which checkBox are checked and which are not.
I tried this:
[button setAction:#selector(checkBoxAction:)];
- (void)checkBoxAction: (id)sender
{
NSLog(#"I am button : %# and my state is %ld", sender, (long)[sender state]);
}
But I can't figure out how to get the row of that button, to know which title is associated with this checkBox.
I also tried the setObjectValue method of the tableView without success.
The way I would like it to work is:
I have a "start downloading" button that check if each checkbox is checked or not and launch the next action (downloading) only with the checked row.
I would like to avoid bindings because I plan to make it work on iOS too and I don't want to have different code for iOS.
You can use the NSTableView method -rowForView: to get the row a particular view is in.
In your case you'd have something like this:
- (void)checkBoxAction:(id)sender
{
NSInteger row = [_downloadTable rowForView:sender];
NSLog(#"The button at row %ld was clicked.", row);
}
Here are the docs for NSTableView: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class/Reference/Reference.html
You could try using the button' tag property setting it for each button you place as the number (location) in the tableview. Look here!!!
Detecting which UIButton was pressed in a UITableView
[EDIT1]
If people actually decided to read the linked post you would realize that the answer is actually there.
Try adding:
[button setTag:row];
[button addTarget:self action:#selector(checkBoxAction:) forControlEvents:UIControlEventTouchUpInside];
inside the else of your viewForTableColumn routine:
In your checkBoxAction routine:
- (void)checkBoxAction: (id)sender{
NSLog(#"I am button : %# and my state is %#", sender.tag, [sender state]);
}
I also think that once you begin digging further into your code, you are going to want to start using the auto-dequeuing capability of the TableViewCell objects. I believe that you are going to find yourself in a memory alloc/dealloc problem.
How would I use a tableView as a value selector?
So I have a series of input fields and what I want is when you select a cetian field it opens a tableview of options that you can pick from as a value for that field.
Upon selecting an option it returns to the previous View with the selected value filling that field.
This is what I do, similar to the Settings > General > International > Language table view in the iPhone/iPod.
The user can tap a row and a check mark will appear. The view is dismissed when "Done" or "Cancel" is tapped.
First, create a UITableViewController that will display your options. Have a toolbar on the top with a Cancel and Done button. Also have these properties:
SEL selector; // will hold the selector to be invoked when the user taps the Done button
id target; // target for the selector
NSUInteger selectedRow; // hold the last selected row
This view will be presented with the presentModalViewController:animated: method so it appears from the bottom of the screen. You could present it in any other way, but it seems kind of standard across iPhone applications.
Before presenting the view, set target and selector so a method will be called when the user taps the "Done" button.
Now, in your newly created UITableViewController you can implement the thetableView:didSelectRowAtIndexPath:` method as:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark; // show checkmark
[cell setSelected:NO animated:YES]; // deselect row so it doesn't remain selected
cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:selectedRow inSection:0]];
cell.accessoryType = UITableViewCellAccessoryNone; // remove check from previously selected row
selectedRow = indexPath.row; // remember the newly selected row
}
Also implement cancel and done methods for the toolbar buttons:
- (IBAction)done:(UIBarButtonItem *)item
{
[target performSelector:selector withObject:[stringArray objectAtIndex:selectedRow]];
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)cancel:(UIBarButtonItem *)item
{
[self dismissModalViewControllerAnimated:YES];
}
You should use UITableViewDelegate's tableView:didSelectRowAtIndexPath:, remember the value somewhere in another object (a share instance/singleton maybe? - depending on your architecture) and then dismiss this table view.
I implemented a ViewController for Date pick.
I create a protocol to return the date picked to the previous view.
#protocol DataViewDelegate
#optional
- (void)dataViewControllerDidFinish:(NSDate*)dateSelected;
#end
...
- (void) viewDidDisappear:(BOOL)animated
{
if ([ (id)(self.delegate) respondsToSelector:#selector(dataViewControllerDidFinish:)])
{
[self.delegate dataViewControllerDidFinish:self.data];
}
[super viewDidDisappear:animated];
}
In the picker view you can use the
tableView:didSelectRowAtIndexPath:
to select the row you want. Here i set the data property.
The previous view is the delegate for the protocol.