Different UI for iPad and iPhone - ios

In my app I have browser and UI for iPad and iPhone should be different.
I don't use storyboards and write all programmatically.
Also, when user taps on "downloadsButton", there will be different behavior.
On iPhone a new controller with full screen size will appear from bottom, but on iPad a little square view will appear in the center of screen.
How can I do this properly ?
iPhone
iPad

Let's say you touch downloadButton to invoke downloadAction, then you may try to change the modalPresentationStyle (of the view controller you want to show) doing so:
func downloadAction() {
let downloadVc = DownloadViewController()
downloadVc.modalPresentationStyle = UIDevice.current.userInterfaceIdiom == .pad ? .formSheet : .fullScreen
self.present(downloadVc, animated: true, completion: nil)
}

Related

How can I get the video from RPScreenRecorder or add a share button?

I'm recording video using RPScreenRecorder.shared().startRecording. However, I want to let the user share the video from within the app. This is the code that stops recording and previews the video in a view controller and gives the user the option to save to photos or cancel.
I cannot figure out how to grab the video from the view controllers view. When I dug into the subviews: preview.view.subviews.first!.subviews.first! There's a view of type: UIRemoteView with no subviews.
Is it possible to grab the video? Or better yet, is there a way to show a UIActivityViewController to allow the user to share the video?
for macOS I could do preview.mode = .share, but for iOS this is not available.
RPScreenRecorder.shared().stopRecording { preview, error in
guard let preview = preview else { return }
self.present(preview, animated: true, completion: nil)
}
There is a share button but it is not visible, if view controller is not presented fullscreen, I think this is a bug related to PRPreviewViewController.
You can change modalTransitionStyle and see share button.
RPScreenRecorder.shared().stopRecording { preview, error in
guard let preview = preview else { return }
preview.modalPresentationStyle = .overFullScreen
self.present(preview, animated: true, completion: nil)
}

youtube iFrame in iOS application causes half screen to go black after full screen

I have a WKWebView in my UIViewController and I'm embedding a youtube video (using an iFrame) into the html along with text. When I launch the video it performs as intended, it opens in full screen, I can rotate either landscape orientations, plays fine etc. The problem lies when I close the video. My application is locked to portrait and when returning from the video the application is half black screen, half my application and the view that is still half my application looks to be in landscape (too larger for the width).
My application is locked portrait within the Info.plist for the whole application. I am fine with the video rotating it just causes this interesting outcome.
1. Launch WKWebView with youtube iframe
2. Click to launch video (video plays full screen)
3. Rotate device to either landscape rotations.
4. Close the player
This is where you notice that half the application is black and the other half looks to be portrait orientation in landscape layout.
When I inspect the views before and after it mimics as if the app has rotated to landscape mode but the device is in portrait. (View starts at 414x862. After viewing and rotating with the video and returning to the view it shows as 862x414)
I'm not really sure what's going on here. Thoughts?
Thanks in advance
I was able to find a workaround/hack/solution to this. I kept my application locked to portrait but overrode the AppDelegate method for allowed orientations.
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return OrientationManager.allowedOrientations
}
...
}
I created an OrientationManager which was just a helper class to allow me to force rotations and alter the allowed orientations.
class OrientationManager {
/// The currently allowed orientations of the application (default: .portrait)
static var allowedOrientations: UIInterfaceOrientationMask = .portrait
/**
* Method to force the current orientation of the device.
*
* - Parameter orientation: The orientation to change to.
*
* - Warning: This method uses setValue(_, forKey:) which accesses values that may change in the future
*/
static func forceOrientation(_ orientation: UIInterfaceOrientation) {
let orientationRawValue = orientation.rawValue
UIDevice.current.setValue(orientationRawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}
}
The last thing I needed to do was figure out when the video was going in and out of full screen. I found some notifications that seemed to reliably fire when the video goes in and out of full screen. When this happens I enable the ability for the view to rotate, which allows it to go to Landscape behind the full screen video. Once the video is closed my view is now (unfortunately) showing in landscape which I can then force the orientation and re-lock it to portrait.
In the UIViewController with the webview:
class WebViewWithVideoViewController: UIViewController {
...
// MARK: Properties
var videoDidFullScreenNotification: NSObjectProtocol?
var videoDidMinimizeNotification: NSObjectProtocol?
...
// MARK: Lifecycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.beginObserving()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.endObserving()
}
// MARK: Observers
func beginObserving() {
// This is a solution to the video causing a half black screen when the device is rotated to landscape.
// The outline of the solution is that when the video is put into full screen mode, we update the
// available orientations to include both landscape directions. Upon the video being closed,
// we force the device orientation back to portrait and then lock it back to portrait only.
// This seems to work because the UIViewController is actually in landscape once complete
// and then it animates back to the portrait orientation and seems to keep the proper ratios
// and sizes.
if self.videoDidFullScreenNotification == nil {
self.videoDidFullScreenNotification = NotificationCenter.default.addObserver(
forName: UIWindow.didBecomeVisibleNotification,
object: self.view.window,
queue: nil
) { notification in
OrientationManager.allowedOrientations = .allButUpsideDown
}
}
if self.videoDidMinimizeNotification == nil {
self.videoDidMinimizeNotification = NotificationCenter.default.addObserver(
forName: UIWindow.didBecomeHiddenNotification,
object: self.view.window,
queue: nil
) { notification in
OrientationManager.forceOrientation(.portrait)
OrientationManager.allowedOrientations = .portrait
}
}
}
func endObserving() {
if let videoDidFullScreenNotification = self.videoDidFullScreenNotification {
NotificationCenter.default.removeObserver(videoDidFullScreenNotification)
}
if let videoDidMinimizeNotification = self.videoDidMinimizeNotification {
NotificationCenter.default.removeObserver(videoDidMinimizeNotification)
}
}
...
}
This seemed to have solved the screen showing half black after going in and out of full screen with embedded videos. Unfortunately there is a slight animation when you return from the full screen video, but it's a small sacrifice for a very weird bug.
Hope this helps anyone else with this (or similar issues) and happy coding!

