After button click label goes up in left upper corner - swift

I have set auto-layout for the label so it should be centered right above my button, however when I click on the button the label goes up in the left corner. I'm a totally new beginner to coding, so bare in mind I might have just missed something very simple? I would guess in my code I need some kind of way to tell the position of the label to be after the click?
This is my code for the button action:
nextStagetwo.textAlignment = NSTextAlignment.Center
nextStagetwo.userInteractionEnabled = true
nextStagetwo.text = "Go to next stage"
self.view.addSubview(nextStagetwo)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTap:")
nextStagetwo.addGestureRecognizer(gestureRecognizer)
}
}
func handleTap(gestureRecognizer: UIGestureRecognizer) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: AnyObject! = storyboard.instantiateViewControllerWithIdentifier("stagethree")
self.presentViewController(vc as! UIViewController, animated: true, completion: nil)
}

Run your application in Xcode 7 and select the debugger view and then the debugger toolbar button with tooltip, "Debug View Hierarchy" (third button from right in the debugger toolbar). That will show you what auto layout is computing for each item on the screen. You can peel off layers as needed in this view. Compare those values with your auto layout constraints for that item and its containers.
Also, make sure you don't have any auto layout warnings in the Xcode Interface Builder for your storyboard.

I added this to the code, which was what was missing in my code:
let nextStagetwo = UILabel(frame: CGRectMake(250, 250, 250, 250))
nextStagetwo.center = CGPointMake(210, 200)

Related

iOS 14 UISplitViewController (sidebar) with triple column sidebar toggle icon behavior

I'm implementing the iOS 14 (iPadOS 14) sidebar (UISplitViewController with TripleColumn) and having strange "sidebar toggle icon" behavior.
In iOS 13 I'm using the tab bar with some split views and table views so I need the Triple Column instead of the Double Column to work.
For example, using the sidebar in "flights" tab needs three columns:
And there are some tabs with only one column (in iOS 13, it was a table view instead of a split view). I set the supplementary view to nil, and hide the view by calling "hide" method implemented in iOS 14. (See below for code):
The "sidebar toggle icon" on the upper left is automatically displayed. After clicking the toggle icon, the sidebar hides correctly but an "back button" was created on my secondary view(a UITableViewController embedded in a UINavigationController):
Pressing (clicking) the back button has no response. User can still swipe from the left edge of the screen to make sidebar reappear but the "back button" is confusing. My expected behavior is, after the toggle icon selected in sidebar, display the "sidebar toggle icon" instead of the "back button" in the secondary view. And after pressing the "sidebar toggle icon" in secondary view, the sidebar reappears.
Like the Photos app in iOS 14 (iPadOS 14), the toggle button is shown instead of the back button. And clicking the toggle icon will make the sidebar shown again. (but it's a double column split view)
My code:
SceneDelegate.swift:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
if #available(iOS 14.0, *) {
let main = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = UISplitViewController(style: .tripleColumn)
splitViewController.preferredDisplayMode = .twoBesideSecondary
splitViewController.preferredSplitBehavior = .tile
splitViewController.setViewController(SideBarViewController(), for: .primary)
// fall back for compact screen
splitViewController.setViewController(main.instantiateInitialViewController(), for: .compact)
window.rootViewController = splitViewController
self.window = window
window.makeKeyAndVisible()
}
}
}
SideBarViewController:
// if the first tab (dashboard) was selected
private func selectDashboardTab() {
if #available(iOS 14.0, *) {
let dashboardVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DashboardTab") as? UINavigationController
splitViewController?.preferredPrimaryColumnWidth = 250.0
splitViewController?.preferredDisplayMode = .twoBesideSecondary
splitViewController?.preferredSplitBehavior = .tile
splitViewController?.setViewController(dashboardVC, for: .secondary)
splitViewController?.setViewController(nil, for: .supplementary)
splitViewController?.hide(.supplementary)
}
}
I was able to reproduce the problem... but was unable to circumvent it using the available API. Apple stubbornly decided that the sidebar icon would always be in the supplementary controller when in a 3-column layout, it seems.
That being said, I've coded a hack to fix it. I managed to create a UISplitViewController subclass that "fakes" an editable style property, thus allowing us to set the number of columns (the hack just creates a brand new controller and makes it the new rootViewController).
The hack allows us to switch between 2-colulm and 3-column layout at will, and seems to solve the sidebar icon problem.
Link to the Xcode project below. But here's the gist of it:
class AdaptableSplitViewController: UISplitViewController {
override var style: Style {
get {
super.style
}
set {
guard newValue != style else { return }
let primaryController = viewController(for: .primary)
let supplementaryController = viewController(for: .supplementary)
let secondaryController = viewController(for: .secondary)
let newSplitController = AdaptableSplitViewController(style: newValue)
newSplitController.setViewController(primaryController , for: .primary)
newSplitController.setViewController(secondaryController, for: .secondary)
if newValue == .tripleColumn {
newSplitController.setViewController(supplementaryController, for: .supplementary)
}
UIApplication.shared.windows[0].rootViewController = newSplitController
}
}
}
Let me know if this helps.
Link to the zipped Xcode sample project
Late in the discussion but... I've encountered a similar behavior.
Just before setting you secondary, set it to nil. Strange, I know, but it fixed it for me. Like this:
splitViewController?.setViewController(nil , for: .secondary)
splitViewController?.setViewController(dashboardVC, for: .secondary)

How can I hide/show my toolbar item when a button is selected/deselected?

