Combined UITableView with other elements - how to create and use the view? - objective-c

Ive a project close to doing everything I need it to do. Its got a Main page which has four buttons that allow you to choose an option. Then a tableview page is launched from those options and displays a parsed XML feed from a website. You can then select one of the options in the table to see a detail view of the item, enquire about it, etc.
My problem is I need to add more elements to the TableViewController page, other than the tableview itself. I want a customized back button (not the navigation controller standard) plus some labels, images, etc.
In the TableViewController xib, the tableview itself fills the page. I cant resize it to add more elements above it. I can add a 'view' window seemingly above the tableview and put things in it. But it seems to add the view to the tableview. This means that when I scroll the table, the other elements like new back button, scroll away as part of the table.
So I'm led to wonder whether I need this page not to be a tableviewcontroller, but a viewcontroller, with a tableview inside it, as well as my other view with buttons, etc. Is that the right way to go? But if thats the case, then how do I instantiate the tableviewcontroller within code? Because my page will not be of that type anymore - it will be just a viewcontroller. But in code Im making a tableviewcontroller .. slightly scared by that route tbh.
Any illumination on this would be much appreciated, as various searches have left me none the wiser. Thanks.

To customize it, this is the way to go:
Change your class to be a view controller instead, which implements the TableViewDelegate and TableViewData Source protocols.
In the view didLoad of you controller, create the table view, set its delegate, data source, and any other properties you wish and add it as a subview to your view.
tableView = [[[UITableView alloc] init] autorelease];
tableView.delegate = self;
tableView.dataSource = self;
// .. Other customization
[self.view addSubview:tableView];
I suggest doing this programatically rather than IB.

Instead of a UITableViewController, you want a UIViewController that has an IBOutlet UITableView. Drag and drop a UITableView component from Storyboard and hook it up, and position it as needed on the screen. This UIViewController should implement the UITableViewDelegate and UITableViewDataSource methods.
Edit: Remember that a UITableViewController is just a subclass of UIViewController so you don't really have to get rid of all your code. :) You only need to make minor tweaks to your header and main file, and change the Storyboard to be a UIViewController instead of UITableViewController as I mentioned above.

Related

subviews with UIButtons - how to connect the buttons to IBActions

