Make a UISwitch hide/unhide a label when it toggles on/off - ios

MeditationSettingsViewController has a UISwitch which is linked to MeditationScreenViewController though a Segue. The UISwitch doesn't hide the text in the label called phaselabel from MeditationScreenViewController but instead displays the MeditationSettingsViewController screen. How do I get it so that the switch doesn't do this but hides and unhides phaselabel when the switch is turned on/off?
class MeditationSettingsViewController: UIViewController {
#IBAction func showCycleTitleChanged(_ sender: UISwitch) {
if (sender.isOn == true)
{
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segue" {
if let sendToDetailViewController = segue.destination as? MeditationScreenViewController {
sendToDetailViewController.isSwitchOn = sender!.isOn
}
}
class MeditationScreenViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
if isSwitchOn == true {
//unhide the label
self.phaseLabel.isHidden = true
//set your label value here
}
else {
self.phaseLabel.isHidden = false
}
}

Try using NSNotificationCenter to let the two view controllers be aware of the switch state change.
In MeditationSettingsViewController in the showCycleTitleChanged function, do this:
#IBAction func showCycleTitleChanged(_ sender: UISwitch) {
let data:[String: Bool] = ["state": sender!.isOn]
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "switchChanged"), object: nil, userInfo: data)
}
In MeditationScreenViewController, listen to the notification like so:
In viewDidLoad:
NotificationCenter.default.addObserver(self, selector: #selector(self.showHideLabel(_:)), name: NSNotification.Name(rawValue: "switchChanged"), object: nil)
Also add this function to handle the notification:
func showHideLabel(_ notification: NSNotification) {
self.phaselabel.isHidden = notification.userInfo?["state"] as? Bool
}

Related

How to hide a UILabel from another UIViewController using Notifications and Observer

I have 2 UIViewControllers and I try to hide an UILabel from the second UIViewController using Notifications and Observer.
Is the first time when I use this design pattern and I'm a little bit confused. What I'm doing wrong ?
I want to specify that I'm getting the message from that print for the first time only when I click the back button from the second ViewController.
And after that I'm getting the message normal when I click Go Next but the UILabel is not hidden or colour changed.
Here is my code for first UIViewController:
class ReviewPhotosVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.post(name: Notification.Name("NotificationOfReviewMode"), object: nil)
}
#IBAction func goNextTapped(_ sender: UIButton) {
let fullscreenVC = storyboard?.instantiateViewController(withIdentifier: "FullscreenPhoto") as! FullscreenPhotoVC
self.present(fullscreenVC, animated: true, completion: nil)
}
}
Here is my code for second UIViewController:
class FullscreenPhotoVC: UIViewController {
#IBOutlet weak var customLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(hideCustomLabel),
name: Notification.Name("NotificationOfReviewMode"),
object: nil)
}
#IBAction func goBackTapped(_ sender: UIButton) {
let reviewPhotosVC = storyboard?.instantiateViewController(withIdentifier: "ReviewPhotos") as! ReviewPhotosVC
self.present(reviewPhotosVC, animated: true, completion: nil)
}
#objc func hideCustomLabel(){
customLabel.isHidden = true
customLabel.textColor = .red
print("My func was executed.")
}
}
Here is my Storyboard:
Thanks if you read this.
The problem is that you are posting the notification before the next controller is initialised and has started observing. Also, there is no need for the notification you can do it directly. In this case I have used an extra variable shouldHideLabel as you cannot call the function hideCustomLabel() directly because this will lead to crash as the outlets are only initialised after view is loaded.
class ReviewPhotosVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//NotificationCenter.default.post(name: Notification.Name("NotificationOfReviewMode"), object: nil)
}
#IBAction func goNextTapped(_ sender: UIButton) {
let fullscreenVC = storyboard?.instantiateViewController(withIdentifier: "FullscreenPhoto") as! FullscreenPhotoVC
fullscreenVC.shouldHideLabel = true
self.present(fullscreenVC, animated: true, completion: nil)
}
}
class FullscreenPhotoVC: UIViewController {
var shouldHideLabel = false
#IBOutlet weak var customLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
if shouldHideLabel {
hideCustomLabel()
}
/*
NotificationCenter.default.addObserver(self,
selector: #selector(hideCustomLabel),
name: Notification.Name("NotificationOfReviewMode"),
object: nil)
*/
}
#IBAction func goBackTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
#objc func hideCustomLabel() {
customLabel.isHidden = true
customLabel.textColor = .red
print("My func was executed.")
}
}

swift4: can't pass value to previous view controller from current popover

