The Code I Have written for loading view controllers in Page View Controllers.
Programatically creating four view controllers and adding them to Page View Controller.
I have changed the view controllers frame position but still not changing in the app
let controller: UIViewController = UIViewController()
print(controller.view.frame)
controller.view.frame = CGRectMake(10, 20, self.view.frame.width/2, self.view.frame.height - 20)
print(controller.view.frame)
controller.view.backgroundColor = UIColor.blackColor()
let controller2: UIViewController = UIViewController()
controller2.view.backgroundColor = UIColor.redColor()
let controller3: UIViewController = UIViewController()
controller3.view.backgroundColor = UIColor.blackColor()
let controller4: UIViewController = UIViewController()
controller4.view.backgroundColor = UIColor.greenColor()
let p1 = controller
let p2 = controller2
let p3 = controller3
let p4 = controller4
myViewControllers = [p1,p2,p3,p4]
for index in 0 ..< myViewControllers.count {
NSLog("\(myViewControllers[index])")
}
let startingViewController = self.viewControllerAtIndex(0)
let viewControllers: NSArray = [startingViewController]
self.setViewControllers(viewControllers as? [UIViewController], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: {(done: Bool) in
})
Related
I have two view controllers embedded into a UINavigationController. The first view controller has a UISearchController set to its navigation item. Here is the full code where I configure the search controller:
private func configureSearchController() {
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
//searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.tintColor = .white
searchController.searchBar.delegate = self
//White search text
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.white]
//White placeholder
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: "search bar placeholder"), attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])
//searchController.searchBar.sizeToFit()
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
navigationController?.navigationBar.prefersLargeTitles = false
//
definesPresentationContext = true
}
I call this method from viewDidLoad.
As mentioned in the question title, I use a navigation controller custom transition. Here is the transition animator's full code.
class RevealViewControllerAnimator: NSObject, UIViewControllerAnimatedTransitioning {
private let animationDuration = 1.5
var operation: UINavigationControllerOperation = .push
var isShowing = true
private weak var storedContext: UIViewControllerContextTransitioning?
var snapshot: UIView?
private lazy var viewOnTopOfSnapshot: UIView? = {
let view = UIView()
view.frame = self.snapshot!.frame
if isShowing {
view.backgroundColor = .clear
} else {
view.backgroundColor = UIColor(white: 0.3, alpha: 0.4)
}
return view
}()
private var backgroundViewBackgroundDarkColor = UIColor(white: 0.2, alpha: 0.4)
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return animationDuration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
storedContext = transitionContext
print ("OPERATION", operation.rawValue)
//If we are presenting a view controller
if isShowing {
let fromVC = transitionContext.viewController(forKey: .from) as! ViewController1
let toVC = transitionContext.viewController(forKey: .to) as! ViewController2
snapshot = UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: false)
let containerView = transitionContext.containerView
//Adding a view on top of a snapshot and animating its bacground color
if let snapshot = snapshot, let viewOnTopOfSnapshot = viewOnTopOfSnapshot {
containerView.addSubview(self.snapshot!)
containerView.insertSubview(viewOnTopOfSnapshot, aboveSubview: snapshot)
UIView.animate(withDuration: animationDuration - 1.0, animations: {
viewOnTopOfSnapshot.backgroundColor = self.backgroundViewBackgroundDarkColor
}, completion: nil)
}
containerView.addSubview(toVC.view)
toVC.view.frame = transitionContext.finalFrame(for: toVC)
animate(toView: toVC.view, fromTriggerButton: fromVC.filterButton)
} else {
//If we are dismissing the view controller
let fromVC = transitionContext.viewController(forKey: .from) as! ViewController2
let toVC = transitionContext.viewController(forKey: .to) as! ViewController1
let containerView = transitionContext.containerView
//Animating the background color change to clear
if let viewOnTopOfSnapshot = viewOnTopOfSnapshot {
UIView.animate(withDuration: animationDuration, animations: {
viewOnTopOfSnapshot.backgroundColor = .clear
}, completion: {_ in
self.snapshot?.removeFromSuperview()
viewOnTopOfSnapshot.removeFromSuperview()
})
}
//containerView.addSubview(fromVC.view)
containerView.insertSubview(toVC.view!, belowSubview: snapshot!)
animateDismisss(fromView: fromVC.view, toTriggerButton: fromVC.saveButton)
}
}
//MARK: Animation for pushing
private func animate(toView: UIView, fromTriggerButton button: UIButton) {
let rect = CGRect(x: toView.frame.maxX, y: toView.frame.minY, width: button.frame.width, height: button.frame.height)
let circleMaskPathInitial = UIBezierPath(ovalIn: rect)
let fullHeight = toView.bounds.height
let extremePoint = CGPoint(x: button.center.x, y: button.center.y - fullHeight)
let radius = sqrt((extremePoint.x * extremePoint.x) + (extremePoint.y * extremePoint.y))
let circleMaskPathFinal = UIBezierPath(ovalIn: button.frame.insetBy(dx: -radius - 1000, dy: -radius - 1000))
let maskLayer = CAShapeLayer()
maskLayer.path = circleMaskPathFinal.cgPath
toView.layer.mask = maskLayer
let maskLayerAnimation = CABasicAnimation(keyPath: "path")
maskLayerAnimation.fromValue = circleMaskPathInitial.cgPath
maskLayerAnimation.toValue = circleMaskPathFinal.cgPath
maskLayerAnimation.duration = animationDuration
maskLayerAnimation.delegate = self
maskLayer.add(maskLayerAnimation, forKey: "path")
}
//MARK: Animation for pop (dismiss)
private func animateDismisss(fromView: UIView, toTriggerButton button: UIButton) {
let rect = CGRect(x: button.frame.origin.x, y: button.frame.midY, width: button.frame.width, height: button.frame.width)
let finalCircleMaskPath = UIBezierPath(ovalIn: rect)
let fullHeight = fromView.bounds.height
let extremePoint = CGPoint(x: button.center.x, y: button.center.y - fullHeight)
let radius = sqrt((extremePoint.x * extremePoint.x) + (extremePoint.y * extremePoint.y))
let initialCircleMaskPath = UIBezierPath(ovalIn: button.frame.insetBy(dx: -radius, dy: -radius))
let maskLayer = CAShapeLayer()
maskLayer.path = finalCircleMaskPath.cgPath
fromView.layer.mask = maskLayer
let maskLayerAnimation = CABasicAnimation(keyPath: "path")
maskLayerAnimation.fromValue = initialCircleMaskPath.cgPath
maskLayerAnimation.toValue = finalCircleMaskPath.cgPath
maskLayerAnimation.duration = 0.8
maskLayerAnimation.delegate = self
maskLayer.add(maskLayerAnimation, forKey: "path")
}
extension RevealFilterViewControllerAnimator : CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if let context = storedContext {
storedContext?.completeTransition(!context.transitionWasCancelled)
} else {
storedContext = nil
}
}
}
So, in two words, I get a snapshot of the ViewController1, insert it to the containerView, and on top of it, insert another view which background color I change during the animation. When popping, I get rid of the snapshot and the view, and also insert the ViewController1's view to a containerView.
As I mentioned in the beginning of the question, I have a UISearchController with a search bar in the first view controller.
The problem is, after dismissing the ViewController2 the search controller gets removed from the hierarchy and I get a blank white space. Here is the demonstration for that:
When I print the UISearchController or the search bar on the console, I get the object information, however, as you can see, it disappears from the view hierarchy (In a view hierarchy debugger I can't find it).
Why is this happening, and how this could be solved?
Finally, I figured out what was causing the issue, and once I did, the solution was quite simple. So, the reason why that was happening was that in the ViewController2's viewDidLoad method I was hiding the navigation bar, but I never set it back when popping the view controller.
So, here is the code that I use for the navigation bar in the second view controller (my view controllers look a little bit different but the logic is the same):
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: false)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
}
Here is how the animation looking right now (I know, there are some rough edges here, but at least, the problem is solved).
I want to present a ViewController as popover in Swift 4, but it presents the Viewcontroller normally, this is the code:
class CustomTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let favViewController = TrialViewController()
let exhibtionViewController = TrialViewController()
let menuViewController = ttttViewController()
let notificationViewController = TrialViewController()
let profileViewController = ttttViewController()
favViewController.tabBarItem.title = "first"
exhibtionViewController.tabBarItem.title = "second"
menuViewController.tabBarItem.title = "third"
notificationViewController.tabBarItem.title = "forth"
profileViewController.tabBarItem.title = "fifth"
favViewController.tabBarItem.image = UIImage(named:"home25")
exhibtionViewController.tabBarItem.image = UIImage(named: "bag25")
menuViewController.tabBarItem.image = UIImage(named: "main_add_25")
notificationViewController.tabBarItem.image = UIImage(named: "notification25")
profileViewController.tabBarItem.image = UIImage(named: "man_man25")
let tabBarItemWidth = Int(self.tabBar.frame.size.width) / (self.tabBar.items?.count)!
let x = tabBarItemWidth * 3;
let newRect = CGRect(x: x, y: 0, width: tabBarItemWidth, height: Int(self.tabBar.frame.size.height))
print(newRect)
menuViewController.modalPresentationStyle = .popover
menuViewController.view.frame = newRect
menuViewController.preferredContentSize = CGSize(width: 150,height: 150)
if let popoverMenuViewController = menuViewController.popoverPresentationController {
popoverMenuViewController.permittedArrowDirections = .down
popoverMenuViewController.delegate = menuViewController as? UIPopoverPresentationControllerDelegate
popoverMenuViewController.sourceRect = newRect
popoverMenuViewController.sourceView = self.tabBar
present(menuViewController, animated: true, completion: nil)
}
viewControllers = [favViewController, exhibtionViewController, menuViewController, notificationViewController, profileViewController]
}
}
what is the problem with my code?
override func viewDidAppear(_ animated: Bool) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "bbb") as! ttttViewController
vc.modalPresentationStyle = .popover //presentation style
vc.preferredContentSize = CGSize(width: 150,height: 150)
vc.popoverPresentationController?.delegate = self as! UIPopoverPresentationControllerDelegate
vc.popoverPresentationController?.sourceView = view
vc.popoverPresentationController?.sourceRect = self.tabBar.frame
self.present(vc, animated: true, completion: nil)
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
demo is here popover
I'm trying to make a view container with table view. That's works fine, but if i select the last row, the method didSelectRowAt indexPath: cannot be triggered. This is my code:
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let controller = storyboard.instantiateViewController(withIdentifier: "pageViewController") as! PageViewController
addChildViewController(controller)
controller.customDelegate = self
controller.index = index
self.controller = controller
//Add Controllers
let clientInfoVC = storyboard.instantiateViewController(withIdentifier: "ClientInfo") as! ClientInfoViewController
clientInfoVC.client = self.client
let clientRequestsVC = storyboard.instantiateViewController(withIdentifier: "ClientRequests") as! ClientProductRequestViewController
clientRequestsVC.client = self.client
let clientDebtsVC = storyboard.instantiateViewController(withIdentifier: "ClientDebts") as! ClientDebtViewController
clientDebtsVC.client = self.client
controller.orderedViewControllers = [clientInfoVC,clientRequestsVC,clientDebtsVC]
controller.view.frame = CGRect(x: 0, y: 0, width: self.clientContainerView.frame.width, height: self.clientContainerView.frame.height)
self.clientContainerView.addSubview(controller.view)
controller.didMove(toParentViewController: self)
And this is my container view:
What am I doing wrong?
Please help me
I found the solution:
I needed to remove the controller's frame setting and thats it. So Just remove this line:
controller.view.frame = CGRect(x: 0, y: 0, width: self.clientContainerView.frame.width,
height: self.clientContainerView.frame.height)
I'm trying to present a popover from a UIMenuItem which anchor point is the rect of a selected text in a textView. I have the following code:
func pickColor(sender: UIMenuItem) {
let range = noteTextView.selectedTextRange
let beginningOfSelection = noteTextView.caretRect(for: (range?.start)!)
let endOfSelection = noteTextView.caretRect(for: (range?.end)!)
let storyboard: UIStoryboard = UIStoryboard(name: "ColorPicker", bundle: nil)
let colorVC = storyboard.instantiateViewController(withIdentifier: "ColorPickerViewController") as UIViewController
colorVC.modalPresentationStyle = .popover
let popover: UIPopoverPresentationController = colorVC.popoverPresentationController!
popover.sourceView = noteTextView
popover.sourceRect = CGRect(x: (beginningOfSelection.origin.x + endOfSelection.origin.x)/2, y: (beginningOfSelection.origin.y + beginningOfSelection.size.height)/2, width: 0, height: 0)
present(colorVC, animated: true, completion: nil)
}
The app crashes in the line colorVC.modalPresentationStyle = .popover. Can someone tell me what's going on here? Thanks! :)
I want to show UITableViewController as popup on button press. I am able to show popup using this code
let menuViewController = popTableViewController() //popTableViewController
menuViewController.modalPresentationStyle = .Popover
menuViewController.preferredContentSize = CGSizeMake(320, 132)
//menuViewController.tableView = FrontTable
let popoverMenuViewController = menuViewController.popoverPresentationController
popoverMenuViewController?.permittedArrowDirections = .Any
popoverMenuViewController?.delegate = self
popoverMenuViewController?.sourceView = sender
popoverMenuViewController?.sourceRect = CGRect(
x: 10,
y: 10,
width: 1,
height: 1)
presentViewController(
menuViewController,
animated: true,
completion: nil)
but it is showing blank table view in popup. I have also added the content in tableview class but it not showing any reflection on result.
Try adding below code in your UIViewController
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
or you can try below code to create popover
let mpopover = self.storyboard?.instantiateViewControllerWithIdentifier("breedPop") as! breedPopover
mpopover.delegate = self
self.citiesPopover = mpopover
citiesPopover!.modalPresentationStyle = .Popover
citiesPopover!.preferredContentSize = CGSizeMake(UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height/2)
let popoverPresentationViewController = citiesPopover!.popoverPresentationController
popoverPresentationViewController?.permittedArrowDirections = UIPopoverArrowDirection.Any
popoverPresentationViewController?.delegate = self
popoverPresentationViewController?.sourceView = breedTextField
popoverPresentationViewController?.sourceRect = CGRectMake(breedTextField.frame.width, breedTextField.frame.height*3, 0, 0)
presentViewController(citiesPopover!, animated: true, completion: nil)