How to disappear sidemenu without button in swift 4 - ios

I have some question. i made side menu in swift4.
when i clicked button, side menu appear and disappear.
but i want make disappear side menu without button.
for example, when i clicked another view (not side menu), disappear sidemenu.
my code like this.
class ContainerVC: UIViewController {
#IBOutlet weak var constaint: NSLayoutConstraint!
var sideMenuOpen = false
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(toggleSideMenu), name: NSNotification.Name("ToggleSideMenu"), object: nil)
}
#objc func toggleSideMenu(){
if sideMenuOpen {
sideMenuOpen = false
constaint.constant = -130
}else {
sideMenuOpen = true
constaint.constant = 0
}
UIView.animate(withDuration: 0.3){
self.view.layoutIfNeeded()
}
}
when i click white background (view) , disappear side menu.
Thanks.

You can use code something like that, please add following code in viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(dismiss(fromGesture:)))
self.view.addGestureRecognizer(tap)
Then create a function for dismiss
#objc func OpenSideMenu(){
sideMenuOpen = true
constaint.constant = 0
UIView.animate(withDuration: 0.3){
self.view.layoutIfNeeded()
}
}
#objc func closeSideMenu(){
sideMenuOpen = false
constaint.constant = -130
UIView.animate(withDuration: 0.3){
self.view.layoutIfNeeded()
}
}
#objc func dismiss(fromGesture gesture: UISwipeGestureRecognizer) {
closeSideMenu()
}
Hope this will work.

Related

fade in button so it won't automatically fade out again

I'm using a tap gesture recogniser so if the user taps on the screen the button fades out for 5 seconds and then if the user wants to see the buttons on the screen again they tap on the screen and the button fades in.
The Problem is:
I can't disable the button when it fades in so it won't automatically fade out again. I tried to invalidate the timer but that didn't work. To be more specific of what I want to do:
On app load, you see an enabled "Start Stop Button." - Tap anywhere on the screen and a 5 second timer starts to fade the button out and disables it. Once the button fades out and disables, I can tap anywhere on the screen to fade the button back in, enable it, and kill the timer so the button shows up as it was before I first tapped it.
class ViewController: UIViewController {
// Create these 3 properties in the top of your class
var secondToFadeOut = 5 // How many second do you want the view to idle before the button fades. You can change this to whatever you'd like.
var timer = Timer() // Create the timer!
var isTimerRunning: Bool = false // Need this to prevent multiple timers from running at the same time.
#IBOutlet weak var startStopButton: UIButton! // The outlet for your button. This is used to fade it in and out, and enable / disable it.
override func viewDidLoad() {
super.viewDidLoad()
startStopButton.isEnabled = true
runTimer()
// Add a tap gesture recognizer to the main view to determine when the screen was tapped (for the purpose of resetting the timer).
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tap(_:)))
self.view.addGestureRecognizer(tapRecognizer)
}
func runTimer() {
// Create the timer to run a method (in this case... updateTimer) every 1 second.
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(ViewController.updateTimer)), userInfo: nil, repeats: true)
// Set the isTimerRunning bool to true
isTimerRunning = true
}
#objc func updateTimer() {
// Every 1 second that this method runs, 1 second will be chopped off the secondToFadeOut property. If that hits 0 (< 1), then run the fadeOutButton and invalidate the timer so it stops running.
secondToFadeOut -= 1
print(secondToFadeOut)
if secondToFadeOut < 1 {
fadeOutButton()
timer.invalidate()
isTimerRunning = false
}
}
#objc func tap(_ gestureRecognizer: UITapGestureRecognizer) {
// When the view is tapped (based on the gesture recognizer), reset the secondToFadeOut property, fade in (and enable) the button.
//secondToFadeOut = 5
fadeInButton()
timer.invalidate()
//if isTimerRunning == false {
// runTimer()
//}
}
func fadeOutButton() {
// Fade out your button! I also disabled it here. But you can do whatever your little heart desires.
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 0.25
}
self.startStopButton.isEnabled = false
}
func fadeInButton() {
// Fade the button back in, and set it back to active (so it's tappable)
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 1
}
self.startStopButton.isEnabled = true
}
#IBAction func startStopButtonPressed(_ sender: UIButton) {
print("Start Stop Button Pressed")
}
}
My best guess is that you have a rogue Timer object that remains in memory even after you invalidate your current timer, and that is causing the button to fade out again after it fades in.
I have made several edits to your class. Check the code out:
class ViewController: UIViewController {
// Create these 3 properties in the top of your class
var secondToFadeOut = 5 // How many second do you want the view to idle before the button fades. You can change this to whatever you'd like.
var timer? = nil // Create the timer!
#IBOutlet weak var startStopButton: UIButton! // The outlet for your button. This is used to fade it in and out, and enable / disable it.
override func viewDidLoad() {
super.viewDidLoad()
startStopButton.isEnabled = true
runTimer()
// Add a tap gesture recognizer to the main view to determine when the screen was tapped (for the purpose of resetting the timer).
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tap(_:)))
self.view.addGestureRecognizer(tapRecognizer)
}
func runTimer() {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: secondToFadeOut, target: self, selector: (#selector(ViewController.timerFired)), userInfo: nil, repeats: false)
}
}
#objc func timerFired() {
timer = nil
if self.startStopButton.isEnabled {
fadeOutButton()
} else {
fadeInButton()
}
}
#objc func tap(_ gestureRecognizer: UITapGestureRecognizer) {
runTimer()
}
func fadeOutButton() {
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 0.25
}
self.startStopButton.isEnabled = false
}
func fadeInButton() {
UIView.animate(withDuration: 0.5) {
self.startStopButton.alpha = 1
}
self.startStopButton.isEnabled = true
}
#IBAction func startStopButtonPressed(_ sender: UIButton) {
print("Start Stop Button Pressed")
}
}