I am trying to create a simple app which uses a main view and has a smaller subview within it. I need to have buttons in the subview and I am having trouble getting the connections for the buttons to work. I have done the following:
Create a new View-based project, which gave me the ViewController.h & .m, the MainStoryboard.storyboard and the AppDelegate.h & .m.
Create the subView using NewFile - Objective-C Class - then naming it "subView1" and making it a subclass of UIViewController and checking the with xib check box.
This gave me the subView1.h &.m files and the subView1.xib.
I then re-sized the subView in the xib, by setting it's size to "FreeForm" in the attributes inspector and then specifying the width (to 280) and height (to 300) in the size inspector. I also change the background colour to differentiate it from the main view.
I then dragged a UIButton into the subView and connected it as an IBAction (which i named "clickButton1") to the subView1.h file using touchupinside.
For testing purposes only i then used a simple NSLog to check the functionality of the button which i placed in the subView.m file as follows:
-(IBAction)clickButton1:(id)sender {
NSLog(#"It Worked!");
}
In my ViewController.m file in the viewDidLoad i then added the following code to add the subview to the main view:
subView1 *sv1 = [[subView1 alloc]init];
sv1.view.frame = CGRectMake(20,120,280,300);
[self.view addSubview: sv1.view];
This all worked fine, and when i run the app i get the main view and the subview appear as expected. The problem is when i click on the button which is located in the subview it crashes with the following error:
Thread1:EXC_BAD_ACCESS(code=1, address=0xe00000008)
From what i have read i believe this may have something to do with how I am adding the subview and the fact that I am using ARC. Something about once the subview is added it is automatically released and therefore all buttons/connections etc within the subview are lost.
So my two questions are 1) Am i missing something silly here and is there an easy fix? and 2) Is this an appropriate way to create an app which uses subviews with buttons within them or is there a better way? Thanks to anyone who takes the time to answer!
I tried to reiterate what you said.
So you first made a View-Based Application (checking the "Use Storyboards" checkbox), and you put a button in the storyboard. Then, you control-dragged the button to the "ViewController.h" file. If that is right, you should just be able to put
NSLog(#"It Worked!");
in the method implementation (at least, I could do that)

Change a UIViewController to a UITableViewController inside a storyboard?

I've made a view in my storyboard which I've now decided I'd rather display its data via static table cells.
I can't use static table views in a UIViewController (Static table views are only valid when embedded in UITableViewController instances). So, I need to convert my existing UIViewController to a UITableViewController somehow. I've changed the .h file's parent, but that hasn't done it.
Is there another way to get this going? I'd really rather not have to make a new VC in the storyboard and move everything over, it's a big hassle.
I'll add to this, since the question is about how to change a UIViewController into a UITableViewController, and given that this question is over a year old and the original answer, while valid and may or may not have been the only solution at the time, doesn't actually answer the question and is not the only solution.
It IS possible to do this, you just have to set up the table view delegate and datasource outlets in IB, and manually edit the storyboard XML, which sounds scary but is actually very easy.
First, change your class's parent to be a UITableViewController. UITableViewController already adopts the UITableViewDatasource and UITableViewDelegate protocols, so if your class does too you can remove them:
#implementation MyTableViewController : UITableViewController
...
#end
Next, create new referencing outlets on your UITableView for its dataSource and delegate. The easiest way to do this is to control-drag from the UITableView to itself. The popup will give you the dataSource and delegate options.
Lastly, you need to change the storyboard XML. The storyboard file can get pretty big pretty fast. The easiest way to find the scene you are looking for is by setting Storyboard Identifier in the Identity Inspector. To view the XML directly, right click on the storyboard file in the project navigator and select "Open As -> Source Code". Now just search for whatever you set the reuse identifier to earlier. You'll see something similar to this:
<!-- My Table View Controller -->
<scene sceneID="EuE-XX-cCb">
<objects>
<viewController storyboardIdentifier="MY_TABLE_VIEW_IDENTIFIER" ... >
// Lots of other stuff
</viewController>
</objects>
</scene>
All you need to do is change the opening and closing view controller tags
<viewController>
</viewController>
to be tableViewController instead
<tableViewController>
</tableViewController>
That's it! No need to create a new UITableViewController scene or embed a UITableViewController in a container view.
EDIT:
I should also add that the UITableView MUST be the root view. It cannot be embedded inside another UIView.
If you want your static cell table view not to take up the entire screen, then using a container view is the easiest way to go. Start with a regular UIViewController and drag a container view (next to normal UIView in the object list) into its view. Resize it however you want -- the storyboard will automatically provide a view controller connected to this container view with an embed segue. Delete that controller, drag out a table view controller and right-drag from the container view to this table view controller to make a new embed segue. This table view controller can be accessed from the UIViewController with its childViewControllers property (and conversely, you can access the UIViewController from the table view controller with parentViewController if you need to).
What I did, is creating a UITableViewController in IB, open the Storyboard with a text editor, and copy all the nodes inside from the UIViewController to the UITableViewController.
I think that with this way there's less risk of deleting something important.
Before copying the sections objects, make sure that both tableviews (UIViewController and UITableViewController) have the same properties set like: static or dynamic cells, style (plain or grouped), etc.

Add other objects to iOS 5 storyboard after tableview

I have a simple iOS 5 storyboard that contains a tableview controller scene. However, the table UI takes up 100% of the real estate and I am unable to add any additional objects such as a title bar. Any object that I drag to the scene will try to size correctly and what-not but as soon as I let go it will not add the object. What am I doing wrong?
If all you want is a title bar, then it looks like you want to embed your table view controller in a navigation controller. You can do this by selecting your table view controller and using the Editor: Embed In: Navigation Controller menu command. Once you do this, you should have a navigation bar, and you can double click it to edit the title.
If you need arbitrary UI elements along with your table view, then I think you need to use a plain UIViewController scene instead of a UITableViewController, and manually drag a UITableView into the scene. Your view controller would not subclass UITableViewController, instead it would subclass UIViewController and implement the UITableViewControllerDelegate and UITableViewControllerDataSource protocols. Also, you would need to manually wire up the delegate and dataSource outlets by ctrl-dragging from the table view to your view controller in interface builder, and your view controller would need a custom tableView outlet that points to the UITableView and is correctly wired up in IB. Perhaps there is a simpler approach than this though, if someone has a better suggestion that would be great to hear.

Custom UISplitViewController?

I want the effect of a UISplitViewController however I am not using the split view template.
Is it relatively easy to achieve without the template? And with using normal UIViewController?
What I want it a customary sized and positioned UITableView which then has a customary sized detail view which then of course goes into a popover and detail view when portrait.
Doing it without Interface Builder, you would create a UIViewController class. In the viewDidLoad method of that class, create a UIView or a UITableView with the frame origin where you want it and a size that you want. (Release it in the viewDidUnload method.) Then set the UIViewController's self.view to point to this new view.
self.view = [[UIView alloc] initWithFrame:...]; // edit - added in response to your question
If you created a UIView, then you will want to put your UITableView inside this new view. (This approach lets you add more items to the container UIView if you need to.)
Make sure your UIViewController adheres to the UITableViewDelegate and UITableViewDataSource protocols. Add the delegate and datasource methods and you should be good to go.
This new view can cover other views, or you can size the other views to fit beside it. You only need to set there frames according to what you want to do with them.
There are some limitations if you use a UITableViewController, so a lot of people recommend using a UIViewController instead. like I described above. You can google for more info on that topic.
Just great a new temporary Xcode-project from that template and judge yourself, if it is complicated for you, to adept your (real) code.
Yes. You can do it quite easily. Just use delegates to pass messages between the left and the right side views (root and detail). For instance the didSelectRowAtIndexPath tableView method could be used along with delegation to pass a message to the right sided detail view. Tap a cell on the left table, show its text as a Label on the right side. Its just a simple example. And yes you can handle the rotations and send left side view into a UIPopoverController as well, thus giving the detail view full screen real estate in Portrait orientation.
Also try MGSplitViewController . It gives you a lot of other customization options on a split view controller.

UISplitViewController: how to get toolbar if details controller is UITableView?

I checked out Apple's example on how to exchange detail views in the UISplitViewController and it seems that they put the UIToolbar in every detail controller. Then, if the device is rotated, they hide the toolbar or show it and add a popover button which will show the root controller.
I'd like to adopt this pattern to show my root controller in a popover using a button in the toolbar, but unfortunately, my detail controllers are all UITableViewControllers and they do not allow adding other UI elements than a table view. So how do I deal with that? Is there an example around?
René
I think I figured out by myself: DON'T use a ´UITableViewController´ and a UITableView as root view in your NIB, as you cannot add a UIToolbar to the table view.
Instead: In the NIB, put a standard view and drag a UIToolbar and a UITableView on it.
Connect the standard view to the controller's "view" outlet.
Add another outlet and make it a UITableView. Connect the table view to it.
In the code: Let your controller inherit from UIViewController and not from UITableViewController.
Add a property to your controller to get the TableView to make it look compatible to UITableViewController.
public UITableView TableView
{
get { return this.viewTableView; }
}
Upon the viewDidRotate event you will have to adjust the table views width and height now (UITableViewController did that job for you before):
this.TableView.Frame = new RectangleF(0, 44, this.SuperView.Frame.Width, this.SuperView.Frame.Height);
The 44 pixels com from the parent view's toolbar.
I don't miss UITableViewController. I know there are some issues like automatic scrolling when editing, but in my case this is simply not needed.
René
Check out this example and the corresponding code. If I understand your question, this should show you how to do what you're looking to accomplish.
Also, just as an FYI to everyone, another MT user MonoTouched the MultipleDetailViews example that you linked to above.