Phonegap 2.6 with KeyboardShrinksView and HideKeyboardFormAccessoryBar - ios

i have a problem with one of the new phonegap features in 2.6 (ios), finally they included an option to shrink the webview to handle fixed elements. Unfortunately in combination with the HideKeyboardFormAccessoryBar option set to true, a strange white bar appears instead of the AccessoryView (take a look at the screenshot).
This is not happening when i set KeyboardShrinksView to false
has anyone experienced a similar problem with the new version? is this a bug or a feature? ;)
cheers
horst.

This is a bug. It's caused by the WebView not being resized properly after the keyboard is displayed. By default, PhoneGap resizes the height of the WebView by subtracting the view frame by the height of the keyboard. But, it doesn't take into account the fact that the form accessory bar is hidden in that calculation.
Here's a temporary solution to this while PhoneGap fixes this bug:
In CDVViewController.m (under Classes/Cleaver), go to line 140. It should be within the (void) keyboardWilLShowOrHide function. In the showEvent if statement, it calculates the new size of the WebView based on the height of the keyboard.
Change the contents of the if statement to:
if (showEvent) {
newFrame.size.height -= keyboardFrame.size.height;
if ([#"true" isEqualToString: self.settings[#"HideKeyboardFormAccessoryBar"]]) {
newFrame.size.height += 45;
}
}
I added an extra if statement that also checks for the HideKeyboardFormAccessoryBar configuration. If it's set, it'll increase the size of the WebView by an additional 45 pixels (the height of the form accessory bar).

While the keyboard is transitioning up, it seems the webview is already resized and the background is white, thus causing the white background to be shown. My HTML body background is black so it looks odd when the white background flashes. Does anyone know how to update the background of the UIView?
Video reproducing the issue in slow motion.
http://www.youtube.com/watch?v=iOjdxJuYp8c
Thanks!
Tom
Edit: I was able to change the background color by adding this code to MainViewConetroller.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.view.backgroundColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1];
}

It's definitely a bug. The phonegap dev team is going to fix this issue in the 2.7 release in a few weeks.

I have just checked my code and I have 2.6 and this fix is already there. But it is not working and I still see the grey bar with the same conditions. How that could be?
EDIT: It looks like that one of my teammates did this fix and solved the issue. The thing is that you still can see the grey space and it is removed very quickly.

Related

Properties assigned to UIButton in ViewController.swift and segue works on Simulator but not on Device

I have an extremely bizarre problem. I created a UIButton and put it on my ViewController storyboard. I added a segue from the Button to another ViewController by pressing control and dragging. I also added an outlet to the corresponding ViewController file and added a border color and width (to the button). The segue and the button border work fine on the simulator but on a device the button border does not show up and the segue does not work.
The only thing I can think of that could be causing the problem is that a little while ago I accidentally deleted my Main.storyboard, so I dragged it from my trash back to my Xcode project. But I am pretty sure my app has worked on the device even after that incident. I wasn't sure if my viewDidLoad method was being fired (since that is where I set my border color and width for the button) so I added a print statement and found out that it was indeed being called. Take a look at the code below...
override func viewDidLoad() {
super.viewDidLoad()
print("Begin Setup Process...")
// Do any additional setup after loading the view.
calibrateButton.layer.borderColor = UIColor.white.cgColor
calibrateButton.layer.borderWidth = 3
}
How would I get this to work on my device as well? What I am doing wrong
Assign Your Border Styling Here...
Try adding the code to change layer properties of calibrateButton in viewDidLayoutSubviews(), i.e.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
calibrateButton.layer.borderColor = UIColor.white.cgColor
calibrateButton.layer.borderWidth = 3
}
Also, since you're giving borderColor as white, that might not be visible if the calibrateButton is placed on a white background. Try changing it to something else that is more visible, red for example.
First try in viewDidAppear(), if it works then cut and paste it in viewDidLayoutSubviews().
I finally solved the issue. The problem was that I didn't have a height constraint on my button. I am still not exactly sure why or how this issue occurred. Why couldn I see the button text but not the border? If the segue was not working there must have been a view on top of the button that was preventing it from going off. But anyway adding a height constraint solved the problem. In answering my own question I realize that the title of my question is misleading in relation to the solution of the problem. This problem, in the end had nothing to do with wether the app was running on a simulator or the device. I just assumed it was a device issue since it was working fine on my iPhone XR simulator but not my actual iPhone 6s. However the actual problem was the screen size and how my constraints adapted to it.

iOS8 touch position is limited in Landscape, as if window is Portrait on one side?