I made a navigation bar with three buttons - Plans,Visit and Documents and every time a button is selected/clicked a view is added as a child into a container view (Code for the other buttons are similar)
#IBAction func planAction(_ sender: UIButton) {
let newPlan = sender.frame.origin.x
scrollView.subviews.forEach{$0.removeFromSuperview()}
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextController = storyBoard.instantiateViewController(withIdentifier: "PlansViewController2") as! PlansViewController2
addChildView(viewController: nextController, in: scrollView)
self.movingView.frame.origin.x = newPlan
}
Now I want to add a tool bar item that only shows up when Plans or Documents is selected and disappears when Visit is selected.
At the moment I add my tool bar item in the viewDidLoad method:
self.toolbarItems = [UIBarButtonItem(title: "Kategorienliste", style: .plain, target: self, action: #selector(handleCategoryListTap(sender:)))]
How can I add a toolbarItem when a certain button is selected and remove it when another button is selected? Thanks in advance!
You can create your UIBarButtonItem with a custom view like:
let button = UIButton()
let barButtonItem = UIBarButtonItem(customView: button)
self.toolbarItems = [barButtonItem]
to hide / show you can access the button as the following:
let barButtonItem = self.toolbarItems.first
barButtonItem.customView?.isHidden = true
Hope it helps.

Snapshot of screen shows toolbar on device but not on simulator

I have a toolbar that's instantiated on viewDidLoad on top of a webkit. When I take a snapshot on the simulator, the toolbar is missing which is what I would like. When built on the device, the toolbar is there.
I tried to hide the toolbar with:
toolbar.isHidden = true
but the application crashes with toolbar being nil. If I change it to:
toolbar?.isHidden = true
It still shows up considering it still thinks it's nil.
The toolbar is set up on viewDidLoad by calling another function:
var toolbar : UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
setUpToolBar()
}
func setUpToolBar() {
let saveButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(takeScreenshot))
...
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 300, width: 200, height: 50))
toolbar.setItems([saveButton,flexibleSpaceFillerLeft,userAgentButton,flexibleSpaceFillerRight,doneButton], animated: true)
view.addSubview(toolbar)
}
The code for my snapshot is below. This is where I tried to hide the toolbar before taking the snapshot.
#objc func takeScreenshot() {
webView.takeSnapshot(with: nil, completionHandler: { (image,error) in
if let image = image {
self.screenshotOfWindow = image
self.showScreenshotEffect()
self.saveAllData()
} else {
print (error?.localizedDescription as Any)
}
})
}
Here's the screen I need to take a screenshot of:
The red box in the screenshot is the bar that I need to disappear from the screenshot.
I'd like to be able to take the screenshot without the bottom bar in view. As stated before, this works in the simulator, but the device always shows the bar. There's also a "navigation controller" gap at the top of the screenshot since the top bar covers part of the screen at top, but this is just blank and something I can address later.
I just wanted to come back and answer how I solved this. The webview is embedded in a navigation controller, but I was creating the toolbar programmatically on viewDidLoad by calling a setupToolBar function I had created early on in the project. I could hide the toolbar, but it was still being captured while taking the screenshot. I commented all of that code out and used the navigation controller's toolbar instead. Now when I take the screenshot, the bottom and top bar of the navigation controller is not part of the screenshot.

Using UINavigationItem on UITabBarController

I have a project with a UITabBarController and a couple of views. Sort of like this:
In this project, the tab bar controller is called by tapping the Tab button on the UIViewController. I would like to get rid of the back button with "Title", and replace it with an "X" icon. When tapped, the "X" icon would dismiss the UITabBarController and return to the caller. I do this all of the time on UINavigationController using a UINavigationItem, but that does not appear to work in this situation. I drag the UINavigationItem to the view and it allows it, but it does not show up on the view and any UIBarButtonItem that I drag and drop on it do not appear.
Is there a way to actually do this? I'd even be ok with leaving the existing back button as it is and just getting rid of "Title"
I figured it out right after posting the question. Just a bit more research is all it took.
To fix this, add the following to the UITabBarController code.
override func viewDidLoad() {
super.viewDidLoad()
let buttonImage = UIImage(named: "back")
let leftButton = UIBarButtonItem(image: UIImage(named: "back"), style: .plain, target: self, action: #selector(dismissTabBar))
leftButton.tintColor = UIColor.black
self.navigationItem.leftBarButtonItem = leftButton
}
#IBAction func dismissTabBar() {
self.navigationController?.popToRootViewController(animated: true)
}
This gives me a black back button with my image. When I tap it, it brings me back to the calling 'UIViewController.

Adding Hamburger Button to SWRevealViewController in Swift

In the app I'm making I have a side menu that I used SWRevealViewController template to make. I made my own animated button to be the hamburger menu button so when its pressed the side menu will open. The problem is I can't figure out how to connect my animated button to the SWRevealViewController.
Here's the button code I made.
Animated Button
self.button = HamburgerButton(frame: CGRectMake(0, 0, 30, 30))
self.button.addTarget(self, action: #selector(home.toggle(_:)), forControlEvents:.TouchUpInside)
let refreshButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Refresh,
target: self, action: #selector(home.buttonMethod))
navigationItem.leftBarButtonItem = button
and heres the button that was used for the SWRevealViewController
override func viewDidLoad() {
super.viewDidLoad()
if revealViewController() != nil {
menuButton.target = revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
}
Ive done a lot of research but just can't find out how to do it. I need the button I made, which is the first code, to be the one to access the SWRevealViewController and to open and close the side menu rather then the button, which is the second code, that came with the SWRevealViewController template. Any help will be Awesome!!
This is how I do it. You can adapt this to your needs.
let singleTap = UITapGestureRecognizer(target: self, action: #selector(tapDetected))
singleTap.numberOfTapsRequired = 1
sideMenuButton.userInteractionEnabled = true
sideMenuButton.addGestureRecognizer(singleTap)
func tapDetected() {
self.revealViewController().revealToggle(self)
}