UIActivityViewController Print Dialog UI Glitches (Bugs?) - ios

I have some strange UI glitches using an UIActivityViewController when on iPad.
Complicated to tell, so here are two videos. One showing the iOS6 behavior and one the faulty iOS7 one:
iOS6: http://quick.as/govpsry7
iOS7: http://quick.as/qr7jtd8b
1st Issue: The arrow is a little bit off it's position on iOS7 (by design?). Common UINavigationBar with UIBarButtonItems.
Code to present the popover (on iPad):
ActivityPopover = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
[activityPopover presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
Nothing fancy here. Sender is the UIBarButtonItem.
2nd Issue: Selecting Print from UIActivityViewController PopOver has some UI transition issues on iOS7. The new Print Options PopOver moves into the view from the left, moving the desaturated background of the whole screen too. Best seen in the 2nd video.
3rd Issue: As seen, when the Print Options dialog is opened the content of the UIWebView adjusts somehow. I don't see a reason for this.
The 1st and 2nd issue even occur when browsing to "about:blank".
Does anybody know something about these glitches? Common bugs?
Edit: The 1st and 2nd look like iOS7 Bugs. I tried SVWebViewController from Sam Vermette and inserted my test code.
In SVWebViewController.m of the Demo insert:
#interface SVWebViewController () <UIWebViewDelegate>
#property (nonatomic, strong) UIBarButtonItem *backBarButtonItem;
#property (nonatomic, strong) UIBarButtonItem *forwardBarButtonItem;
#property (nonatomic, strong) UIBarButtonItem *refreshBarButtonItem;
#property (nonatomic, strong) UIBarButtonItem *stopBarButtonItem;
#property (nonatomic, strong) UIBarButtonItem *actionBarButtonItem;
#property (nonatomic, strong) UIPopoverController *popover; // added
Later in file, at the very bottom, adjust:
- (void)actionButtonClicked:(id)sender {
NSArray *activities = #[[SVWebViewControllerActivitySafari new], [SVWebViewControllerActivityChrome new]];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:#[self.self.webView.request.URL, self.self.webView.viewPrintFormatter] applicationActivities:activities];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.popover = [[UIPopoverController alloc] initWithContentViewController:activityController];
[self.popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentViewController:activityController animated:YES completion:nil];
}
}
This produces the same UI glitches when touching the Activity PopOver and Print Icon.
So it is reproducible with a simple demo, too.
Environment: SDK 7.0, current public Xcode (as of 02/25/2014). Targets: iOS6 and iOS7.
Edit 2/3:
Regarding the 3rd Issue I found this, so it's already reported: http://openradar.appspot.com/8668247
Regards,
Frederik

Verified all three Issues to be Apple iOS Bugs.
The 1st and 2nd are visible by Demo mentioned above. The 3rd is even with the Google Browser App visible (on iPad). Source of the 3rd issue is the scaling reset of UIWebView viewPrintFormatter during dialog popup (in fact an internal UIActivity prepareAction).

Related

How to create an App using the Single View App template where the main window does not rotate but the rest does?

