I'm working on a Monotouch project, where I have designed the UIImagePickerController with the CameraOverlayView.
In then bottom I have an UIToolBar, and on iPhone5 the toolbar is large. Here the camera-button is centeret vertical, but my cancel button isn't.
What can I do to center it?
The code for creating it is:
mCameraToolbar = new UIToolbar();
UIBarButtonItem cancel = new UIBarButtonItem(UIBarButtonSystemItem.Cancel);
cancel.Clicked += delegate(object sender, EventArgs e)
{
mPicker.DismissViewController(true, null);
if(mImgView.Image == null)
NavigationController.PopViewControllerAnimated(true);
};
UIBarButtonItem camera = new UIBarButtonItem(UIBarButtonSystemItem.Camera);
camera.Clicked += delegate(object sender, EventArgs e)
{
mPicker.TakePicture();
};
mCameraToolbar.SetItems(new UIBarButtonItem[]{
cancel,
new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace),
camera,
new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace),
new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace)
}, true);
I think this is not possible with a simple UIBarButtonItem. But you can try doing it with adding a view as a container. You only have to pass a UIView when creating a new UIBarButtonItem like this:
UIView containerView = new UIView();
containerView.Frame = new RectangleF(0f,0f,150f,YOUR_TOOLBAR_HEIGHT);
UIButton buttonAnuller = new UIButton();
buttonAn.SetTitle("Annuler",UIControlState.Normal);
buttonAn.Bounds = new RectangleF(0f,0f,150f,30f);
buttonAn.Center=new PointF(containerView.Frame.Width/2,containerView.Frame.Height/2);
containerView.Add(buttonAn);
UIBarButtonItem itemWithView = new UIBarButtonItem(containerView);
In this code snipped a containerView is created. After that a Button is created an added to the containerView. The last step is only creating a new UIBarButtonItem with the container as parameter.
Instead of figuring out how to tame the Toolbar I would suggest to just going without it, you can easily get that result with a custom view which has the two buttons inside.
PS: Don't use anonymous delegates. Otherwise your code will leak memory.
Related
Is it possible to disable the scrolling of tableHeaderView (Not to be confused with section header).Right now whenever I scroll the table, view in the tableHeaderView also gets scrolled.
What i am doing:
I have a class subclassed from UITableViewController.
In storyboard, I am using the static table view.
Table style is Grouped and I have added 8 sections having a row each.
On the top of 1st section, added a view which is the tableHeaderView.
I want to disable the scrolling of view with title "Profile" when I scroll the table.
PS:
I know this is achievable if I subclassed my class from UIViewController instead of UITableViewController.
But I don't want to UIViewController because I am using storyboard for designing static cell and If I use UIViewController instead of UITableViewController then compiler throws a warning "Static table views are only valid when embedded in UITableViewController instances"
Please let me know which is the best approach to achieve this.Is it possible to disable the scrolling of tableHeader using my current approach or do I need to use UIViewController instead.
Just use an embed segue with a parent UIViewController consisting of a header view and a container view. Embed your UITableViewController in the container view. More specific steps in this answer.
If you want everything in UITableViewController, you can insert your own subview doing something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.header = [[UIView alloc] init];
self.header.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, 44);
self.header.backgroundColor = [UIColor greenColor];
[self.tableView addSubview:self.header];
self.tableView.contentInset = UIEdgeInsetsMake(44, 0, 0, 0);
}
and then manipulate the position of the view in scrollViewDidScroll and friends:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
self.header.transform = CGAffineTransformMakeTranslation(0, self.tableView.contentOffset.y);
}
I say "and friends" because you'd need to take care of the corner cases like scrollViewDidScrollToTop:. scrollViewDidScroll gets called in every display cycle during scrolling, so doing it this way looks flawless.
Timothy Moose was spot on. Here are the necessary changes for iOS8.
MonoTouch (C#)
// create the fixed header view
headerView = new UIView() {
Frame = new RectangleF(0,0,this.View.Frame.Width,44),
AutoresizingMask = UIViewAutoresizing.FlexibleWidth,
BackgroundColor = UIColor.DarkGray
};
// make it the top most layer
headerView.Layer.ZPosition = 1.0f;
// add directly to tableview, do not use TableViewHeader
TableView.AddSubview(headerView);
// TableView will start at the bottom of the nav bar
this.EdgesForExtendedLayout = UIRectEdge.None;
// move the content down the size of the header view
TableView.ContentInset = new UIEdgeInsets(headerView.Bounds.Height,0,0,0);
.....
[Export("scrollViewDidScroll:")]
public virtual void Scrolled(UIScrollView scrollView)
{
// Keeps header fixed, this is called in the displayLink layer so it wont skip.
if(headerView!=null) headerView.Transform = CGAffineTransform.MakeTranslation(0, TableView.ContentOffset.Y);
}
[Export ("scrollViewDidScrollToTop:")]
public virtual void ScrolledToTop (UIScrollView scrollView)
{
// Keeps header fixed, this is called in the displayLink layer so it wont skip.
if(headerView!=null) headerView.Transform = CGAffineTransform.MakeTranslation(0, TableView.ContentOffset.Y);
}
I need to implement a single button which would be shown at upper right corner of the application on UIView or MKMapView. On clicking that button a combo should come up and user would be able to select the categories.
How can I achieve that?
You have to create an UIButton and add it as a subview of your UIView (for example in viewDidLoad method if your view is linked to an UIViewController).
UIButton *showButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
showButton.frame = CGRectMake(500, 20, 150, 44); // hardcoded frame, not quite elegant but works if you know the dimension of your superview
[showButton setTitle:#"Show Categories" forState:UIControlStateNormal];
// add target and actions
[showButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
// add to a superview, your parent view
[superView addSubview:showButton];
Then you add a method, called buttonClicked: that takes an id parameter (usually the sender, showButton in this case).
-(void)buttonClicked:(id)sender
{
// visualize categories
}
To visualize the categories you can follow two different ways:
Present a UITableViewController inside a UIPopoverController (only for iPad device)
Show a modal controller presenting a UITableViewController (both iPad and iPhone devices).
The UITableViewController allows you to have a list of categories and then select one of them.
P.S. Check the code in XCode because I've written by hand (without XCode)
I am trying to use my own custom image to represent my toolbar buttons, however, whenever I set the image (a png image) as the toolbar button's image, it just displays as a white box the size of the image on my button.
Programmatically I tried this:
bestButton.image = [UIImage imageNamed:#"best_off.png"];
Where bestButton is a UIBarButtonItem declared and set as a property and IBOutlet.
However, this also just displays a white box where the button should be.
To check if the image is bonked, I tried this code:
self.navigationItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"best_off.png"]]autorelease];
Which correctly sets my titleview in the navigation bar to show the image perfectly.
Can anyone help identify why this, and all my other images just show as white boxes when put in the bar button's image?
The images used in toolbars are never displayed. They are used as a mask (the alpha channel I believe). Try this. Create an icon (png) with transparent background. Where ever you have a pixel set, it will be white in your icon displayed in the toolbar.
I did this by iterating over all of the bar-items in the toolbar and for those items that were a button, not a space, I set the customView to that of a new button with my image and hooked up the same TouchUpInside listener that I used for the corresponding toolbar button. The buttons even glow. The images have to be 30x30.
If you dont mind looking at MonoTouch instead of Objective C, here is the code. It could be translated easily to Obj C.
void InitializeTbButtons (UIToolbar toolbar, string[] imageFilePaths, EventHandler[] buttonHandlers)
{
int i =0;
foreach (UIBarButtonItem item in toolbar.Items)
{
if ((item.Image != null) && (( i < imageFilePaths.Length) && (i < buttonHandlers.Length) ) )
{
UIButton btn = new UIButton( new System.Drawing.RectangleF(0,0,30,30) );
string filePath = imageFilePaths[i];
btn.SetImage( UIImage.FromFile(filePath), UIControlState.Normal );
btn.ShowsTouchWhenHighlighted = true;
EventHandler eventHandler = buttonHandlers[i];
btn.TouchUpInside += eventHandler;
item.CustomView = btn;
i++;
}
}
}
You can create customView of UIBarButtonItem and assign to navigationItem. Here is the example...
UIImage *bestImage = [UIImage imageNamed:#"best_off.png"];
UIImageView *bestView = [[UIImageView alloc] initWithImage:bestImage];
UIBarButtonItem *bestButton = [[UIBarButtonItem alloc] init];
bestButton.customView = bestView;
self.navigationItem.rightBarButtonItem = bestButton;
My goal is to draw an invisible button above the status bar on the top of my iPhone app (dimension 320*20 pixels).
No matter what I try, something is buggy:
For example, I tried to create a new view. When I want to place the view on the top of my app, it always disappears behind the status bar instead of being in front of it!
I found another great idea on Stackoverflow:
Add UIView Above All Other Views, Including StatusBar
Even if a second UIWindow isn't recommended, I tried to implement it. It worked as I wanted until the moment that I noticed a problem: the keyboard doesn't appear anymore when needed (for example when clicking in a textbox)!
How can I possibly fix this? Or is there a better approach to my problem? This is my code for creating the second window:
// Create window
statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0,0,320,20)];
statusWindow.windowLevel = UIWindowLevelStatusBar;
[statusWindow makeKeyAndVisible];
// Create statusBarButton
statusBarButton = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect buttonFrame2 = statusBarButton.frame;
buttonFrame2.size = CGSizeMake(320,20);
statusBarButton.frame = buttonFrame2;
[statusBarButton addTarget:self action:#selector(goTop) forControlEvents:UIControlEventTouchUpInside];
// Place button into the new window
[statusWindow addSubview:statusBarButton];
in AppDelegate file
self.window.windowLevel = UIWindowLevelStatusBar;
or in any other class
[AppDelegate appDelegate].window.windowLevel = UIWindowLevelStatusBar;
and if you want to make status bar to be on the top again u can set
self.window.windowLevel = UIWindowLevelNormal;
In the documentation for -[UIWindow makeKeyAndVisible]:
This is a convenience method to make the receiver the main window and displays it in front of other windows. You can also hide and reveal a window using the inherited hidden property of UIView.
The "key window" is the one that gets certain input events; text fields in a non-key window might not work. There are two things you can do:
Call [window makeKeyAndVisible] on the old key window afterwards
Set statusWindow.hidden = NO instead (but I don't see why it would be hidden by default). I don't think you can "display it in front of other windows" like -makeKeyAndVisible does; windows don't have a superview you can call -bringSubviewToFront: on IIRC.
If other users want to implement this, here my solution:
// Create window
statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0,0,320,20)];
statusWindow.windowLevel = UIWindowLevelStatusBar;
// Dont make the statusWindow keyWindow or the keyboard won't work!
// [statusWindow makeKeyAndVisible];
// Create statusBarButton
statusBarButton = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect buttonFrame2 = statusBarButton.frame;
buttonFrame2.size = CGSizeMake(320,20);
statusBarButton.frame = buttonFrame2;
[statusBarButton addTarget:self action:#selector(goTop) forControlEvents:UIControlEventTouchUpInside];
// Place button into the new window
[statusWindow addSubview:statusBarButton];
// Instead, add this:
[window makeKeyAndVisible]; // has to be main window of app
statusWindow.hidden = NO; // without this the statusWindow won't appear
Try:
[self.view bringSubviewToFront:statusWindow];
I dont think its possible to bring a view in front of the status bar though.
hopefully someone can help me out- iv'e scoured the net for the answer and cannot find one-
the UIBarButtonItems added to UINavigationBar have a much larger click area than required-
for example, open up any project you have a nav bar with buttons on- click anywhere between the end of the button and the title of the nav bar- the button clicks, when you clearly did not click on the button-
also try this- click underneath the nav bar, below the button, the button clicks for about 5+ pixels below the nav bar-
my problem is this-
i have added a custom header with buttons to a tableview- but when i click the buttons in the header, the UINavigationBar buttons trigger for those 5+ pixels instead of the buttons in the tableview header-
i did a test, and removed the buttons from UINavigationBar and what is interesting is that for the 5 pixels below the nav bar, the buttons in the header will not trigger even though there are no buttons in the nav bar-
its almost like the nav bar has reserved some 5+ pixels below itself as click space-
my question is this-
can someone tell me how to make the nav bar not grab those extra 5+ pixels for its buttons?
thanks very much ;)
This is the only solution I found. Create a container of the custom button:
//Create a container for the button
UIView *buttonContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 55, 44)];
//Create a smaller button
UIButton *closeButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 55, 25)];
[closeButton setTitle:#"Cancel" forState:UIControlStateNormal];
//center the title
closeButton.titleEdgeInsets = UIEdgeInsetsMake(23, 0, 0, 0);
[buttonContainer addSubview:closeButton];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:buttonContainer];
I'm not 100% sure but maybe you can get the location of the touch via the UITouch class?
UIBarButtonItem doesn't extend UIResponder but UINavigationBar does!
So if you subclass UINavigationBar and use this subclass in your app, maybe you can catch the coordinates of the touch and check if they are ok to you and then decide to apply either the navigation bar action or your button action (by some custom redirection).
Short answer is... should shouldn't try and get rid of them. It's about ease of use. The navigation bar at the top tends to mean people tap lower than you may expect. Always leave that gap there, or have a sufficiently large hit area that the user stabbing their finger towards the middle of your "below the nav bar" item will avoid the dead area.
As far as I know, it is impossible to turn off. If you have other buttons on the navigation bar, those click-spaces will not collide, but if you have button directly beneath the nav bar with no space at all in between, you're out of luck. Consider a small padding in the header and its buttons as a solution.
Trying to work around the UINavigation Bar padding may run you into trouble when you submit to the app store. It would be easier to add the padding to your custom heading. As a "fat thumber" I have learned to appreciate the HIG.
Quite old question, but maybe a solution is helpful to others too...
I've created a UINavigationBar subclass, that overrides just one method: 'hitTest:withEvent:'. When hitTest:withEvent is called, it checks wether the event has happened inside the frame of the navigation bar (pointInside:withEvent:) or not. In case, the event has happened outside, the userInteractionEnabled flag is set to NO so the event will be ignored by the navigation bar and its subviews.
In my case, the navigation bar subclass is inserted via IB, but of course is is also possible to insert it via 'UINavigationController initWithNavigationBarClass:toolbarClass:'
Header:
#interface MMMasterNavigationBar : UINavigationBar
#end
Implementation:
#implementation MMMasterNavigationBar
/*
hitTest:withEvent:
The hit area in for navigation bar button items is enlarged by default.
Other objects directly below the navigation bar doesn't receive tap events.
We avoid the default enlarging of the tappable area by disabling userInteraction
when the real tap is outside the navigation bar.
*/
-(UIView *)hitTest:(CGPoint)pPoint
withEvent:(UIEvent *)pEvent {
//FLog;
if ([self pointInside:pPoint
withEvent:pEvent]) {
//NSLog(#"User interaction enabled");
self.userInteractionEnabled = YES;
} else {
//NSLog(#"User interaction disabled");
self.userInteractionEnabled = NO;
}
return [super hitTest:pPoint
withEvent:pEvent];
}
#end
This can be done directly from a storyboard. Drag a UIView into each navigation item, set its background to clearColor, and size it. Drag a button into each UIView and size them to match.
var buttonContainer:UIView = UIView()
buttonContainer.frame = CGRectMake(0, 0, 32, 32)
var imagess:UIImage = UIImage(named: "noti#2x.png")!
var closeButton:UIButton = UIButton()
closeButton.setImage(imagess, forState: UIControlState.Normal)
closeButton.frame = CGRectMake(10, 5, 20, 20)
closeButton.contentMode = UIViewContentMode.Center
closeButton.titleEdgeInsets = UIEdgeInsetsMake(20, 0, 0, 0)
buttonContainer.addSubview(closeButton)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: buttonContainer)