I'm using swift4, i present view controller modally as popover and want to pass data back to previous view controller when dismissing current popover, this is the first View controller :
import UIKit
class SearchResultViewController: UIViewController, UIPopoverPresentationControllerDelegate, PopoupDelegate {
#IBOutlet var errorLable: UILabel!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "pop") {
let dest = segue.destination
if let pop = dest.popoverPresentationController {
dest.preferredContentSize = CGSize(width: self.view.frame.size.height - 20, height: 500)
pop.delegate = self
}
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
func popupValueSelected(value: String) {
print("value: ", value)
self.errorLable.text = value
}
}
and this the popover code:
import UIKit
class SearchPopoverViewController: UIViewController {
#IBOutlet var cityLable: UILabel!
var delegate: PopoupDelegate?
#IBAction func closeButtonAction(_ sender: Any) {
self.delegate?.popupValueSelected(value: "hiiiiii from the other side")
self.dismiss(animated: false, completion: nil)
}
}
and this is the PopoupDelegate
import Foundation
protocol PopoupDelegate {
func popupValueSelected(value: String)
}
when i click in the popover close button, the popover should dismiss and the errorLable in SearchResultViewController should change it's text to new passed text, but none happens, only the popover dismiss,
what should i do?
You delegate function is wrong, function inside function in SearchResultViewController:
func popupValueSelected(value: String) {
func popupValueSelected(value: String) {
print("value: ", value)
self.errorLable.text = value
}
}
It should be:
func popupValueSelected(value: String) {
print("value: ", value)
self.errorLable.text = value
}
After editing the question :
You never assigned any instance to the delegate variable. Try to change delegate variable name to popoUpDelegate.
pop.delegate is for UIPopoverPresentationControllerDelegate not your delegate. This function should be like this :
if (segue.identifier == "pop") {
if let dest = segue.destination.popoverPresentationController as? SearchPopoverViewController {
dest.preferredContentSize = CGSize(width: self.view.frame.size.height - 20, height: 500)
dest.popoUpDelegate = self
}
}
}
And your SearchPopoverViewController look like this :
class SearchPopoverViewController: UIViewController {
#IBOutlet var cityLable: UILabel!
var popoUpDelegate: PopoupDelegate?
#IBAction func closeButtonAction(_ sender: Any) {
self.popoUpDelegate?.popupValueSelected(value: "hiiiiii from the other side")
self.dismiss(animated: false, completion: nil)
}
}
you have to define delegate to SearchResultViewController.
var PopoupDelegate : PopoupDelegate?
and before pop viewcontroller assign delegate to popoupDelegate
PopoupDelegate.delegate = self
and you have right function inside function. first make it correct.
Try this. Hope this will work. and let me know in case of any concern
When you are presenting SearchPopoverViewController from SearchResultViewController you need to set delegate.
Using segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "segueToPopOver") {
let dest = segue.destination
if let vc = dest.popoverPresentationController as? SearchPopoverViewController {
//set other properties
vc.delegate = self
}
}
}
Using UINavigationController
let vc = SearchPopoverViewController() // initialise view controller
vc.delegate = self
present(vc, animated: true, completion: nil)
Respond to delegate
#IBAction func closeButtonAction(_ sender: Any) {
self.delegate?.popupValueSelected(value: "hiiiiii from the other side")
self.dismiss(animated: false, completion: nil)
}
In SearchResultViewController implement delegate method
func popupValueSelected(value: String) {
print("value: ", value)
self.errorLable.text = value
}
I think you have a fundamental misunderstanding as to how segues and protocols work for view controllers. Frankly, I would recommended reviewing the topic in Apple's App Development with Swift. This is written clearly with exercises to help you understand the basics of passing information between view controllers. I have been where you are, and while the suggestions and comments have been correct, you don't seem to have the foundation to understand what they are saying. Good luck!
I used popover dismiss delegate instead of protocol:
this code solved my problem:
in the SearchResultViewController:
func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
if let searchPopoverViewController =
popoverPresentationController.presentedViewController as? SearchPopoverViewController{
self.passed_city_id = searchPopoverViewController.selected_city_id
}
}
in the SearchPopoverViewController
#IBAction func searchButtonAction(_ sender: Any) {
self.selected_city_id = 10
popoverPresentationController?.delegate?.popoverPresentationControllerDidDismissPopover?(popoverPresentationController!)
self.dismiss(animated: true, completion: nil)
}
you can use "Unwind segue". pls refer
https://medium.com/#mimicatcodes/create-unwind-segues-in-swift-3-8793f7d23c6f

Using a Textfield as a Search Bar in Swift 3 Xcode 8