How to create an App using the Single View App template where the main window does not rotate but its rootViewController and everything else autorotates?
Apple does that on CIFunHouse but because the code is poorly explained in that matter, it is impossible to know how they did it. If you run the app you will see that the camera's preview window does not autorotate because the preview was added to the window but everything else does.
Apple uses this technique on their native iPad camera app.
So the answer is not clean but I can give you a fix. At some point the main application window must not have autorotated like it does now but at some point it started rotating according to the rootviewcontroller. At least this source code suggests that. I started developing at the end of iOS 6 and I think this source was written about that time. The best fix I could find for allowing everything to rotate in the example for me but having the preview to not rotate was to add a second window. Set the main window background to clear. Then add the previewLayer to the second window behind the main window. In code it would look like this.
The AppDelegate looked like this.
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>
#interface FHAppDelegate : UIResponder <UIApplicationDelegate>
{
#private
CMMotionManager *_motionManager;
}
#property (strong, readonly, nonatomic) CMMotionManager *motionManager;
//future preview window
#property (strong, nonatomic) UIWindow *previewWindow;
#property (assign, readonly, nonatomic) UIDeviceOrientation realDeviceOrientation;
#end
Then in the viewDidLoad of the FHViewController instead of adding to the main window I did this and it added where they get the main window I add the previewView to that.
// we make our video preview view a subview of the window, and send it to the back; this makes FHViewController's view (and its UI elements) on top of the video preview, and also makes video preview unaffected by device rotation
//nothing special about this viewcontorller except it has
//-(BOOL)shouldAutorotate{
//return NO;
//}
TestViewController *test = [[TestViewController alloc]initWithNibName:#"TestViewController" bundle:nil];
FHAppDelegate *delegate = ((FHAppDelegate *)[UIApplication sharedApplication].delegate);
delegate.previewWindow = [[UIWindow alloc]initWithFrame:window.bounds];
UIWindow *previewWindow = delegate.previewWindow;
[window setBackgroundColor:[UIColor clearColor]];
previewWindow.rootViewController = test;
previewWindow.windowLevel = UIWindowLevelNormal - 1;
[previewWindow setBounds:delegate.window.bounds];
[previewWindow makeKeyAndVisible];
[previewWindow addSubview:_videoPreviewView];
[previewWindow sendSubviewToBack:_videoPreviewView];
Because the previewWindow has to have a rootviewcontroller and it determines the rotation you can see my testviewcontroller has autorotate of NO. Hope this helps. It is working for me on iOS 10.
Edit: The view in the example above does not rotate but the window animation on rotation is bad visually. It can be removed by overriding
willTransitionToSize
[UIView setAnimationsEnabled:NO];
and after completion
[UIView setAnimationsEnabled:YES];
See swift version on GitHub
For an iPad requires Full Screen must be check.
With using navigation controller you can create an Objective-C category like and use these in sub viewcontrollers
#import "UINavigationController+Orientation.h"
#implementation UINavigationController (Orientation)
- (NSUInteger)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate {
return YES;
}
#end
For Swift
extension UINavigationController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .portrait
}
open override var shouldAutorotate: Bool {
return true
}
}

addSubView not adding subview

