LTR to RTL in iOS Application [without closing Application] - right-to-left

When changing language within the application I need to change the application layout as per selected language.
For example, the base language is English; when the user changes it to Arabic I need to change UI as per RTL.
Is there any specific setting in storyboard or in ViewController for achieving LTR and RTL?

To Manage RTL and LTR without closing application Swift 3.0.
//RTL
UIView.appearance().semanticContentAttribute = .forceRightToLeft
UINavigationBar.appearance().semanticContentAttribute = .forceRightToLeft
//applicationNavigationController is Application Default Navigation Controller
if let applicationNavigationController = storyboard?.instantiateViewController(withIdentifier: "root") {
UIApplication.shared.keyWindow?.rootViewController = applicationNavigationController
LTR//
UIView.appearance().semanticContentAttribute = .forceLeftToRight
UINavigationBar.appearance().semanticContentAttribute = .forceLeftToRight
if let applicationNavigationController = storyboard?.instantiateViewController(withIdentifier: "root") {
UIApplication.shared.keyWindow?.rootViewController = applicationNavigationController
// Additional Tips while a deal with MMDrawer.
AppDelegate
var centerContainer:MMDrawerController?
Implement MMDrawer Code inside one ViewController.
let appdelegate=UIApplication.shared.delegate as! AppDelegate
let mainStoryboard:UIStoryboard=UIStoryboard(name: "Main", bundle: nil)
let centerViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let leftViewController = mainStoryboard.instantiateViewController(withIdentifier: "LeftSideMenuViewController") as! LeftSideMenuViewController
let leftSideNav = UINavigationController(rootViewController: leftViewController)
let centerNav = UINavigationController(rootViewController: centerViewController)
appdelegate.centerContainer = MMDrawerController(center: centerNav, leftDrawerViewController: leftSideNav)
appdelegate.centerContainer?.maximumLeftDrawerWidth = 250.0
appdelegate.centerContainer!.openDrawerGestureModeMask = MMOpenDrawerGestureMode.panningCenterView
appdelegate.centerContainer!.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.all
//////////
self.navigationController?.pushViewController(appdelegate.centerContainer!, animated: false)

Related

Replace NSWindow contentViewController with new ViewController with same Window Size

I need, on button click, to replace a NSWindow.contentViewController with new ViewController. To do this I wrote following code:
let g = GameViewController()
if self.window!.styleMask & NSFullScreenWindowMask != NSFullScreenWindowMask {
let ws = NSScreen.mainScreen()?.frame.size
let width : CGFloat = g.view.frame.width
let height : CGFloat = g.view.frame.height
let frame = NSRect(origin: NSMakePoint(((ws?.width)!-width)/2, ((ws?.height)!-height)/2), size: CGSize(width:width, height:height))
self.window?.setFrame(frame, display: true, animate: true)
}
self.window?.contentViewController = g
When NSWindow is not in FullScreen mode, this code works good. While, when NSWindow is in FullScreen mode, the GameViewController is set with his default size and not change is size until occurs a resize event.
How can I instantiate NSViewController in order to occupy all window space?
If you are using storyboard:
let storyboard = NSStoryboard(name: "Main", bundle: nil)
if let homeViewController = (storyboard.instantiateControllerWithIdentifier("HomeViewController") as? NSViewController){
let windowController = NSWindowController(window: Constants.appDelegate!.window)
windowController.contentViewController = homeViewController
windowController.showWindow(Constants.appDelegate!.window)
}
Hope this will help you. Happy Codding

Configure window in App Delegate with TabBar and NavBar

I'm not totally sure how to phrase this, but for some reason I'd assume its fairly simple. The below is code that works for a NavigationBar and a ViewController to set up the managed context/core data in my App Delegate (under didFinishLaunchingWithOptions). How do I make the same thing work but with a TabBar as well (assuming I still want to get to the UIViewController)?
let navController = window!.rootViewController as! UINavigationController
let viewController = navController.topViewController as! ViewController
viewController.coreDataStack = coreDataStack
The below was my attempt at doing this, but it errors out with the "tabController.selectedIndex = 2" command.
let tabController = window!.rootViewController as! UITabBarController
let navController = (tabController.selectedIndex = 2) as! UINavigationController
let viewController = navController.topViewController as! FamilyViewController
viewController.coreDataStack = coreDataStack
Any ideas? Thanks in advance for any help!
I think let navController = (tabController.selectedIndex = 2) as! UINavigationController is not correct.
tabController.selectedIndex = 2 instead of that you should use [tabController.viewControllers objectAtIndex:2]
Sorry for not using swift syntax but I think you can get the idea from that.

Swift how to do appearance of uiview slide left to right

I designed some UIView that interactive each other. But when a view appear always slide from right to left (default).
But i want it appears left to right some case (e.g i swipe right).
How i cant do it from Swift code?
Updated
I found a solution for this problem
let slideInFromLeftTransition = CATransition()
// Customize the animation's properties
slideInFromLeftTransition.type = kCATransitionPush
slideInFromLeftTransition.subtype = kCATransitionFromLeft
slideInFromLeftTransition.duration = 0.5
slideInFromLeftTransition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
slideInFromLeftTransition.fillMode = kCAFillModeRemoved
// Add the animation to the View's layer
self.navigationController?.view.layer.addAnimation(slideInFromLeftTransition, forKey: "slideInFromLeftTransition")
This solved.
The solution in swift 4.2:
func transitionVc(vc: UIViewController, type: CATransitionSubtype) {
let transition = CATransition()
transition.duration = 0.3
transition.type = CATransitionType(rawValue: "push")
transition.subtype = type
self.navigationController?.view.layer.add(transition, forKey: kCATransition)
self.navigationController?.pushViewController(vc, animated: false)
}
Use these in the following way:
let viewController = YourViewController()
transitionVc(vc: viewController!, type: .fromLeft)
transitionVc(vc: viewController, type: .fromRight)

Resizing NSWindow to match view controller size in storyboard

I am working on Xcode 6.1.1 on OSX 10.10. I am trying out storyboards for Mac apps. I have a NSTabViewController using the new NSTabViewControllerTabStyleToolbar tabStyle and it is set as the default view controller for the window controller. How do I make my window resize according to the current selected view controller?
Is it possible to do entirely in Interface Builder?
Here is what my storyboard looks like:
The auto layout answer is half of it. You need to set the preferredContentSize in your ViewController for each tab to the fitting size (if you wanted the tab to size to the smallest size satisfying all constraints).
override func viewWillAppear() {
super.viewWillAppear()
preferredContentSize = view.fittingSize
}
If your constraints are causing an issue below try first with a fixed size, the example below sets this in the tab item's view controller's viewWillAppear function (Swift used here, but the Objective-C version works just as well).
override func viewWillAppear() {
super.viewWillAppear()
preferredContentSize = NSSize(width: 400, height: 280)
}
If that works, fiddle with your constraints to figure out what's going on
This solution for 'toolbar style' tab view controllers does animate and supports the nice crossfade effect. In the storyboard designer, add 'TabViewController' in the custom class name field of the NSTabViewController. Don't forget to assign a title to each viewController, this is used as a key value.
import Cocoa
class TabViewController: NSTabViewController {
private lazy var tabViewSizes: [String : NSSize] = [:]
override func viewDidLoad() {
// Add size of first tab to tabViewSizes
if let viewController = self.tabViewItems.first?.viewController, let title = viewController.title {
tabViewSizes[title] = viewController.view.frame.size
}
super.viewDidLoad()
}
override func transition(from fromViewController: NSViewController, to toViewController: NSViewController, options: NSViewController.TransitionOptions, completionHandler completion: (() -> Void)?) {
NSAnimationContext.runAnimationGroup({ context in
context.duration = 0.5
self.updateWindowFrameAnimated(viewController: toViewController)
super.transition(from: fromViewController, to: toViewController, options: [.crossfade, .allowUserInteraction], completionHandler: completion)
}, completionHandler: nil)
}
func updateWindowFrameAnimated(viewController: NSViewController) {
guard let title = viewController.title, let window = view.window else {
return
}
let contentSize: NSSize
if tabViewSizes.keys.contains(title) {
contentSize = tabViewSizes[title]!
}
else {
contentSize = viewController.view.frame.size
tabViewSizes[title] = contentSize
}
let newWindowSize = window.frameRect(forContentRect: NSRect(origin: NSPoint.zero, size: contentSize)).size
var frame = window.frame
frame.origin.y += frame.height
frame.origin.y -= newWindowSize.height
frame.size = newWindowSize
window.animator().setFrame(frame, display: false)
}
}
The window containing a toolbar style tab view controller does resize without any code if you have auto layout constraints in your storyboard tab views (macOS 11.1, Xcode 12.3). I haven't tried other style tab view controllers.
If you want to resize with animation as in Finder, it is sufficient to add one override in your tab view controller. It will resize the window with system-calculated resize animation time and will hide the tab view during resize animation:
class PreferencesTabViewController: NSTabViewController {
override func transition(from fromViewController: NSViewController, to toViewController: NSViewController, options: NSViewController.TransitionOptions = [], completionHandler completion: (() -> Void)? = nil) {
guard let window = view.window else {
super.transition(from: fromViewController, to: toViewController, options: options, completionHandler: completion)
return
}
let fromSize = window.frame.size
let toSize = window.frameRect(forContentRect: toViewController.view.frame).size
let widthDelta = toSize.width - fromSize.width
let heightDelta = toSize.height - fromSize.height
var toOrigin = window.frame.origin
toOrigin.x += widthDelta / 2
toOrigin.y -= heightDelta
let toFrame = NSRect(origin: toOrigin, size: toSize)
NSAnimationContext.runAnimationGroup { context in
context.duration = window.animationResizeTime(toFrame)
view.isHidden = true
window.animator().setFrame(toFrame, display: false)
super.transition(from: fromViewController, to: toViewController, options: options, completionHandler: completion)
} completionHandler: { [weak self] in
self?.view.isHidden = false
}
}
}
Please adjust closure syntax if you are using Swift versions older than 5.3.
Use autolayout. Set explicit size constraints on you views. Or once you have entered the UI into each tab view item's view set up the internal constraints such that they force view to be the size you want.

How to present a modal atop the current view in Swift

(Xcode6, iOS8, Swift, iPad)
I am trying to create a classic Web-like modal view, where the outside of the dialog box is "grayed-out." To accomplish this, I've set the alpha value of the backgroundColor of the view for the modal to 0.5, like so:
self.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
The only problem is that when the modal becomes full-screen, the presenting view is removed. (Ref Transparent Modal View on Navigation Controller).
(A bit irritated at the concept here. Why remove the underlying view? A modal is, by definition, to appear atop other content. Once the underlying view is removed, it's not really a modal anymore. it's somewhere between a modal and a push transition. Wa wa wa... Anyway..)
To prevent this from happening, I've set the modalPresentationStyle to CurrentContext in the viewDidLoad method of the parent controller, and in Storyboard... but no luck.
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
How do I prevent the presenting view from being removed when the modal becomes full screen?
tyvm.. more info below.
Also in Storyboard, like so (Presentation: Current Context)
Thx for your help... documentation below:
First, remove all explicit setting of modal presentation style in code and do the following:
In the storyboard set the ModalViewController's modalPresentation style to Over Current context
Check the checkboxes in the Root/Presenting ViewController - Provide Context and Define Context.
They seem to be working even unchecked.
You can try this code for Swift:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
let navigationController = UINavigationController(rootViewController: popup)
navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(navigationController, animated: true, completion: nil)
For swift 4 latest syntax using extension:
extension UIViewController {
func presentOnRoot(`with` viewController : UIViewController){
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(navigationController, animated: false, completion: nil)
}
}
How to use:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
self.presentOnRoot(with: popup)
The only problem I can see in your code is that you are using CurrentContext instead of OverCurrentContext.
So, replace this:
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
for this:
self.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
This worked for me in Swift 5.0. Set the Storyboard Id in the identity inspector as "destinationVC".
#IBAction func buttonTapped(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let destVC = storyboard.instantiateViewController(withIdentifier: "destinationVC") as! MyViewController
destVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
destVC.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(destVC, animated: true, completion: nil)
}
The problem with setting the modalPresentationStyle from code was that you should have set it in the init() method of the presented view controller, not the parent view controller.
From UIKit docs: "Defines the transition style that will be used for this view controller when it is presented modally. Set
this property on the view controller to be presented, not the presenter. Defaults to
UIModalTransitionStyleCoverVertical."
The viewDidLoad method will only be called after you already presented the view controller.
The second problem was that you should use UIModalPresentationStyle.overCurrentContext.
The only way I able to get this to work was by doing this on the presenting view controller:
func didTapButton() {
self.definesPresentationContext = true
self.modalTransitionStyle = .crossDissolve
let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
let navController = UINavigationController(rootViewController: yourVC)
navController.modalPresentationStyle = .overCurrentContext
navController.modalTransitionStyle = .crossDissolve
self.present(navController, animated: true, completion: nil)
}
I am updating a simple solution. First add an id to your segue which presents modal. Than in properties change it's presentation style to "Over Current Context". Than add this code in presenting view controller (The controller which is presenting modal).
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue
let iOS8 = iosVersion >= 8
let iOS7 = iosVersion >= 7 && iosVersion < 8
if((segue.identifier == "chatTable")){
if (iOS8){
}
else {
self.navigationController?.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
}
}
}
Make sure you change segue.identifier to your own id ;)

Resources