I have my project setup like this:
I have a custom Tab Navigation Controller. In the top bar of the Custom Tab Navigation Controller is a text field. This text field changes according to the 4 main views of the app (4 tab buttons).
What I am trying to do is use the text field as a search bar by passing whatever is typed into the text field into the searchView However, I am having trouble passing the textfield.text from the Navigation Controller into searchView. I have a picture below that illustrates this more clearly.
The searchView has the search function taken care of. All I am trying to do is pass with textfieled.text value to the searchView whenever it is changed
// global
let handleTextChangeNotification = "handleTextChangeNotification"
your FirstViewController
override func viewDidLoad() {
super.viewDidLoad()
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
func textFieldDidChange(textField: UITextField){
NotificationCenter.default.post(name: NSNotification.Name(rawValue: handleTextChangeNotification), object: nil, userInfo: ["text":textField.text])
let search_screen = SearchViewController()
self.navigationController?.pushViewController(search_screen, animated: true)
}
SeacrchViewController's
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(SeacrchViewController.handleTextChange(_:)),
name: NSNotification.Name(rawValue: handleTextChangeNotification),
object: nil)
}
func handleTextChange(_ myNot: Notification) {
if let use = myNot.userInfo {
if let text = use["text"] {
// your search with 'text' value
}
}
}
}
You can do something like that.
In your FirstViewController
func textFieldDidChange(textField: UITextField){
let search_screen = SearchViewController()
search_screen.search_string = self.textField.text
self.navigationController?.pushViewController(search_screen, animated: true)
}
In case of storyboards
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "Your_SearchViewController_identifier") {
let search_screen = segue.destinationViewController as!
SearchViewController
search_screen.search_string = self.textField.text
}
}
And In your SeacrchViewController's viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.textField.text = self.search_string
}

I'm trying to use Dynamic Buttons by a GitHub source but the do not work

#IBOutlet weak var dynamicButton: DynamicButton!
override func viewDidLoad() {
super.viewDidLoad()
let dynamicButton = DynamicButton(style: DynamicButtonStyle.hamburger)
dynamicButton.setStyle(DynamicButtonStyle.close, animated: true)
}
I'm getting the hamburger button with a bounce effect but I cannot see any transition.
This is the source : https://github.com/YannickL/DynamicButton
Changing styles on tap...
Create a segue to your destination view controller. Give it an identifier, such as "destSegue". Add Touch Down, Touch Up Inside and Touch Up Outside IBActions, as follows:
#IBAction func didTouchDown(_ sender: Any) {
if let b = sender as? DynamicButton {
b.setStyle(.plus, animated: true)
}
}
#IBAction func didTouchUpInside(_ sender: Any) {
if let b = sender as? DynamicButton {
b.setStyle(.hamburger, animated: true)
self.performSegue(withIdentifier: "destSegue", sender: self)
}
}
#IBAction func didTouchUpOutside(_ sender: Any) {
if let b = sender as? DynamicButton {
b.setStyle(.hamburger, animated: true)
}
}
Note that if you tap quickly on the button, you will probably not see the full animation cycle. To allow that, you'll need to edit the source of the DynamicButton and add completion blocks or delegate callbacks.

change label from another viewcontroller on swift

I want to change label from another viewController.
First viewcontroller is MenuController. Second one is LoginViewController.
I want to change MenuController's Label.text from LoginViewController.
In LoginViewController:
let viewController = MenuController()
viewController.changeLabel("logout")
In MenuController:
class MenuController: UITableViewController {
var attractionImages = [String]()
var attractionNames = [String]()
var webAddresses = [String]()
#IBOutlet weak var loginLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
loginLabel.text = "Login"
print(loginLabel.text)
}
func changeLabel(Log: String)O {
self.loginLabel.text = log
print (log)
}
But an error occur.
fatal error: unexpectedly found nil while unwrapping an Optional value
How can I solve it?
Thanks for your help.
Another way to achieve that is you can use NSNotificationCenter. Blow is the example for that:
In your MenuController add this code:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshLbl:", name: "refresh", object: nil)
}
Also add this helper method:
func refreshLbl(notification: NSNotification) {
print("Received Notification")
lbl.text = "LogOut"
}
Now in your LoginViewController your back button action will look like:
#IBAction func back(sender: AnyObject) {
NSNotificationCenter.defaultCenter().postNotificationName("refresh", object: nil, userInfo: nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
Now when ever you press back button from LoginViewController your refreshLbl method will call from MenuController.
For more info refer THIS example.
Swift 3 version:
In your MenuController (where the label needs to be changed) add this code:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(refreshLbl),
name: NSNotification.Name(rawValue: "refresh"),
object: nil)
}
Also add this helper method:
#objc func refreshLbl() {
print("Received Notification")
lbl.text = "LogOut"
}
Now in your LoginViewController your back button action will look like:
#IBAction func backButton(_ sender: Any) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "refresh"), object: nil)
// Any additional code...
}
Now when ever you press back button from LoginViewController your refreshLbl() method will call from MenuController.

Resources