I have a table view , within that tableview I'm setting up a section header, which I want to contain an edit button.
I know there is a built in support for something like that if my viewcontroller is part of a navigation chain, but is there a way to do it without it, or the only option is to set a button manually and trigger an action that will replace the title and the editing property?
btw - I know the code I wrote below is wrong, just wondering if there is a convenient way to convert a UIBarButtonItem to a UIButton. Thanks
-(UIView*) headerView
{
if (headerView)
return headerView;
float w = [[UIScreen mainScreen] bounds].size.width;
CGRect headerViewFrame = CGRectMake(0,0, w,48);
headerView = [[UIView alloc] initWithFrame:headerViewFrame];
[headerView addSubview:[self editButtonItem]]; // I want to do something like that
}
There is no way to convert a UIBarButtonItem into a UIButton. If you look at each of their superclasses you will find that UIBarButtonItem inherits from UIBarItem which inherits from NSObject (not related at all to UIButton which from UIView and conforms to the UIResponder protocol).
For this specific problem you can override the following method:
- (void) setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing: editing animated: animated];
[self.tableView setEditing:editing animated:animated];
}
and have a button (you can use it as your section header view) trigger a method that sets the edit status
Related
I need to add a subview to left part of UIViewController, which shows the user that there is something near the left part of screen, when masterview is hidden(in portrait orientation). And this view must move with left part of UISplitView. Something like the view with arrow in these two images. (Sorry for the russian interface)
http://s2.uploads.ru/8EHJI.png
http://s2.uploads.ru/NhEam.png
But my problem is that when I try to add such a view, it clips to bounds of masterview and is not visible when masterview is hidden. I think, I'm doing it wrong and there is an easy way to do this.
Update: I've tried to make some hack like:
-(void) clipToBoundsRecursive:(UIView *)someView
{
NSLog(#"%#", someView);
someView.clipsToBounds = NO;
for (UIView *v in someView.subviews)
{
[self clipToBoundsRecursive:v];
}
}
and send it to view of splitviewcontroller.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
[self clipToBoundsRecursive:splitViewController.view];
It takes effect at first time (subviews outside the masterview's bounds shows, but after first show/hide animation they disappears and don't appear even if I call this method again)
You can add the view directly to the window's view, though you will have to manually manage its position depending on when the device rotates. Views added to the window.view will appear above the rootViewController.view.
I have described here a simple Logic for you: (how to add a UIView in Window and call it from your master or detail view )
Create UIView in #import "AppDelegate.h" ,
- (void) CreateViewInWindow
{
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 780)];// set as u wish
myView.backgroundColor = [UIColor redColor];
// I have added myView to the Window with a specific animation , your can give animation as you like. :)
[UIView transitionWithView:self.window duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve // change to whatever animation you like
animations:^ { [self.window addSubview:myView]; }
completion:nil];
}
Here create a simple UIButton in the DetailViewController.m file (You can put the code in either of the files, DetailViewController.m OR MasterViewController.m)
UIButton *btnShowView = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnShowView addTarget:self action:#selector(btnShowViewTapped:) forControlEvents:UIControlEventTouchUpInside];
btnShowView.frame = CGRectMake(20, 30, 174, 35);
//[btnLoginInner setBackgroundImage:[UIImage imageNamed:#"LoginBut.png"] forState:UIControlStateNormal];
[self.view addSubview:btnShowView];
In button tapped method, write code for calling UIView from AppDelegate, and also don't forget to add #import "AppDelegate.h" in DetailViewController.m,
-(void)btnShowViewTapped:(UIButton *) Sender
{
AppDelegate *del = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[del performSelector:#selector(CreateViewInWindow) withObject:nil afterDelay:0];
}
Above code is a simple logic for your problem, It might be helpful for you.
Sounds to me like your app could benefit from PKRevealController.
Try with deselecting auto layout option in identity and type pan if you are using nib otherwise set autoresizing mask to view that currently clipping. I believe it will solve the issue
I work on a project for iPhone iOS4 with Xcode 4.
My app uses a tabBar for two Views with two View Controllers.
I want to programmatically create a Button in a View and to have same button in the other view.
For "same button" I mean that buttons have same background Image, same Title and so on. Also, when I programmatically change first button title also second button title change; same for backgrounds.
I was thinking something like "passing the pointer", but I do not know how to do it, how to pass a pointer from a View to another View. (I have a singleton GlobalData, if it can help.)
Thank you.
What you want to do is to create a custom UIButton, and then just use it wherever you need it. Once you change it in it's implementation file it will change globally.
Example CustomButton
//CustomButton.h
#import <UIKit/UIKit.h>
#interface CustomButton : UIButton{
}
#end
//CustomButton.m
#import "CustomButton.h"
#implementation CustomButton
- (id)init
{
self = [super init];
if (self) {
self.type = UIButtonTypeCustom;
self.frame = CGRectMake(170, 45, 150, 40);
[self setTitle:#"Title" forState:UIControlStateNormal];
[self.titleLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size:15]];
[self setBackgroundImage:[UIImage imageNamed:#"bg_image.png"] forState:UIControlStateNormal];
}
return self;
}
#end
Then use it like so:
#import "CustomButton.h"
...
CustomButton *myButton = [[CustomButton alloc] init];
Although the approach looks a bit shady, but I do not know what the use cases are so here it goes.
You can create a UIButton subclass and make that a singleton. Or store that in the AppDelegate.
An interesting thing to note is that when you add the same object to a second view, it will be removed from the first view! So you will have to keep adding it back to the view when ViewController's viewWillAppear: method is called.
I have a core data application which uses a navigation controller to drill down to a detail view and then if you edit one of the rows of data in the detail view you get taken to an Edit View for the that single line, like in Apples CoreDataBooks example (except CoreDataBooks only uses a UITextField on its own, not one which is a subview of UITableViewCell like mine)!
The edit view is a UITableviewController which creates its table with a single section single row and a UITextfield in the cell, programatically.
What I want to happen is when you select a row to edit and the edit view is pushed onto the nav stack and the edit view is animated moving across the screen, I want the textfield to be selected as firstResponder so that the keyboard is already showing as the view moves across the screen to take position. Like in the Contacts app or in the CoreDataBooks App.
I currently have the following code in my app which causes the view to load and then you see the keyboard appear (which isn't what I want, I want the keyboard to already be there)
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[theTextField becomeFirstResponder];
}
You can't put this in -viewWillAppear as the textfield hasn't been created yet so theTextField is nil. In the CoreDataBooks App where they achieve what i want they load their view from a nib so they use the same code but in -viewWillAppear as the textfield has already been created!
Is there anyway of getting around this without creating a nib, I want to keep the implementation programatic to enable greater flexibility.
Many Thanks
After speaking with the Apple Dev Support Team, I have an answer!
What you need to do is to create an offscreen UITextField in -(void)loadView; and then set it as first responder then on the viewDidLoad method you can set the UITextField in the UITableViewCell to be first responder. Heres some example code (remember I'm doing this in a UITableViewController so I am creating the tableview as well!
- (void)loadView
{
[super loadView];
//Set the view up.
UIView *theView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view = theView;
[theView release];
//Create an negatively sized or offscreen textfield
UITextField *hiddenField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, -10, -10)];
hiddenTextField = hiddenField;
[self.view addSubview:hiddenTextField];
[hiddenField release];
//Create the tableview
UITableView *theTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewStyleGrouped];
theTableView.delegate = self;
theTableView.dataSource = self;
[self.view addSubview:theTableView];
[theTableView release];
//Set the hiddenTextField to become first responder
[hiddenTextField becomeFirstResponder];
//Background for a grouped tableview
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//Now the the UITableViewCells UITextField has loaded you can set that as first responder
[theTextField becomeFirstResponder];
}
I hope this helps anyone stuck in the same position as me!
If anyone else can see a better way to do this please say.
Try do it in viewDidAppear method, works for me.
I think the obvious solution is to create the textfield in the init method of the view controller. That is usually where you configure the view because a view controller does require a populated view property.
Then you can set the textfield as first responder in viewWillAppear and the keyboard should be visible as the view slides in.
have you tried using the uinavigationcontroller delegate methods?:
navigationController:willShowViewController:animated:
I was wondering if anyone knew of any good online resources/tutorials for creating views and controllers programatically rather than via the interface builder. Everything I have looked at uses the interface builder and the created nibs, while the IB is ok I would like to have the option of developing these manually (both for practical reasons and get a good understanding of how it all fits together rather than the superficial one you get from dragging and dropping things).
My background is in java and I'm finding it slow and frustrating using the interface builder to develop views the way I would sometimes do them in Java, i.e. either
generate the source programatically from a domain model and then tweak the result if requried
use some meta-data and/or reflection and dynamically add the controls to the view
Also, once I have created a view is there anyway I can add it to the interface builder to make it available to use as a sub view on another view?
Thanks, Vic
The Interface Builder method creates "freeze-dried" objects that are re-created at runtime when you initialize the object from the NIB. It still does the same alloc and init stuff, using NSCoder objects to bring the objects in to memory.
If you want to have a view controller based on a particular NIB, you can then override the default init method and init it based on the NIB for that view controller. For example:
#implementation MyViewController
-(id) init {
if (self = [super initWithNibName:#"MyViewController" bundle:nil]) {
//other setup stuff
}
return self;
}
And when you want to display the MyViewController, you would simply call something like this:
- (void) showMyViewController {
MyViewController *viewController = [[[MyViewController alloc] init] autorelease];
[self presentModalViewController:viewController animated:YES];
}
Now, if you want to create your view manually instead of in Interface Builder, you don't have to change your -showMyViewController method at all. Get rid of your -init override, and instead override the -loadView method of your MyViewController to create it programmatically:
- (void) loadView {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(320,460)];
self.view = view;
[view release];
//Create a button
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton addTarget:self action:#selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[myButton setTitle:#"Push Me!" forState:UIControlStateNormal];
myButton.frame = CGRectMake(100,230,80,44);
[self.view addSubview:myButton];
}
This example shows how to create the view and add a button to it. If you want to keep a reference to it, declare it the same way you would if you were using a NIB (without the IBOutlet/IBActions) and use self when assigning it. For example, your header might look like this:
#interface MyViewController : UIViewController {
UIButton *myButton;
}
- (void) pressedButton;
#property (nonatomic, retain) UIButton *myButton;
#end
And your class:
#implementation MyViewController
#synthesize myButton;
- (void) loadView {
//Create the view as above
self.myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton addTarget:self action:#selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[myButton setTitle:#"Push Me!" forState:UIControlStateNormal];
myButton.frame = CGRectMake(100,230,80,44);
[self.view addSubview:myButton];
}
- (void) pressedButton {
//Do something interesting here
[[[[UIAlertView alloc] initWithTitle:#"Button Pressed" message:#"You totally just pressed the button" delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK",nil] autorelease] show];
}
- (void) dealloc {
[myButton release];
[super dealloc];
}
I had the same issue a couple of months ago when I wanted to do all the iPhone development inside Emacs. To make a long story short: I'm not developing for the iPhone anymore :)
I'd still suggest you to check my question and some helpful answers here.
I typically don't use Interface builder too much for iPhone development. Usually I will create a view controller in code like this
MyUIViewControllerSubclass *controller = [[MyUIViewControllerSubclass alloc] initWithNibName:nil bundle:nil];
controller.someProperty = myModel;
[self presentModalViewController:controller];
[controller release];
Or something along those lines. Typically I create a subclass of UIViewController and that's where I layout my views and such. The views are subclasses of UIView (either things Apple provides like UIButton etc, or something I've created myself). If you read up on both UIViewController and UIView you should get a pretty good idea of how it works.
I have a view that was created with all of the default UITableView stuff, but now I need to add a header area above where the UITableView is (so the UITableView will scroll normally, but the top 100px of the screen or so will have static header content). I don't see where I can resize the UITableView in IB, and am not sure how to do this.
Does anyone know?
You can use UITableViewDelegate methods to create a custom header view for a table and specify the height, namely tableView:viewForHeaderInSection: and tableView:heightForHeaderInSection:. You can add whatever you like to the view. Here's an example that adds a right aligned UILabel:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0,tableView.frame.size.width,30)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, headerView.frame.size.width-120.0, headerView.frame.size.height)];
headerLabel.textAlignment = NSTextAlignmentRight;
headerLabel.text = [titleArray objectAtIndex:section];
headerLabel.backgroundColor = [UIColor clearColor];
[headerView addSubview:headerLabel];
return headerView;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 30.0;
}
Why don't you use the UITableView provided header?. As follow:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #"My Title";
}
Additionally you may resize your table view in IB by dragging the borders.
When you add a UIView or one of its subclasses onto the UITableView using IB (just drag a UIView and drop it onto the UPPER part of UITableView of yours), it automatically adds that UIView component and makes it the "tableHeader" component.
Each UITableView has one tableHeader and one tableFooter component reserved...
This way the new view would be a part of the UITable, and scroll with it or appear/disappear or whatever you do to the table. You can change its hidden property if you need conditional behavior.
On the other hand, if you want the header view stay put, as the table scrolls, then it is better to make the table smaller and put the header above it as suggested in other answers...
I finally solved this problem the right way without changing the base class. The one answer to add the view to the parent nav controller is nice but the transitions look horrible.
The fix is actually easy. The trick is to create custom setter and getter for self.tableView property. Then, in loadView, you replace the view with a fresh UIView and add the tableView to it. Then you're free to add subviews around the tableView. Here's how it's done:
In header:
#interface CustomTableViewController : UITableViewController
{
UITableView *tableView;
}
In .m:
- (UITableView*)tableView
{
return tableView;
}
- (void)setTableView:(UITableView *)newTableView
{
if ( newTableView != tableView )
{
[tableView release];
tableView = [newTableView retain];
}
}
- (void)loadView {
[super loadView];
//save current tableview, then replace view with a regular uiview
self.tableView = (UITableView*)self.view;
self.view = [[UIView alloc] initWithFrame:self.tableView.frame];
[self.view addSubview:self.tableView];
//code below adds some custom stuff above the table
UIView *customHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 20)];
customHeader.backgroundColor = [UIColor redColor];
[self.view addSubview:customHeader];
[customHeader release];
self.tableView.frame = CGRectMake(0, customHeader.frame.size.height, self.view.frame.size.width, self.view.frame.size.height - customHeader.frame.size.height);
}
- (void)viewDidUnload
{
self.tableView = nil;
[super viewDidUnload];
}
Enjoy!
You will have to embed the UITableView in a UIView alongwith another view (which you are referring to as header section).
So, the UIView will have 2 subviews. The header view followed by the table view.
UIView(parent)
UIView (header)
UITableView (table)
Hope this helps.
I like the answer from noodl_es (upvoted), because it provides the functionality and behavior you want, yet you don't have to worry about resizing the UITableView: that is handled for you automatically. However, the solution is best suitable only if the header information pertains specifically to the first section of the table (or if the table has only one section). If the table has more than one section, then the header of the second section will push away the header of the first section when scrolled up, and therefore the header view will not appear to pertain to the whole table.
Found a solution at iphonedevsdk
Instead of doing this:
[tableViewController.view addSubview:viewSubclass];
do this
[tableViewController.navigationController.view addSubview:viewSubclass];
Suppose to have your UITableViewController
#interface MXMTableViewController : UITableViewController <UITableViewDelegate,UIScrollViewDelegate> {
/// your table view interface here
}
and a xib with you simple UITableView defined yet in it, you can do as Mihir says overriding the loadView method like this:
- (void)loadView {
[super loadView];
UIView *mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view = mainView;
[mainView release];
// Add Header View
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 36)];
headerView.backgroundColor = [UIColor redColor];
[self.view addSubview:headerView];
// now, move your table view down. Check you nib to choose
// the right Y-axis offset
CGRect f = tableView.frame;
f.origin.y += headerView.frame.size.height/2;
tableView.frame = f;
// Add the table view to the container view
[self.view addSubview:self.tableView];
// Add footer
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, self.tableView.frame.size.height, 320, 125)];
footerView.backgroundColor = [UIColor redColor];
[self.view addSubview:footerView];
[footerView release];
[headerView release];
}
...and that's it. You have a UITableView with fixed header and footer.
PS. You may now use your xib custom views as the header and footer's views.