Swift - Prevent back event in UIViewController

i have a question about canceling the back event triggered from the back-button in a UIViewController. In Objective-C there was the following extension. I don't really know how to convert it to swift. What I tried to far was to override the backBarButton with my own functions but it's not working:
navigation.backBarButtonItem?.action = #selector(MyController.back)
navigation.backBarButtonItem?.target = self
I searched for something like a delegate function but I can't find anything for the backButton.
You need to override the backBarButtonItem by using the navigationItem's leftBarButtonItem. This replaces the back button in the navigation bar, and you can specify the custom selector to call:
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .Done, target: self, action: #selector(self.backAction(sender:)))
func backAction(sender: AnyObject) {
//Your Code
}
When i faced with this problem, i rewrited this extension to Swift 3
This solution keeps system back button with "<"
public protocol VCWithBackButtonHandler {
func shouldPopOnBackButton() -> Bool
}
extension UINavigationController: UINavigationBarDelegate {
public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
if viewControllers.count < (navigationBar.items?.count) ?? 0 {
return true
}
var shouldPop = true
let vc = self.topViewController
if let vc = vc as? VCWithBackButtonHandler {
shouldPop = vc.shouldPopOnBackButton()
}
if shouldPop {
DispatchQueue.main.async {[weak self] in
_ = self?.popViewController(animated: true)
}
} else {
for subView in navigationBar.subviews {
if(0 < subView.alpha && subView.alpha < 1) {
UIView.animate(withDuration: 0.25, animations: {
subView.alpha = 1
})
}
}
}
return false
}
}
Usage:
class ViewController: UIViewController,VCWithBackButtonHandler{
public func shouldPopOnBackButton() -> Bool {
return false
}
}
Try this:
override func viewDidLoad {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Bordered, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton
}
func back(sender: UIBarButtonItem) {
// Perform your custom actions
// ...
// Go back to the previous ViewController
self.navigationController?.popViewControllerAnimated(true)
}

TabBar hides in viewDidLoad but doesnt in gesture function

I tried calling tabBarController!.tabBar.hidden = true in viewDidLoad() and it hides the TabBar. However, I tried to set tap gesture and hide the bar on Tap. The parent viewController that has ScrollView inside it with subview (that is connected with IBOutlet as myView)
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
myView.addGestureRecognizer(tap)
}
func handleTap(sender: UITapGestureRecognizer? = nil) {
print("A") // logs successfully
if TabBarHidden == false {
print("B") // logs successfully
//I tried:
tabBarController?.tabBar.hidden = true
// I also tried
tabBarController?.tabBar.alpha = 0
tabBarController?.tabBar.frame.origin.x += 50
hidesBottomBarWhenPushed = true
} else {
...
TabBarHidden = false
}
}
hidden does work when I call it in viewDidLoad as I said, but not if I call in tap gesture function. What may be the problem? What am I missing?
this code totally works for me:
class ViewController: UIViewController {
var tabBarHidden: Bool = false {
didSet {
tabBarController?.tabBar.hidden = tabBarHidden
}
}
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognized(_:)))
view.addGestureRecognizer(tapGestureRecognizer)
}
func tapGestureRecognized(sender: UITapGestureRecognizer) {
tabBarHidden = !tabBarHidden
}
}

Using Back on Navigation Bar bugs UIBarButtonItem

