I've lost enough sleep trying to figure this one out. I have a tabbed application that supports all orientations. Everything works completely fine when the app starts in portrait and switches to landscape. When the app starts in landscape however and then switches to portrait, I lose response ONLY on the bottom quarter of the screen! It's as if something in the background is not adjusting the "user interaction" area from landscape bounds to portrait bounds when the orientation changes.
I have two tabs at the moment. When I switch to the second tab, and then back to the first, the problem goes away! I'm able to interact with the bottom quarter of the screen again. I've gotten that similar problem before when I setup the tab view controller away in viewDidLoad as opposed to viewDidAppear. Everything is in viewDidAppear now.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
NSArray* controllers = nil;
TimeTableViewController * timeTableViewController = [[TimeTableViewController alloc] init];
FRLayeredNavigationController *timeTableNavController = [[FRLayeredNavigationController alloc] initWithRootViewController:timeTableViewController configuration:^(FRLayeredNavigationItem *item)
{
item.hasChrome = YES;
}];
timeTableNavController.dropLayersWhenPulledRight = true;
TestViewController* vc2 = [[TestViewController alloc] init];
timeTableNavController.tabBarItem = [[UITabBarItem alloc]
initWithTitle:#"Student Lookup"
image:[UIImage imageNamed:#"search_gray.png"]
tag:0];
timeTableNavController.tabBarItem = [[UITabBarItem alloc]
initWithTitle:NSLocalizedString(#"Attendance", #"Attendance")
image:[UIImage imageNamed:#"attendance_gray.png"]
tag:0];
timeTableNavController.view.backgroundColor = [UIColor lightGrayColor];
controllers = [NSArray arrayWithObjects:timeTableNavController,vc2, nil];
self.viewControllers = controllers;
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
I don't think the FRLayeredNavigationController library is an issue. Is there any method I can call that readjusts the "area of response" when switching from landscape to portrait? That would be a life-saver. Someone please beat some sense into me!
In fact when you start your app in landscape mode, it should starts in portrait and then your viewcontroller need to rotate this.
In fact you have 3 approaches:
First and i think the best:
https://stackoverflow.com/a/10533561/2204866
Or you can create separates views with separate xib's for each
mode.
Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape?
And the last use auto layout.
Related
I am trying to create my first iphone app and I have a view that is supposed to be pitch black. My view is connected to my controller properly (my label shows when I run the simulator).
I want to add a black layer (so the screen looks like the iphone is off). Not only this, when the user pushes or interacts with the screen it should only be triggering those actions onto the black layer. I will have something underneath that layer, like a label persay.
When I set the brightness to 0.0 in my controller and run the simulator it still shows the view:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[UIScreen mainScreen] setBrightness: 0.0]; //<-- here
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIScreen mainScreen] setBrightness: 0.0]; //<-- here as well. but nothing happens
self.navigationItem.hidesBackButton = YES;
// Do any additional setup after loading the view.
}
Also, I feel like setting the brightness would still allow the user to interact with the screen, which isn't what I want. Could anyone help? Could I just add a black image or something?
You could add a completely black UIView on top of your current view.
UIView *blackView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
blackView.backgroundColor = [UIColor blackColor];
[viewIWantToObscure addSubview:blackView];
This would render the view you want to cover up (viewIWantToObscure) completely blacked out. As for the second part of your requirement, touching though the view, more infromation about sending touches up the view hierarchy can be found here.
You have to place the setBrightness statement in - (void)applicationDidBecomeActive:(UIApplication *)application -- it has no effect anyplace else. To clean up after your app, you should restore brightness in - (void)applicationWillResignActive:(UIApplication *)application.
I have a question about CvPhotoCamera (OpenCV) in the iOS App.
I have a myViewController1: in this viewController I push a mySecondView controller.
In this second View Controller I use CvPhotoCamera:
I have a UIImageViewController.
In viewDidLoad I have this code:
- (void)viewDidLoad
{
[super viewDidLoad];
_photoCamera = [[CvPhotoCamera alloc] initWithParentView:imageView];
_photoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetPhoto;
_photoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
[_photoCamera setDefaultAVCaptureDevicePosition:AVCaptureDevicePositionBack];
_photoCamera.delegate = self;
[_photoCamera start];
}
in viewDidDisappear I have this code:
- (void) viewDidDisappear:(BOOL)animated
{
[_photoCamera stop];
}
I use CvPhotoCamera to take a photo from camera using the method:
- (IBAction)actionStart:(id)sender;
{
[_photoCamera takePicture];
}
The my problem is this:
When I push this second ViewController and I tap on back button on Nav bar I have some memoryWarning and the app crashes ..always!!!
I used also the profile Xcode tool to manage memory allocation or memory leak but I do not see anything strange.
Is correct this use of CvPhotoCamera obj?
I tried to implement stripe into an iOS app through its online documentation. Everything good so far, now pushing the paymentView onto my navigation controller stack I get a completely broken screen. Thought it'd be a problem with the stripe view but when I do not log in (see code below - no identification token given) and the login screen is being pushed instead, it is completely black too. It cant be a problem with that view cause it loads just fine if I push the login view from another view before this one.
So why does pushing view via the buyButtonAction below give me black / fucked up screens?!
Ive been on this for hours.. nothing seems to work.
A pic:
the important code part:
#interface PaymentViewController ()
#end
#implementation PaymentViewController
#synthesize stripeCard = _stripeCard;
#synthesize stripeView;
#synthesize passedProductId;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.stripeView = [[STPView alloc] initWithFrame:CGRectMake(15,20,290,55)
andKey:#"pk_test_45mqixOu8N9S4lQ6cdn1OXBD"];
self.stripeView.delegate = self;
[self.view addSubview:self.stripeView];
}
And the call:
-(void)buyButtonAction:(id)sender
{
tokenClass *tokenObject = [tokenClass getInstance];
NSLog(#"%#", tokenObject.token);
if (tokenObject.token == nil) {
LoginController *loginController = [[LoginController alloc] init];
[self.navigationController pushViewController:loginController animated:YES];
} else {
NSLog(#"%#", tokenObject.token);
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
PaymentViewController *payView = [[PaymentViewController alloc] init];
payView.passedProductId = [[self.productData valueForKey:#"id"] objectAtIndex:hitIndex.row];
NSLog(#"passing %#", payView.passedProductId);
// push payment view
payView.navigationItem.title = #"One-Click-Payment";
[self.navigationController pushViewController:payView animated:YES];
}
}
We can see that there's a view behind the navigation bar. It's an iOS 7 related issue. Add this line to your viewDidLoad:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
Or change your self.stripeView frame by adding 64 to y:
CGRectMake(15,84,290,55)
Useful link: https://stackoverflow.com/a/18103727/1835155
I'm practicing on how TabViewcontroller works. Now I have 2 subclasses of UIViewcontroller.
One is HypnosisViewController , the other is TimeViewController.
What I wanted to check is how -(void)viewDidLoad works when IOS simulator gets memory warning.
And I did
Built and ran the app
The console said "HypnosisViewcontroller loaded its view."
Switched the other tab (TimeViewController)
Saw the message in the console. It says "TabViewcontroller loaded its view"
Did the simulator memory warning command in IOS simulator
The console said "HypnoTime Received memory warning."
Switched back to the HypnosisViewcontroller to see whether the console says "HypnosisViewcontroller loaded its view." again.
So the problem here is HypnosisViewcontroller is not destroyed and created again. (Because I can't see the log message when I switch back to HypnosisViewcontroller.)However I leaned the view not on the screen should be destroyed during the memory warning.
Did I miss something? Thanks in advance!
HypnosisViewController.m:
#import "HypnosisViewController.h"
#import "HypnosisView.h"
#implementation HypnosisViewController
-(void)loadView
{
//Create a view
CGRect frame = [[UIScreen mainScreen] bounds];
HypnosisView *v = [[HypnosisView alloc] initWithFrame:frame];
// Set it as *the* view of this view controller
[self setView:v];
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
self = [super initWithNibName:nil
bundle:nil];
if(self){
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a label
[tbi setTitle:#"Hypnosis"];
//Create a UIImage from a file
//This will use Hypno#2x.png on retina display devices
UIImage *i = [UIImage imageNamed:#"Hypno.png"];
// Put that image on the tab bar item
[tbi setImage:i];
}
return self;
}
-(void)viewDidLoad
{
// Always call the super implmetaion of viewDidload
[super viewDidLoad];
NSLog(#"HypnosisViewcontroller loaded its view");
}
#end
TimeViewController.m:
#import "TimeViewController.h"
#implementation TimeViewController
-(IBAction)showCurrentTime:(id)sender
{
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
[timeLabel setText:[formatter stringFromDate:now]];
[timeLabel2 setText:[formatter stringFromDate:now]];
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
// Call the superclass's designated initializer
self = [super initWithNibName:nil
bundle:nil];
//Get a pointer to the application bundle object
// NSBundle *appBundle = [NSBundle mainBundle];
// self = [super initWithNibName:#"TimeViewController"
//bundle:appBundle];
if(self){
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a label
[tbi setTitle:#"Time"];
//Create a UIImage from a file
//This will use Time#2x.png on retina display devices
UIImage *i = [UIImage imageNamed:#"Time.png"];
// Put that image on the tab bar item
[tbi setImage:i];
}
return self;
}
-(void)viewDidLoad
{
// Always call the super implmetaion of viewDidload
[super viewDidLoad];
NSLog(#"TimeViewcontroller loaded its view");
// [[self view] setBackgroundColor:[UIColor greenColor]];
}
#end
Memory Warnings don't cause the Controllers to destroy/unload their views anymore.
It is working properly. And HypnosisViewcontroller was destroyed and created again, because viewDidLoad will be called only when all the views are initiated. So here you see the log message again when you switch back to HypnosisViewcontroller which represent that HypnosisViewcontroller has been purged from memory and initiated again. You can try switch between these two view controllers without simulating memory warning, and you will only see the log message once.
Since the iOS7 upgrade, I have a weird behaviour of the UIImagePickerController. In this application I am using the UIImagePickerController with a cameraOverlayView.
In iOS6 I called the UIImagePickerController using the following code:
_picker = [[UIImagePickerController alloc] init];
if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {
_picker.sourceType = UIImagePickerControllerSourceTypeCamera;
_picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
_picker.cameraDevice = UIImagePickerControllerCameraDeviceRear;
_picker.showsCameraControls = NO;
_picker.navigationBarHidden = NO;
_picker.toolbarHidden = YES;
_picker.wantsFullScreenLayout = YES;
_overlayViewController = [[OverlayViewController alloc] init];
_overlayViewController.picker = _picker;
_overlayViewController.frameSize = self.frameSize;
_overlayViewController.delegate = self;
_picker.cameraOverlayView = _overlayViewController.view;
}
else {
_picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
_picker.delegate = self;
Where the OverlayViewController is an UIViewController, with a transparent background which draws some custom controls on screen.
But now in iOS 7 the camera is drawn through the statusbar and a black bar appears beneath the live camera view.
I can solve this by applying a CGAffineTransformMakeTranslation to the cameraViewTransform property of the UIImagePickerController, but why is this like this?
In iOS 7, by default UIViewController views take up the entire screen area including the status bar.
wantsFullScreenLayout
is deprecated and ignored. In some cases, this fix works (in the view controller class):
if ([self respondsToSelector:#selector(setEdgesForExtendedLayout:)]) {
[self setEdgesForExtendedLayout:UIRectEdgeNone];
}
In other cases, it's a bit more complicated. It's late here, so see how you go with it. Helpful things to note - in a UIViewController, the following code will give the correct statusbar height on both iOS 6 and iOS 7, should it come to having to align things using CGRect math:
if (UIDeviceOrientationIsLandscape(self.interfaceOrientation)) {
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.width;
} else {
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
}
And then don't forget that in Interface Builder, there are the new "iOS 6 delta" adjustments that allow you to design for iOS 7 and then use offsets to correct for iOS 6.
Anyhow, let me know how you go.
My understanding of the issue, based on a few other SO threads and such, is that UIImagePickerController does not do what we'd expect in terms of managing the status bar via [UIViewController -prefersStatusBarHidden].
This means you either have to disable view controller status bar management entirely, via plist, or figure out a way to get UIImagePickerController to do what we want. On the assumption that you're not looking for the former, I can say I've had success in the latter by putting the picker in a wrapper controller that does what I want (but fall back to your previous code if you still need to detect/support iOS6):
#interface PickerContainer : UIViewController
#property ( nonatomic, weak ) UIImagePickerController* picker;
#end
#implementation PickerContainer
- (void) setPicker: (UIImagePickerController*) picker
{
[self addChildViewController: picker];
[picker didMoveToParentViewController: self];
self->_picker = picker;
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.picker.view.frame = self.view.bounds;
[self.view addSubview: self.picker.view];
}
// Will have no effect in ios6 -- see [-init] for that option
- (BOOL) prefersStatusBarHidden { return YES; }
- (id) init
{
if ( ! ( self = [super init] ) ) return nil;
if ( detectThatThisIsIos6() ) self.wantsFullScreenLayout = YES;
return self;
}
#end
This will work for you, scaled camera, you will have a black bar at the bottom but it will get overlayed by tool bar
https://stackoverflow.com/a/15803947