I'm having a bizarre problem here with iOS8. I've been googling and bashing my head against a wall for a couple of days with no luck. I'm not exactly sure how to even explain it, but here goes...
Apps have been running fine under iOS7, but now compiling using xCode 6/iOS8 I'm having a few strange orientation problems. I'm not using a xib file, but instead creating a window and view programatically. I'm running OpenGL in the view, and then handling everything else inside OpenGL. So, I'm collecting touches and passing them to my GL routines. All has been fine forever, til now.
Now with iOS8 it seems as if the "touch window" is rotating itself so that touches in Landscape are limited to one side of the screen, as if the display window is Landscape, but the touches are all within a Portrait window that is set to on one side of the screen.
What seems bizarre is that touches come through to the view all over the screen as normal, but the Y value stops at 320 and goes no further. The X acts normally. If I turn the device to Portrait (the view controller does not auto rotate), it all works, but in Landscape it switches to this strange behaviour.
I've tried all I can think of without any changes, and am not sure where to begin to work out why this could be happening. Any advice would be greatly appreciated.
On iOS8, UIScreen is now interface oriented. In some (or should I say all of) libraries before iOS8, some checks were done to adjust that lack and swap width and height when the application was in landscape.
You should look at some code that makes some rotation and remove it.
-[UIScreen bounds],
-[UIScreen applicationFrame],
Status bar frame and
Keyboard frame are now interface-oriented.
(cf. WWDC2014 video - view controller advancements in iOS8 # 50:41)
In our case.
Force to rotate with view's transform caused that problem.
We removed that code, rotate with
+ (void)attemptRotationToDeviceOrientation
and problem solved.
We called that method at our forceRotate method.
-(void)forceRotateLandscape {
...
UIViewController *vc = [UIViewController new];
[topVc presentViewController:vc animated:NO completion:nil];
[topVc dismissViewControllerAnimated:NO completion:nil];
supportedOrientations = UIInterfaceOrientationMaskLandscapeRight;
[UIViewController attemptRotationToDeviceOrientation];
...
}
My guess is that whatever view owns the gesture recognizer isn't getting resized during the rotation for one (or more) of the following reasons:
It uses auto layout and isn't pinned to its superview
It uses springs and struts and doesn't have the correct UIViewAutoresizing mask
It lives in a subview that isn't getting resized
If you're using auto layout, try this in your view controller:
- (void)viewDidLayoutSubviews
{
// For each subview with its own auto layout:
[self.mySubview layoutSubviews];
// ...
[super viewDidLayoutSubviews];
}
Ok, I've found the issue on my side (I'm the bounty giver).
We were probably using some kind of hack in our App to manually handle the rotation of our views, because we were returning 0 to the - (NSUInteger)supportedInterfaceOrientations in our rootViewController.
- (NSUInteger)supportedInterfaceOrientations {
return 0; // BOOOOOOO, even forbidden by documentation
}
Then we manually managed our internal views by listening to the UIDeviceRotationChanged notification, rotating them views, and asking the statusBar to rotate as well.
Returning something not 0 to this supportedInterfaceOrientations made the "touch" layer rotate along with the rest.
But now we have to make the code evolve to use iOS rotation instead of our hacky layer.
Also, after investigating more, especially on iPad, you have to use a Storyboard-based UIWindow.
Using a XIB-based window will result in its dimensions being wrong when the app is launched while in landscape. This leads to a mountain of buggy frames and messes up badly with our layout.
I had the same problem. In iOS7 all worked fine, in iOS8 it was like the "touch-view" was still in portrait.
I just replaced the main xib with a storyboard, no other change (i've tried a lot playing with screen bound and frame without any results).
Just try it out, let me know if it work also for you. Good luck.
I have the same issue with second window in landscape. It refuses to display itself on the full screen and also to receives touch events on the cut part of the screen. The only solution that I found so far is to enable support of the iPhone6/6+ native resolutions by adding required launch screens. If you do not support these resolutions in your app that might be the same problem.

View is pushed down by about 20px, but is fixed when I rotate screen

I have a viewcontroller(Nib) that is invoked from two different places. When I invoke it from one place, all looks fine but from the other it always seems to have a 20px(looks like enough for the status bar) offset up top..
If I rotate the device this goes away and it looks OK..I've been troubleshooting this since yesterday with no luck - As far as I can tell I'm not doing anything different when I load the screen..
I'm not really sure what code to paste, as from both places they are being called in the same way, I'm looking for any ideas - even if it's not an answer as I seem to be out of ideas.
Screenshot,
Did you try setting edgesForExtendedLayout in viewDidLoad?
if ( IS_OS_7_OR_LATER && [self respondsToSelector:#selector(edgesForExtendedLayout)] ) {
self.edgesForExtendedLayout = UIRectEdgeNone;
}
EDIT: here is the iOS 7 Transition Guide from Apple if you want more info on how this is fixed for iOS 7
I hope that these questions will help us and you to pinpoint the problem:
Are you invoking the VC using Interface builder or programmatically?
Have you added any or none constraints?
My best guess would be that you try to load the VC from:
- (void)viewWillLayoutSubviews
rather then
- (void)viewDidLoad
The reason for this suggestion is that the screen bounds are not properly loaded in viewDidLoad which you can check by printing self.view.bounds.width & self.view.bounds.height. In viewDidLoad they are not set correctly. This can lead to many later problems. This is just a wild guess.
Hope it helps.

UISearchDisplayController's full-screen background intercepts touch events in iOS 7

I have a UITableview that doesn't take up the whole screen (screenshot). Everything worked fine in iOS 6. But in iOS 7, when the user searches, the search result table takes up the whole view (screenshot).
To fix this, I tried setting the frame manually as described in this answer. The appearance is now correct (screenshot), but now the "<" button in the top left doesn't receive tap events when the search results table is displayed.
It seems the searchResultsTableView is adding a full-screen background view that is intercepting touch events. To prove this, I added this code to didShowSearchResultsTableView:
controller.searchResultsTableView.superview.backgroundColor = [UIColor blueColor];`
This screenshot confirms my hypothesis.
How can I fix this to allow the "<" button to receive tap events?
I want to avoid modifying controller.searchResultsTableView.superview so that my change doesn't break in future versions of iOS.
And what change in iOS 7 caused this behavior to start happening?
I am still searching for a better solution, but currently my solution is in the viewControllers viewDidLayoutSubviews tell your view to move to front. The code would look something like this.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.view bringSubviewToFront:self.navigationBar];
}

Why UISearchBar and its scope buttons are shown in one line?

I have seen Apple's example "TableSearch" that when touched its scope buttons come below the search bar.
http://developer.apple.com/iphone/library/samplecode/TableSearch/Introduction/Intro.html
But when I make my own it looks good at first but when I touch it looks like ugly, scope buttons and search bar are shown in the same line like this:
http://cl.ly/BN9
What do I have to do make it like "TableSearch" example in the iPad?
I am doing everything in IB and tried to modify the search bar programatically from the controller:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = 88.0f;
self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height);
self.searchDisplayController.searchResultsTableView.rowHeight = self.tableView.rowHeight;
//BELOW DID NOT WORK:
CGRect b = self.searchDisplayController.searchBar.bounds;
self.searchDisplayController.searchBar.bounds = CGRectMake(b.origin.x, b.origin.y, b.size.width, self.tableView.rowHeight);
b = self.searchDisplayController.searchBar.frame;
self.searchDisplayController.searchBar.frame = CGRectMake(b.origin.x, b.origin.y, b.size.width, self.tableView.rowHeight);
//BELOW WORKS PERFECT BUT IS A PRIVATE METHOD, HENCE I AM NOT SUPPOSED TO USE IT
//[self.searchDisplayController.searchBar setCombinesLandscapeBars:NO];
}
Thanks in advance.
I've encountered this bug as well, and I've both filed a report with Apple and requested technical assistance. I'll let you know how it goes. In the meantime I'll give you a brief bit of background on this bug.
On the iPhone, to preserve precious vertical screen real estate in Landscape mode, the UISearchDisplayController sets the UISearchBar to combine its search bar and search field in a single horizontal layout. This works pretty well because of the increased horizontal size of the screen (480 points in Landscape). Unfortunately, it works not so well on the iPad, where in Landscape mode the UI change really isn't necessary in the first place because you have plenty of vertical real estate. You also still only have 320 pixels of horizontal display space in the master view of the UISplitViewController, not the increased 480 of the iPhone. The result is an iSore.
Presumably the problem is that UISearchDisplayController is behaving badly in its willRotateToInterfaceOrientation:duration‎: method. Specifically, it's not bothering to check whether it's on an iPhone or not before it sets the combinesLandscapeBars property on its UISearchBar. The private API kludge in your code works because it fixes that oversight in the UISearchDisplayController. But of course Apple will rain down the fury of the ancients on you for using undocumented APIs, so you can't. Really we're at the mercy of Apple on this one.
If you're willing to give up the eye-candy and convenience of UISearchDisplayController, you can use a UISearchBar sans UISearchDisplayController and manage aspects of presentation yourself. Obviously this requires a lot more code and would be pointless if Apple's API engineers did their jobs, but it will at least resolve the display bug.
If you're Apple you can use your own undocumented APIs, which is why Mail.app doesn't have this problem.
UPDATE
The bug report I've filed with Apple is #8344719.
Using the following code, you will not get warning:
if ([self.searchDisplayController.searchBar respondsToSelector:#selector(setCombinesLandscapeBars:)])
{
objc_msgSend(self.searchDisplayController.searchBar, #selector(setCombinesLandscapeBars:), NO );
}
When you set the bounds and frame for the searchBar, like for the frame here:
blabla.searchBar.frame = CGRectMake(b.origin.x,
b.origin.y,
b.size.width,
self.tableView.rowHeight);
it seems like there is a problem with height. Scope buttons require some space under the search bar, so you should increase the height of both bounds and the frame.
If you show and hide scope buttons on some event you need to adjust the frame size each time.
I'm getting this issue on an iPad, but I can get it to work if I insert this in my implementation file:
#synthesize tableView;
I'm guessing there is something bad with the XIB being loaded, but I don't know why this would fix it.

Resources