I have a NavigationBar at the top of a TableView. It looks nice opening/closing the search.
However, if I click on a button in a cell and get directed to another page (with segue); and then use Back button to unwind, it seems like bugged.
()
So it looks like it is pressed and opened but it shouldn't have. It should be looked like the top picture instead (just UIBarButtonItem - search button)
I couldn't figure out the issue creating this problem.
Please note that < Back is created automatically and I didn't write any code to create it. Is there something I am doing wrong?
Update: Added some snippets...
First, created a different class for handling the search
class SearchBarViewController: UIViewController, UISearchBarDelegate {
var searchBar : UISearchBar?
var searchBarWrapper : UIView?
var searchBarButtonItem : UIBarButtonItem?
func constructSearchBar()
{
searchBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "showSearchBar")
self.navigationItem.rightBarButtonItem = searchBarButtonItem
}
func showSearchBar() {
// styling & configuration
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
UIView.animateWithDuration(0.2, animations: {
self.searchBar?.resignFirstResponder()
self.searchBarWrapper?.alpha = 0
}, completion: { (success) -> Void in
self.searchBar = nil
self.searchBarWrapper = nil
self.navigationItem.rightBarButtonItem = self.searchBarButtonItem
})
}
}
And my ViewController:
class ViewController: SearchBarViewController {
override func viewDidLoad() {
super.viewDidLoad()
constructSearchBar()
}
}
Regarding to emrys57's answer, I tried adding viewWillAppear() in my ViewController but I couldn't make it work, as my cancel looks a little different:
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
// Here, I couldn't figure out what to put because
// my searchBarCancelButtonClicked() needs searchBar and
// forces me to use (!) but then it says, it's optional..
}
The answer is...
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
navigationItem.titleView = nil
constructSearchBar()
}
You have not posted code, so it's not entirely clear what's gone wrong. Using UISearchBar, I think you must be handling the buttons separately yourself, as opposed to using UISearchController. I think that you may not be clearing away the search bar when coming back from the second VC. This code clears out the search bar in viewWillAppear:
class ViewController: UIViewController {
var cancelButton: UIBarButtonItem?
var searchButton: UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
cancelButton = UIBarButtonItem(barButtonSystemItem: .Cancel, target: self, action: Selector("searchCancelPressed:"))
searchButton = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: Selector("searchPressed:"))
}
override func viewWillAppear(animated: Bool) {
super.viewDidAppear(animated)
searchCancelPressed(nil)
}
func searchPressed(sender: AnyObject) {
navigationItem.titleView = UISearchBar()
navigationItem.rightBarButtonItem = cancelButton
}
func searchCancelPressed(sender: AnyObject?) {
navigationItem.titleView = nil
navigationItem.rightBarButtonItem = searchButton
}
}
and that is working nicely for me when I do a push from a button to the second VC and then hit back.
Following the edit to the original question, this code seems to work, although it may not be the most elegant way of constructing the answer:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationItem.titleView = nil
searchBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "showSearchBar")
navigationItem.rightBarButtonItem = searchBarButtonItem
}
The function constructSearchBar no longer needs to be called in viewDidLoad, and can be deleted.

NinJump Like game Swift (Score updating issue)

I'm trying to create Ninjump like game using Swift UIKit. everything was working fine until i added scores label. This is actually weird and I can't figure out why its happeing.
So I have a enemy which movies 15px down when timer updates. and One ninja, which moves from left to right when touched on screen. And Score updates when enemy moves out of screen. Whats happening is, score is updating to 1...2..3 when enemies go out of screen. But whenever the score is updating, Ninja moves to left automatically if at right. I don't know why its happening. Its happening everytime when one enemy goes out of the screen. Here's my code
import UIKit
class GameViewController: UIViewController {
#IBOutlet weak var Ninja: UIImageView!
var score = 0
#IBOutlet weak var scoreLabel: UILabel!
var startGame = NSTimer()
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.updateNinja()
}
var enemyImage = UIImageView(frame: CGRectMake(32, -300, 100, 100))
override func viewDidLoad() {
super.viewDidLoad()
self.scoreLabel.text = "0"
enemyImage.image = UIImage(named: "enemy")
self.view.addSubview(self.enemyImage)
}
override func viewDidAppear(animated: Bool) {
startGame = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
if CGRectIntersectsRect(self.Ninja.frame, self.enemyImage.frame) {
println("Game Over")
}
// show the enemy again and again
if self.enemyImage.frame.origin.y > self.view.frame.height {
self.enemyImage.frame.origin.y = -100
score++ // THIS IS THE PROBLEM
self.scoreLabel.text = "\(score)"
}
// move the enemy image downwards
enemyImage.frame.origin.y += 15
}
var isLeft:Bool = false // check where is the ninja left/right
func updateNinja() {
if isLeft {
isLeft = false
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.Ninja.frame.origin.x = 32
})
} else {
isLeft = true
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.Ninja.frame.origin.x = self.rightBar.frame.origin.x - 50
})
}
}
}
and whats more weird is when I remove score++ its working fine.
Update: Its happeing when I'm trying to update the scoreLabel's text. any solution?
hide that label and try creating a new label programatically, update the new label for scores. Let me know if it works for you, It happened to me once as well.

Resources