Converting a legacy app for iOS 7. Have most of the problems covered, but we have a feature that emails an error log using MFMailComposeViewController, and the status bar is coming up black on black in that view.
The status bar text color is set to white globally using plist settings, and that seems to handle everything else just fine. Only the email VC is acting up. (We present it using presentModalViewController.)
Has anyone figured out how to crack this nut?
Update: Tried subclassing MFMailComposeViewController and implementing preferredStatusBarStyle, but it's not invoked, even after setting "View controller-based status bar" to YES in the plist.
The following kluge appears to do the job:
// Present the email controller. The delegate will dismiss it.
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion < 7.0f) {
[viewController presentViewController:emailController animated:YES completion:^{}];
}
else {
// Need a song and dance to get the header bar to show correctly. (And presentModalViewController is deprecated anyway.) Note that this code doesn't actually change the email controller's header, but it somehow lets the header below "show through" when it wouldn't otherwise. (I know -- like many of the iOS 7 fixes this makes no sense. But it works. (So far.))
#warning Sometimes produces console message "Presenting view controllers on detached view controllers is discouraged <XxxxViewController: 0xc658a70>"
[viewController presentViewController:emailController animated:YES completion:^{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 7)
&& [[UIApplication sharedApplication] respondsToSelector:NSSelectorFromString(#"setStatusBarStyle:")]) {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
#endif
}];
}
#else
[viewController presentModalViewController:emailController animated:YES];
#endif
Related
If you see in ios 7 safari app have left and right dragging to see history of webpages. It also show content of previous page while dragging . I want similar functionality using UIWebiview.
I can get forward and backward page but how that dragging functionality with displaying previous content will be implemented?
Note: this is iOS 7 only. For iOS 6 you should use the PanGestureRecognizer and detect if it's left or right.
Your need two properties:
#property (nonatomic, strong) UIImageView * imgvcChild1;
#property (retain, strong) IBOutlet UIWebView *webView;
First of all, add the gesture recognizer to the webView:
[[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(EdgeLeftPanDetected:)];
panLeft.edges = UIRectEdgeLeft;
[self.webView addGestureRecognizer:panLeft];
Control the gesture:
- (void) EdgeLeftPanDetected:(UIScreenEdgePanGestureRecognizer*)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
UIGraphicsBeginImageContext ( self.webView.frame.size );
[self.webView.layer renderInContext:UIGraphicsGetCurrentContext() ];
UIImage *grab = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if ( _imgvcChild1 ) [ _imgvcChild1 removeFromSuperview ];
_imgvcChild1 = [[ UIImageView alloc ] initWithImage:grab ];
_imgvcChild1.frame = self.webView.frame;
_imgvcChild1.userInteractionEnabled = YES;
_imgvcChild2 = [self.arrayImagenes lastObject];
if ([self.webView canGoBack]) {
[self.webView goBack];
}
[ self.view addSubview:_imgvcChild1 ];
}
if (gesture.state == UIGestureRecognizerStateChanged) {
_imgvcChild1.frame = CGRectMake([ gesture locationInView:_imgvcChild1.superview ].x, _imgvcChild1.frame.origin.y, _imgvcChild1.frame.size.width, _imgvcChild1.frame.size.height);
}
}
if (gesture.state == UIGestureRecognizerStateEnded) {
[_imgvcChild1 removeFromSuperview];
}
}
This a prototype, it needs a lot of work, it's just for going back and the page where you go back doesn't have animation. If you want to have animation in the previous page you'll need to create a image before loading the new page and store it on an NSMutableArray and then show it with a different animation (this image starts like -1/4 of screen and goes like 1/4 of the speed of imgvcChild1)
You'll need another gesture recognizer for the right and another array of UIImageViews if you want to go forward too.
Few days back i too have similar kind of requirement. I did lot of research for this, but no luck. I read somewhere that this kind of gesture (History dragging) are managed by OS or the browser itself.
History dragging gesture are not available for UIWebView. As of now you cannot do this with UIWebView.
The one gesture will implement to achieve near to this functionality is UIPanGestureRecognizer but, you still not get the content of the previous page(history).
I currently have a map displaying 10 or so co ordinates.The map gets the users location and centers on it as soon as it is opened. When panning the page or zooming different levels it eventually resets and centers in on the first position of the user.I have tried "stopupdating location" and Animated as "NO".I can not get it to stay in positon when the user scrolls the map.
- (void)viewDidLoad {
[super viewDidLoad];
self.petrolMap.delegate = self;
self.location = [[CLLocationManager alloc] init];
[location setDelegate:self];
[location setDistanceFilter:0]; // Do not apply a distance filter to the map
[location setDesiredAccuracy:kCLLocationAccuracyBest]; // Use the best accuracy possible when displaying the map
petrolMap.delegate=self; // Display on "Petrol Map" , the mapview for the application}
-(void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{MKCoordinateRegion mapRegion;
mapRegion.center = petrolMap.userLocation.coordinate;
mapRegion.span.latitudeDelta=0.02;
mapRegion.span.longitudeDelta=0.02;
[petrolMap setRegion:mapRegion animated:NO];}
Your 'location' is a location manager, when it works out where you are it'll send its delegate
locationManager:didUpdateToLocation:fromLocation:
which you don't seem to have, so all those settings you're doing to 'location' are wasted (as far as the code you've given us, it may be useful elsewhere) and telling it to stop tracking the user is of no use.
"(void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{MKCoordinateRegion mapRegion;" is what petrolMap is sending to its delegate. Somewhere you must have set petrolMap to track the user, it can be done in the .xib.
Anyway, to stop petrolMap sending messages make sure you run
[petrolMap setUserTrackingMode:MKUserTrackingModeNone animated:NO];
Some extra notes:
Within didUpdateUserLocation you don't need to refer to petrolMap directly because the mapView parameter is set to which ever MKMapView sent the message.
Also within didUpdateUserLocation you are using petrolMap's userLocation instead of the parameter userLocation, and even building your region. The entire code for that function could be one line
[mapView setRegion:mapRegion animated:NO];
'Animated' controls how the change in region is done. Yes means it will slide between locations, No means it will snap from one to the other instantly, either way the map will move to the new region.
Your viewDidLoad method could be cut to two lines like follows
[super viewDidLoad];
self.petrolMap.delegate = self;
Addendum:
locationManager:didUpdateToLocation:fromLocation
is deprecated in iOS6.
Unfortunately this is a few years to late for you James - but hopefully it'll help others who are stuck in this situation (like myself).
I ended up adding...
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow];
Into my -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
You should normally add "animated:YES" at the end, but this again would ping it back to my current location, even if I changed the commander to "NO" - so tried deleting it and it worked!!!
Just for reference my whole code became:
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
if(userLocationShown) return;
MKCoordinateRegion region;
MapView.showsUserLocation = YES;
region.center.latitude = MapView.userLocation.coordinate.latitude;
region.center.longitude = MapView.userLocation.coordinate.longitude;
region.span = MKCoordinateSpanMake(0.02,0.02);
[MapView setRegion:region animated:YES];
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow];
[locationManager startUpdatingLocation];
[locationManager stopUpdatingLocation];
userLocationShown = YES;
and I added...
- (void)viewDidLoad {
[super viewDidLoad];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
MapView.delegate = self;
Trying to use share kit to send a link to twitter,and when the webview comes up to log into twitter, you can tap into the username and password fields, get a cursor, but no keyboard pops up.
This is really starting to frustrate me.
Here's how I'm trying to call Share kit. (from an alert)
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 21){
if (buttonIndex == 1) {
//call SHK
NSLog(#"Calling SHK");
// Create the item to share (in this example, a url)
NSURL *url = [NSURL URLWithString:#"http://link.com"];
SHKItem *item = [SHKItem URL:url title:[NSString stringWithFormat:#"I just played a %d by %d board on #GAMENAME and solved it in %d moves!", down, across, turns]];
// Get the ShareKit action sheet
[alertView dismissWithClickedButtonIndex:0 animated:NO];
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
// Display the action sheet
[actionSheet showInView:self.view];
}
}
It was a problem with UIResponder
UIResponder Troubles
I'm attempting to present a UITabBarController modally using the following code:
// Declare all view controllers.
TabOne *tabOne = [[TabOne alloc] initWithNibName:#"TabOne" bundle:nil];
TabTwo *tabTwo = [[TabTwo alloc] init];
TabThree *tabThree = [[TabThree alloc] init];
// Set each view controller's delegate to self.
tabOne.delegate = self;
tabTwo.delegate = self;
tabThree.delegate = self;
// Set a title for each view controller.
tabOne.title = #"One";
tabTwo.title = #"Two";
tabThree.title = #"Three";
// Create a tab bar controller.
UITabBarController *tabBarController = [[UITabBarController alloc] init];
[tabBarController setViewControllers:[NSArray arrayWithObjects:tabOne,tabTwo,tabThree, nil]];
// Present the tab bar controller modally.
[self presentModalViewController:tabBarController animated:NO];
// Memory management.
[tabOne release];
[tabTwo release];
[tabThree release];
This all works as expected except that I get the following warnings in the console:
Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
Using two-stage rotation animation is not supported when rotating more than one view controller or view controllers not the window delegate.
I've done some research on this and have checked that shouldAutorotateToInterfaceOrientation is implemented as follows:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
As far as I can tell, the problem is that the tab bar controller is not the root view controller, but I'm presenting this modal view some way into a deep view hierarchy. It's called from another modal view, which itself is called from a tab bar set in the application delegate.
I know this is a bit of an old chestnut, but it's got me stumped. Any thoughts?
Thanks in advance.
I've had a similar problem.
UITabBarController has some odd behavior with its orientation handling. When setting its orientation, it calls recursively into self.selectedViewController to decide whether to use one-stage or two-stage animation. That seems sensible, but the trouble is self.selectedViewController is initially nil (in particular, if you're displaying the UITabBarController modally for the first time), and that can confuse the controller. Depending on the iOS version, a nil selectedViewController will lead the UITabBarController to believe that one-stage animation is unsupported.
Try this: when you first load / initialize your UITabBarController, add the line
tabBarController.selectedIndex = 0;
I was getting this warning (including serious visual problems: the view controller was switching orientation but the status bar was not), and setting the index this way fixed the problem. The UITabBarController successfully called into its selected view controller, and detected the one-stage animation.
I have use the custom splitview in the my application.
custom splitview .h file
#interface CustomUISplitViewController :UISplitViewController {
BOOL keepMasterInPortraitMode;
BOOL keepMasterInPortraitMode1;
}
and .m file is
-(void) viewWillAppear:(BOOL)animated {
keepMasterInPortraitMode1=keepMasterInPortraitMode;
if(keepMasterInPortraitMode1 == NO) {
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
UIViewController* master = [self.viewControllers objectAtIndex:0];
UIViewController* detail = [self.viewControllers objectAtIndex:1];
[self setupPortraitMode:master detail:detail];
}
}
if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
UIViewController* master = [self.viewControllers objectAtIndex:0];
UIViewController* detail = [self.viewControllers objectAtIndex:1];
[self setupPortraitMode:master detail:detail];
}
}
}
- (void)setupPortraitMode:(UIViewController*)master detail:(UIViewController*)detail {
//adjust master view
CGRect f = master.view.frame;
f.size.width = 220;
f.size.height = 1024;
f.origin.x = 0;
f.origin.y =0;
[master.view setFrame:f];
//adjust detail view
f = detail.view.frame;
f.size.width = 548;
f.size.height = 1024;
f.origin.x = 221;
f.origin.y = 0;
[detail.view setFrame:f];
}
This works correctly under iOS4.0 but under 4.2 I see only one view when the app runs. What could change between OS versions?
I was having the same issue and I believe this to be an Apple bug (I filed it a month ago with no response from them.) For me, it was specifically the "detail" view that was blank when the app started at orientation UIInterfaceOrientationLandscapeRight (3). It would look like this: http://d.pr/cGcU. This would occur when I restricted one of the two view controllers (say, the RootViewController) to landscape-only:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
With this in place, the following would occur during the detail view's initialization:
2010-11-15 20:17:47.792 MultipleDetailViews[96250:207] firstDetailViewController willAnimateRotationToInterfaceOrientation: 3 (landscape)
2010-11-15 20:17:47.792 MultipleDetailViews[96250:207] self.view.hidden is: 0
2010-11-15 20:17:47.799 MultipleDetailViews[96250:207] rotating...
2010-11-15 20:17:47.848 MultipleDetailViews[96250:207] firstDetailViewController didRotateFromInterfaceOrientation
2010-11-15 20:17:47.849 MultipleDetailViews[96250:207] self.view.hidden is: 1
For some reason the detail view would mysteriously become hidden during rotation to orientation 3. Until Apple fixes this bug (it doesn't occur in 3.2), my workaround is currently to override the following method in the detail view controller, re-displaying the view after rotation has completed:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
self.view.hidden = NO;
}
EDIT: If your detail view isn't a direct subview of splitViewController.view (e.g. you are using a UINavigationController), you will need to set hidden on the topmost view on the detail side within the UISplitViewController:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// Make sure you set splitViewController via an outlet or get it via your AppDelegate
for (UIView *splitViewChild in splitViewController.view.subviews)
splitViewChild.hidden = NO;
}
I have had the exact same problem with my applications. I had used the same Subclassing technique to have the Master and Detail visible in both Portrait and Landscape modes. Worked great until 4.2 which, unfortunately I didn't test for when the Beta releases were available.
I recommend trying the excellent MGSplitViewController (http://mattgemmell.com/2010/07/31/mgsplitviewcontroller-for-ipad). It is an open-source implementation of the UISplitViewController. It's only drawback is that it isn't quite as easy to use in Interface Builder, but it includes a sample project. Visually it is identical to UISplitViewController, but adds support for several extras such as dragging the split position at runtime.
Just implement it exactly as your UISplitViewController but add the following line somewhere:
[splitViewController setShowsMasterInPortrait:YES];
This is very similar to the Private API that Apple prohibits using with their version.
//[splitViewController setHidesMasterViewInPortrait:NO]; // Naughty, Naughty, Not allowed by the Apple police