I have an app that should display a Youtube video and I'm using the Youtube ios helper API.
I have a subclass of UITabBarController that is used to present two youtube videos and the UITabBarController is inside a NavController and is pushed to from a UITableViewController. So the setup looks like
[NAVController] -- relationship --> [UITableViewController] -- push --> [UITabBarController] -- relationship --> [CustomViewController]
Now my CustomViewController.h looks like:
#import <UIKit/UIKit.h>
#import "YTPlayerView.h"
#interface CustomViewController : UIViewController<YTPlayerViewDelegate>
#property (strong, nonatomic) YTPlayerView *youtubeView;
#property (strong, nonatomic) NSString *videoID;
#end
and my .m file has
#import "CustomViewController.h"
#import "YTPlayerView.h"
#interface CustomViewController ()
#end
#implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.youtubeView.delegate = self;
self.view.backgroundColor = [UIColor blueColor];
self.youtubeView.frame = self.view.frame;
self.youtubeView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.youtubeView];
NSLog(#"Subviews %lu", (unsigned long)[self.view.subviews count]);
NSLog(#"Subviews %#", self.views.subviews);
BOOL b = [self.youtubeView loadWithVideoId:self.videoID];
NSLog(#"Loaded? %d", b);
[self.youtubeView playVideo];
}
What I end up with is a navigation bar at the top (as it should be), a tab bar at the bottom (as it should be), but with a blue background instead of a red background (and needless to say, no Youtube video loads). When I run this, it prints
Subviews 0
Subviews (
)
Loaded? 0
Clearly the addSubView: call is not working.
I've seen this post, but it didn't help.
(For those unfamiliar with the youtube ios helper library:
The youtube-ios-player-helper is an open source library that helps you embed a YouTube iframe player into an iOS application. The library creates a UIWebView and a bridge between your application’s Objective-C code and the YouTube player’s JavaScript code, thereby allowing the iOS application to control the YouTube player.
(Using iOS 7 and Xcode 5.1)
Since I don't see that you're using an IBOutlet, I believe you need to initialize the self.youtubeView:
self.youtubeView = [[YTPlayerView alloc]init];
self.youtubeView.delegate = self;
self.view.backgroundColor = [UIColor blueColor];
self.youtubeView.frame = self.view.frame;
self.youtubeView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.youtubeView];
The YouTube api isn't the problem here, UINavigation controller and UITabBarController just dont play nicely together. What you should do instead is make a view controller to handle the tabbar instead of a UITabBarController. This shows some insight on how to get it done.

Memory is not released under ARC

I have an app with a parent View Controller. It has some buttons and when one of them is clicked it presents a Modal View Controller (using XIB). The code I use to present and dismiss the Modal VC is :
iPadViewController *iPadVC = [[iPadViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:iPadVC animated:YES completion:NULL];
and to dismiss :
-(IBAction)Back:(id)sender{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
So the problem is, when I dismiss it, it does not release any memory. And if I present it 3/4 times it crashes. I am using ARC, never had similar problems because I tough that ARC did all the memory management job.
I do have some backgrounds that need a lot of space and they are not getting released either. I tried :
[backgroundImage removeFromSuperview];
backgroundImage=nil;
The memory does decrease using this code, I'm not sure if the image was released because the next time I press the button the memory increases to almost 300mb and terminates due to "memory pressure". If the VC was released it would work fine because it only uses 160mb on the iPad and 65mb on the iPhone. Also, My image is selected through the Xib utilities :
And I tried to use Xcode instruments and it does not show any leak (!) but it does show that the allocations are growing and growing every time I click a button.
and on my ViewController.h:
IBOutlet UIImageView (...);
IBOutlet UIImageView (...);
IBOutlet UILabel (...);
IBOutlet UIButton (...);
IBOutlet NSTimer (...);
IBOutlet UIImage (...);
IBOutlet UIView (...);
-(IBAction)Back:(id)sender;
#property (nonatomic, assign) int ;
#property (nonatomic) IBOutlet UIButton ;
#property (nonatomic) IBOutlet UIButton ;
#property (nonatomic) IBOutlet UIButton ;
#property (nonatomic) IBOutlet UIView ;
#property (nonatomic) IBOutlet UILabel ;
I tried to give all the details about my code, but if you need anything else just let me know, and thank you all so much!
If Your images are big please see this question: Problem dealloc'ing memory used by UIImageViews with fairly large image in an UIScrollView
To sum up: when using nib files all the assigned images are loaded using
[UIImage imageNamed]
method which is known to cause huge memory allocations because it always caches the images.
Try assigning the images to views in the code with
[UIImage imageWithContentsOfFile:path];
method (it is described in the answer to above question).
In the modal view controller:
[self dismissViewControllerAnimated:TRUE completion:Nil];
In the main View controller check it exists first before presenting it:
iPadViewController *iPadVC;
if (iPadVC == Nil)
iPadVC = [[iPadViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:iPadVC animated:YES completion:NULL];
Sounds like iPadVC is always in scope so ARC may not be releasing it.

Custom view which looks like UIAlertView

I need something what looks like UIAlertView (same background transparent and not full screen), blocks other UI parts and has some custom content.
This custom content are: two check-boxes with labels and two buttons YES/NO at the bottom.
Sub-classing or customizing UIAlertView doesn't looks useful (see this answer) and it is dangerous (code can be rejected by Apple). I was thinking to create own custom UIView (possible with UIViewController), but I have no idea how to make it look and feel like UIAlertView. I mean I'd like to make it that it changes its appearance dependent on iOS version (iOS7).
update:
I can abandon os version dependency, it would be nice to have, but this is additional feature.
The main question is: is there a good way to make such view which will look and feel like UIAlertView without large amount of work? Customizing UIAlertView directly looks complicated and dangerous.
I created my own custom view to look like iOS UIAlertView 7. With that technique you can create a custom alert for both iOS 6 and iOS 7.
For that, I created a UIView in my xib file of my UIViewController :
I added some #property for this view :
// Custom iOS 7 Alert View
#property (nonatomic, weak) IBOutlet UIView *supportViewPopup; // My UIView
#property (nonatomic, weak) IBOutlet UIView *supportViewPopupBackground; // The grey view
#property (nonatomic, weak) IBOutlet UIView *supportViewPopupAction; // The white view with outlets
// Property for customize the UI of this alert (you can add other labels, buttons, tableview, etc.
#property (nonatomic, weak) IBOutlet UIButton *buttonOK;
#property (nonatomic, weak) IBOutlet UIButton *buttonCancel;
#property (nonatomic, weak) IBOutlet UILabel *labelDescription;
On my viewDidLoad :
- (void)viewDidLoad
{
[super viewDidLoad];
// Support View
self.supportViewPopupAction.layer.cornerRadius = 5.0f;
self.supportViewPopupAction.layer.masksToBounds = YES;
// Add Support View
[self.view addSubview:self.supportViewPopup];
// Center Support view
self.supportViewPopup.center = self.view.center;
// Alpha
self.supportViewPopup.alpha = 0.0f;
self.supportViewPopupBackground.alpha = 0.0f;
self.supportViewPopupAction.alpha = 0.0f;
}
Action to display Popup :
- (IBAction)displayPopup
{
// Support View
self.supportViewPopup.alpha = 1.0f;
self.supportViewPopupBackground.alpha = 0.5f;
// Animation
[UIView animateWithDuration:0.5f
animations:^{
self.supportViewPopupAction.alpha = 1.0f;
}];
}
Action to dismiss Popup :
- (IBAction)dismissModal
{
// Animation
[UIView animateWithDuration:0.5f
animations:^{
self.supportViewPopup.alpha = 0.0f;
self.supportViewPopupBackground.alpha = 0.0f;
self.supportViewPopupAction.alpha = 0.0f;
}];
}
So, with that you can configure your supportViewPopupAction like you want with buttons, table view, labels, collection view, etc...
I spent time to write this example of alert view. I hope this will help you !
Custom views can be passed to PXAlertView: https://github.com/alexanderjarvis/PXAlertView
Some components as UIButtons and UITextFields are going to look different depending on the version, so that's going to be fine, the problem I see is going to be in the view that contains then.
My suggestion is to detect the version where the app is running and then draw the alert view based on that, or just create a custom design that will fit both.
Creat view depending on the iOS versions!
NSString *version = [[UIDevice currentDevice] systemVersion];
int major = [version intValue];
if (major < 7)
//alert for the iOS 6
else
//alert for the iOS 7

A few IBOutlets pointing to nil

After a long while I've finally started working with Objective-C again, on my only complete app so far. The goal is to eventually refactor for ARC and possibly storyboards, but for the time being I'm polishing the iOS 4.x target. I am quite rusty, so bar with me if this is a stupid question.
I have a button in my main view that triggers the showAction method. The method is as follows:
- (void)showAbout
{
AboutViewController *aboutView = [[[AboutViewController alloc] init] autorelease];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
aboutView.modalPresentationStyle = UIModalPresentationFormSheet;
}
else
{
aboutView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
}
[self presentModalViewController:aboutView animated:YES];
}
The AboutViewController class has this .h:
#interface AboutViewController : UIViewController <UIActionSheetDelegate, MFMailComposeViewControllerDelegate> {
}
- (IBAction)dismiss:(UIButton *)sender;
- (IBAction)feedback:(UIButton *)sender;
#property (retain) IBOutlet UIButton *dismissButton;
#property (retain) IBOutlet UIButton *feedbackButton;
#property (retain) IBOutlet UIImageView *background;
#property (retain) IBOutlet UITextView *textView;
#end
and everything has been connected properly in the .xib file (the same one for iPhone and iPad). The actions are triggered as expected, and the outlets are accessible, but only on iPhone. When running on iPad, only textView is properly initialized, and all the rest points to nil.
In the .m I have tried this:
#implementation AboutViewController
#synthesize dismissButton = _dismissButton;
#synthesize feedbackButton = _feedbackButton;
#synthesize background = _background;
#synthesize textView = _textView;
// ...
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"obj self.dismiss: %#", self.dismissButton);
NSLog(#"frame dismiss: %#", NSStringFromCGRect(self.dismissButton.frame));
}
On iPhone I get this:
2012-02-08 22:51:00.341 myapp[17290:207] obj self.dismiss: <UIButton: 0x70281d0; frame = (180 410; 120 30); opaque = NO; autoresize = LM+W+RM+TM; layer = <CALayer: 0x7028260>>
2012-02-08 22:51:00.342 myapp[17290:207] frame dismiss: {{180, 410}, {120, 30}}
On iPad, instead, I get this:
2012-02-08 22:51:40.428 myapp[17320:207] obj self.dismiss: (null)
2012-02-08 22:51:40.428 myapp[17320:207] frame dismiss: {{0, 0}, {0, 0}}
There is nothing else that happens depending on the UI Idiom, and I'm really confused about this. It's as if on the iPad the outlets for anything other than textView are not set, even though they are correctly linked up in the .xib file. In viewWillAppear, self.textView is working as expected also on iPad. I also tried doing this in viewDidLoad, which should be called before viewWillAppear if I'm not mistaken, and even in the dismiss: method, but they are just never available.
The reason I need to access the buttons' frames is that the about view is relatively complex and fails to reposition its subviews automatically. The only thing I need to do is make the buttons wider on the larger modal view on iPad.
Any hints would be greatly appreciated!
Thanks in advance.
Did you ever have a separate .xibs for iPad and iPhone? If so you might have the same issue I had. That is until #AliSoftware dropped some knowledge on me:
UIView in nib is nil on iPad, and not nil on iPhone
Essentially you need to:
Delete the Build Products Directory
Delete your app from all your simulators
Build and Run
I believe the problem is that a ghost .xib for iPad was hanging around causing issues. Truly wiping the apps clean did the trick. Good luck!

Resources