I am making an app with a main view controller and a menu button in it. By clicking the button, there is another view controller as the side-menu appearing and then users can choose to go back to the previous main view controller. However, then the menu button doesn't work anymore.
The code for the main view controller is here (not the container view controller):
#objc
protocol CenterViewControllerDelegate {
optional func toggleLeftPanel()
optional func collapseSidePanels()
}
class CenterViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
var delegate: CenterViewControllerDelegate?
#IBAction func MenuTapped(sender: AnyObject) {
delegate?.toggleLeftPanel?()
}
// MARK: Button actions
}
You have to take a bool flag to track open/collapse of menu, something like this:
#objc
protocol CenterViewControllerDelegate {
optional func toggleLeftPanel()
optional func collapseSidePanels()
}
class CenterViewController: UIViewController {
var _isMenuOpen = false
#IBOutlet weak var titleLabel: UILabel!
var delegate: CenterViewControllerDelegate?
#IBAction func MenuTapped(sender: AnyObject) {
if _isMenuOpen{
delegate?.toggleLeftPanel?()
_isMenuOpen = true
}
else{
delegate?.collapseSidePanels?()
_isMenuOpen = false
}
}
// MARK: Button actions
}
Hope this will help you.
Related
I have a view controller with a UIImage that will be sent to a service. I'm trying to load this image from another view so I'm using delegation. However I cant seem to understand why it will not work. I set some messages to print in the console and I see them right before the call to the method but its not setting the variables and I'm not sure why.
The view are linked via a navigation controller and to return I use popViewController and to go to the other view controller I use a simple show segue from the button. The "confirmation" of the selected image is done with a button that is supposed to send the image to the previous view controller.
This is the main controller with the UIImage I want to set from another view:
import UIKit
class MainNewPost: UIViewController{
override var preferredStatusBarStyle: UIStatusBarStyle{
return.lightContent
}
var imageForUpload: UIImage?
var isImageSelected: Bool = false
#IBOutlet weak var newPostBox: TVUIView!
#IBOutlet weak var newPost: UIButton!
#IBAction func sendNewPost(_ sender: Any) {
var imageId = ""
if isImageSelected {
imageId = UUID().uuidString
ImageWS.sendIamge(imageId: imageId, image: imageForUpload!, {()}, error: {(errorMessate) in
print(errorMessate)
})
}
if (newPostBox.text!.isEmpty) {
Util.showMessage(controller: self, message: "Ingrese un texto", seconds: 5)
} else {
PostWS.newPost({() in
Util.showMessage(controller: self, message: "Enviaste un mensaje!", seconds: 3.0)
}, img: imageId, postBody: newPostBox.text!, personId: PersonBE.shared!.personId, posterName: PersonBE.shared!.displayName, error: {(errorMessage) in print(errorMessage)})
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension MainNewPost: NewPostDelegate {
// This is not executing. I'm calling it since I see the console message by the flag and image dont get set
func selectedImage(_ image: UIImage, _ isImageSelected: Bool) {
self.imageForUpload = image
self.isImageSelected = isImageSelected
}
}
This is the view controller where I select the image:
import UIKit
protocol NewPostDelegate {
func selectedImage(_ image: UIImage, _ isImageSelected: Bool)
}
class imageSelectViewController: UIViewController {
var postDelegate: NewPostDelegate?
#IBOutlet weak var imageView: UIImageView!
var imagePicker: ImagePicker!
override func viewDidLoad() {
super.viewDidLoad()
self.imagePicker = ImagePicker(presentationController: self, delegate: self)
}
#IBAction func showImagePicker(_ sender: UIButton) {
self.imagePicker.present(from: sender)
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return.lightContent
}
#IBAction func clickBtnBack(_ sender: Any){
self.navigationController?.popViewController(animated: true)
}
#IBAction func selectImage(_ sender: Any) {
// I see this message printed in the console
// This button is suposed to send the selected image to the previous view controller
print("In selectImage button")
self.postDelegate?.selectedImage(imageView.image!, true)
self.navigationController?.popViewController(animated: true)
}
}
extension imageSelectViewController: ImagePickerDelegate {
func didSelect(image: UIImage?) {
// I see this message printed in the console
print("In didSelect delegate method")
self.imageView.image = image
self.postDelegate?.selectedImage(image!, true)
}
}
Thanks!
It seems that var postDelegate: NewPostDelegate? in your imageSelectViewController instance remains nil. Which means that even if you're calling a delegate method, there is no delegate specified itself.
In order to fix it you should assign your MainNewPost instance reference to var postDelegate: NewPostDelegate? of your destination imageSelectViewController while preparing for segue.
I'm using PanelKit for an iOS app that I'm developing right now.
I have set up a panel, which is a ViewController, and have set up a button in that ViewController. When pressed, I want a picture to be displayed in another ViewController (the main VC that's instantiated when the app is launched). I'm using a delegate for this. However, my delegate function never gets executed. Here's my code:
Delegate:
protocol IMGPickerDelegate: class {
func didFinishPicking(_ imageData: UIImage)
}
Panel ViewController:
class IMGLibraryViewController: UIViewController, PanelContentDelegate {
weak var delegate: IMGPickerDelegate?
#IBAction func fireButton(_ sender: Any) {
let imageSample = UIImage(named: "sample")!
didPickImage(imageDData: imageSample)
}
func didPickImage(imageDData: UIImage) {
delegate?.didFinishPicking(imageDData)
}
Main ViewController:
class ImageDisplayViewController: UIViewController, IMGPickerDelegate {
#IBOutlet weak var imageDisplayViewOutlet: UIImageView!
var imgLibrary = IMGLibraryViewController()
func didFinishPicking(_ imageData: UIImage) {
imageDisplayViewOutlet.image = imageData
}
override func viewDidLoad() {
super.viewDidLoad()
imgLibrary.delegate = self
}
I have an onboarding user flow:
Name -> Age -> Gender
Each of the screens shares the same structure:
Question (top)
Input (middle)
Continue (bottom)
I have a class OnboardingHelper.swift that creates a class to set the question box and continue button:
class UserOnboardingHelper{
var text: String
var questionbox: UIView
var viewController: UIViewController
var continueButton: UIButton
init(text: String, questionbox: UIView, viewController: UIViewController, continueButton: UIButton){
self.text = text
self.questionbox = questionbox
self.viewController = viewController
self.continueButton = continueButton
}
func setQuestionBox(){
//sets question box
}
func setContinueButton(){
//sets continue button
enableContinueButton()
addContinueButtonPath()
}
func enableContinueButton(){
//enables continue button
}
func disableContinueButton(){
//disables continue button
}
func addContinueButtonPath(){
//sets path of continue button based on which view
}
}
In each of the onboarding ViewControllers I am setting the class in ViewDidLoad():
class NamePageViewController: UIViewController, UITextFieldDelagate {
#IBOutlet weak var questionbox: UIView!
#IBOutlet weak var continueButton: UIButton!
#IBOutlet weak var inputLabel: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let namePageSettings = UserOnboardingHelper(text: "What is your name", questionbox: questionbox, viewController: self, continueButton: continueButton)
namePageSettings.setQuestionBox()
namePageSettings.setContinueButton()
inputLabel.delegate = self
if nameIsFilled {
namePageSettings.enableContinueButton()
} else{
namePageSettings.disableContinueButton()
}
}
}
The issue is that in the ViewController I textFieldDidEndEditing() function which needs to call the namePageSettings class from viewDidLoad()
func textFieldDidEndEditing(_ textField: UITextField){
if (textField.text?.empty)!{
//I want to call disableContinueButton() from UserOnboardingHelper
} else {
//I want to enable enableContinueButton() from UserOnboardingHelper
}
}
Trying to understand if:
The overall approach is correct and if not, what's the best way
If the above approach is in the right direction, how should disableContinueButton() and enableContinueButton() be called?
Thanks in advance! Sorry if the approach is really dumb - I'm still trying to wrap my head around classes.
You can have the view controller have a weak reference to the onboarding helper, so you can still call helper methods without creating a retain cycle.
In NamePageViewController, add a property:
weak var userOnboardingHelper: UserOnboardingHelper?
Then, in UserOnboardingHelper's initializer, add:
self.viewController.userOnboardingHelper = self
You can now call the onboarding helper's methods in the view controller:
userOnboardingHelper.disableContinueButton()
userOnboardingHelper.enableContinueButton()
I have 2 UISwitch and a Button, in viewDidLoad, I set the button to be hidden and disabled, I want only my button to be not hidden if those 2 switch is in ON state, otherwise, I want my button to hide again. is there any method from UI Switch delegate that can be used ? how do I do that in Swift ?
here is the code I use
import UIKit
class AskingAuthorizationVC: UIViewController {
#IBOutlet weak var locationSwitch: DesignableSwitch!
#IBOutlet weak var notificationSwitch: DesignableSwitch!
#IBOutlet weak var nextButton: DesignableButton!
override func viewDidLoad() {
super.viewDidLoad()
// initial state
nextButton.isHidden = true
nextButton.isEnabled = false
notificationSwitch.isOn = false
locationSwitch.isOn = false
}
#IBAction func signUpButtonDidPressed(_ sender: Any) {
performSegue(withIdentifier: "toAuthenticationVC", sender: nil)
}
}
Hook both of the UISwitch-s as IBActions & IBOutlets
#IBAction func oweSwitch(_ sender: UISwitch) {
self.mybutton.isHidden = !(switch1.isOn && switch2.isOn)
}
I want to change with two subviews as button been clicked, the subview was created by StoryBoard, each subview has a button, click the button will bring another subview and hidden current one.
But I found when a subview call removeFromSuperview(), it will be release automatically, if I want to use this subview later, I need a var to point it.
Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var secondView: UIView!
#IBOutlet weak var firstView: UIView!
var temp1: UIView?
var temp2: UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
temp1 = firstView
temp2 = secondView
secondView.removeFromSuperview()
}
#IBAction func moveToSecond(_ sender: UIButton) {
firstView.removeFromSuperview()
view.insertSubview(secondView, at: 0)
secondView.isUserInteractionEnabled = true
}
#IBAction func moveToFirst(_ sender: UIButton) {
secondView.removeFromSuperview()
view.insertSubview(firstView, at: 0)
firstView.isUserInteractionEnabled = true
}
}
Without two temp var, subview will release after removeFromSuperview, and cause next insertSubview crash because it is nil.
So, How to prevent subview auto release?
Is there another way to change between two subviews created by StoryBoard graceful?
My mistake, I didn't notice that outlet is weak, everything is reasonable, when removeFromSuperview, no strong point is left to the sub view, than it release automatically.
You can use #IBOutlet var secondView: UIView! to create strong reference of the view.But as per your requirement I suggest not to remove it from the super view. Instead of that you should hide and show the views when needed as below.
class ViewController: UIViewController {
#IBOutlet var secondView: UIView!
#IBOutlet var firstView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
secondView.isHidden = true
}
#IBAction func moveToSecond(_ sender: UIButton) {
firstView.isHidden = true
secondView.isHidden = false
secondView.isUserInteractionEnabled = true
}
#IBAction func moveToFirst(_ sender: UIButton) {
secondView.isHidden = true
firstView.isHidden = false
firstView.isUserInteractionEnabled = true
}
}
Assuming your two views are one upon above , having same width and same height . In viewDidLoad . first set the firstView to front and secondView to back. Once button click i bring secondView to front and firstView to back , like so on.
import UIKit
class ViewController1: UIViewController {
#IBOutlet var secondView: UIView!
#IBOutlet var firstView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.bringSubview(toFront: firstView)
self.view.sendSubview(toBack: secondView)
}
#IBAction func moveToSecond(_ sender: UIButton) {
self.view.bringSubview(toFront: secondView)
self.view.sendSubview(toBack: firstView)
}
#IBAction func moveToFirst(_ sender: UIButton) {
self.view.bringSubview(toFront: firstView)
self.view.sendSubview(toBack: secondView)
}
}
If your two sub view's are in different position of the view. then you need to hide alternative View in respective button click
class ViewController: UIViewController {
#IBOutlet var secondView: UIView!
#IBOutlet var firstView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
secondView.isHidden = true
firstView.isUserInteractionEnabled = true
}
#IBAction func moveToSecond(_ sender: UIButton) {
firstView.isHidden = true
secondView.isHidden = false
secondView.isUserInteractionEnabled = true
}
#IBAction func moveToFirst(_ sender: UIButton) {
secondView.isHidden = true
firstView.isHidden = false
firstView.isUserInteractionEnabled = true
}
}