UITabBarController opens and turns into black Screen in iOS13

I have a application flow
first presentviewController -> pushViewController -> PushViewController -> click button action Showing TabBarContorller which in .present(manner)
DispatchQueue.main.async {
let tabBarController = TabBarController.instantiate()
tabBarController.modalPresentationStyle = .overFullScreen
self.present(tabBarController, animated: true)
}
Application works fine in iOS 11. When running on iOS 13 its show black Screen
Well I guess if you present of push and then present I guess this make no difference with the application.
Your Inputs are highlight appreciated
Thanks in advance.

ReplayKit RPBroadcastActivityViewController iPad

How do I present the RPBroadcastActivityViewController on iPads.
I am using the standard code to start a recording
RPBroadcastActivityViewController.load { [unowned self] (broadcastActivityViewController, error) in
// If an error has occurred, display an alert to the user.
if let error = error {
self.showAlert(message: error.localizedDescription)
return
}
// Present vc
if let broadcastActivityViewController = broadcastActivityViewController {
broadcastActivityViewController.delegate = self
// present
self.present(...
}
}
Works on iPhones but on iPads nothing is presented and the app kind of freezes. I have been checking out games on the app store that use this feature and I noticed the same problem.
E.g on the game Tower Dash nothing is presented when pressing the live stream button on iPads, it only works on iPhones.
I have been trying to play around with popover presentations but nothing seems to work.
Am I missing something?
UPDATE: This seems to be a bug. Even in apples own Swift Playground app this happens.
UPDATE2: Apple has actually responded to my bug report and told me that I need to present the View Controller on iPads as a popover like so
UIDevice.current.userInterfaceIdiom == .pad {
broadcastAVC.popoverPresentationController?.sourceView = view
broadcastAVC.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
broadcastAVC.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) // no arrow
}
However it still doesnt work for me. As I mentioned this happens on apples own Swift Playground app so it must be a bug.
Fixed:
I forgot to add this line in the code mentioned above
broadcastAVC.modalPresentationStyle = .popover
You are correct that Apple's demo app does not include this little detail, but it isn't a bug. This is what I use to get it to work on an iPad. iPads require a popover to present the view and a popover needs an anchor. I chose to anchor it to the leftBarButtonItem.
if let unwrappedPreview = preview {
unwrappedPreview.previewControllerDelegate = self
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone {
self.present(unwrappedPreview, animated: true, completion: nil)
}
else {
unwrappedPreview.popoverPresentationController?.barButtonItem = self.navigationItem.leftBarButtonItem!
unwrappedPreview.modalPresentationStyle = UIModalPresentationStyle.popover
unwrappedPreview.preferredContentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
self.present(unwrappedPreview, animated: true, completion: nil)
}
}
iOS 10.1 beta 2 still have the same problem.
For now, I found the only way to present a RPBroadcastActivityViewController on iPad is to present it on a trait collection's horizontal compact environment.
So you may need to tell your user switch to Split View mode before select a broadcast-supported app, then switch back to full screen. After back to full screen, you can use RPBroadcastController.startBroadcast(handler:) to start broadcast.

iDevice app orientation before and after interstitial ads

Hi I have an app (SpriteKit) that I have set it to only portrait under Target > General > Deployment Info. Also in my info.plist, I have supported interface orientations set to Portrait (bottom home button) and supported interface orientations (iPad) set to Portrait (bottom home button) and Portrait (top home button). This works for most part, however when an interstitial ad is shown, and the device is rotated to landscape mode, the ad rotates too. When the ad is closed, the app stays in landscape mode, and it is not displayed right (i.e. zoomed in so that the width of the app fits the width of the screen and top and bottom is cut off).
I played with the settings a little and found that setting this code makes it work fine, for now at least. I was just wondering if this is the right way to do it? Will there be an issue during the official app review? What are your suggestions? Any comments?
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .Portrait // used to be return .AllButUpsideDown, changed this and everything works for now
} else {
return .Portrait // used to be return .All
}
}

Resources