Swift 4: scrollViewDidScroll not working - swift

I created first View controller "MainViewController" and put into it Container View with outlet contentContainer.
I created second View Controller "AboutContentViewController" and put into it ScrollView
I connect Container View and AboutContentViewController programmatically:
class MainViewController: UIViewController {
#IBOutlet weak var contentContainer: UIView!
override func viewDidLoad() {
let contentControllerName = "AboutContentViewController"
if let contentController = storyboard?.instantiateViewController(withIdentifier: contentControllerName) {
contentContainer.addSubview(contentController.view)
}
}
}
I tried to catch scrollViewDidScroll event using this code
class AboutContentViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var topGalleryScrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
topGalleryScrollView.contentSize = CGSize(width: 3750.0, height: 417.0)
topGalleryScrollView.delegate = self
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("scrollViewDidScroll called")
}
}
In this context scrollViewDidScroll event not working

I have solved problem. AboutContentViewController is need to be add as child view controller to MainVewController before adding its's view to container:
class MainViewController: UIViewController {
#IBOutlet weak var contentContainer: UIView!
override func viewDidLoad() {
let contentControllerName = "AboutContentViewController"
if let contentController = storyboard?.instantiateViewController(withIdentifier: contentControllerName) {
addChildViewController(contentController)
contentContainer.addSubview(contentController.view)
}
}
}

Related

How to show containerview in viewcontroller in swift

I need to show containerview in viewcontroller, so i have taken one viewcontroller and designed and in that i have taken one containerview below to the buttons view
given containerview constraints: below to the buttonview
top = buttonview.bottom 10, leading, trailing, bottom = 0
there are two buttons indicates with green line.. initially i am in the "viewproposalvc" with red colour button.. here if i click gray colour button then i need to show containerview
here the viewproposalvc code:
class ViewProposalVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var postId: Int?
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
updateNavigationBar(with: "View Proposal")
containerView.isHidden = true
}
#IBAction func grayBtn(_ sender: Any) {
containerView.isHidden = false
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ContainerVC") as? ContainerVC
vc.serviceId = self.viewproposalData?.result?.posted_services?.id
self.navigationController?.pushViewController(vc!, animated: true)
}
#IBAction func redBtn(_ sender: Any) {
containerView.isHidden = true
postedServicesCall()
}
}
this is containervc code:
class ContainerVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
}
}
but here containervc not coming below to the buttonsview.. its coming in separate viewcontroller, why?
o/p of containervc: i dont want separate viewcontroller.. i need containervc to show below to the buttonsview of the viewproposalvc
first time i am working with container views, please do help
The reason why is because you are calling
self.navigationController?.pushViewController(vc!, animated: true)
ContainerView is just a generic UIView with an embedded segue, that is triggered from viewDidLoad of the hosted VC. If you need to do additional setup of that VC I suggest making an var on ViewProposalVC and making desired changes from there.
as in
class ViewProposalVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var postId: Int?
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var secondaryController: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
updateNavigationBar(with: "View Proposal")
containerView.isHidden = true
}
#IBAction func grayBtn(_ sender: Any) {
containerView.isHidden = false
self.secondaryController.serviceId = self.viewproposalData?.result?.posted_services?.id
}

Is it possible to modify the properties of a subclass from a parent class in Swift 4?

Via a method or closure, perhaps?
I created a subclass view controller of my superclass/parent view controller and placed labels with placeholder text in that subclass view controller.
I want to set the labels' values to blank strings from the superclass/parent view controller, or, specifically, from an IBAction function that causes the subclass view controller to appear.
Here is the code, first from the parent class, then from the subclass...
'''
class ViewController: UIViewController {
#IBAction func leavingView(){
self.EntryViewController.entryDateLabel.text = ""
self.EntryViewController.entryLabel.text = ""
self.dismiss(animated: true, completion: nil)
}
'''
then from the subclass...
'''
class EntryViewController: ViewController {
#IBOutlet var entryDateLabel: UILabel!
#IBOutlet var entryLabel: UILabel!
}
'''
I have come up with 2 solutions to this problem, without having the parent view controller know about its subclass.
In the first example the parent sets properties on itself that the child listens to (via the didSet method, it then updates its view accordingly. However, this isn't ideal because the entryDate and entry string fields are useless on their own, almost redundant in the parent.
class ParentViewController: UIViewController {
var entryDate: String?
var entry: String?
#IBAction func leavingView(){
self.entryDate = ""
self.entry = ""
self.dismiss(animated: true, completion: nil)
}
}
class ChildViewController: ParentViewController {
#IBOutlet var entryDateLabel: UILabel!
#IBOutlet var entryLabel: UILabel!
override var entryDate: String? {
didSet {
guard isViewLoaded else {
return
}
entryDateLabel.text = entryDate
}
}
override var entry: String? {
didSet {
guard isViewLoaded else {
return
}
entryLabel.text = entry
}
}
}
In my opinion, the second solution is clearer and keeps implementation details more separate because you're using instructions or events to notify the child view controllers.
class ParentViewController: UIViewController {
#IBAction func leavingView(){
self.dismiss(animated: true, completion: didLeaveView)
}
func didLeaveView() { }
}
class ChildViewController: ParentViewController {
#IBOutlet var entryDateLabel: UILabel!
#IBOutlet var entryLabel: UILabel!
override func didLeaveView() {
entryDateLabel.text = ""
entryLabel.text = ""
}
}
Since your requirement is not that much clear I have created a demo for you and into that demo I have added child ContainerViewController into parent ViewController and from that parent view controller you can change UILabel text when you click on UIButton of parent ViewController and code will be for ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnFromParentViewTapped(_ sender: Any) {
//Here get the child of your parent view controller
if let containerView = self.children[0] as? ContainerViewController {
containerView.lblContainer.text = ""
}
}
}
and ContainerViewController code will be:
class ContainerViewController: UIViewController {
#IBOutlet weak var lblContainer: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Don't need to add much here because you are accessing it from parent view.
And your result will be:
As you can see when I click on button which title says Change Container label text the label text from ContainerViewController set to empty string.
For more info check THIS demo project.

Having issues passing a delegate from NSWindowController subclass to my ViewController

I'm having issues with passing a custom protocol (MainWindowControllerProtocol) to the EditorViewController from the MainWindowController, which is subclass of NSWindowController. Please help.
EditorViewController.swift
extension EditorViewController: MainWindowControllerProtocol {
func didOpenFile() {
print("TODO: Open File") // never called, but it should be
}
}
class EditorViewController: NSViewController {
// - IBOutlets
#IBOutlet weak var treeOutlineView: NSOutlineView!
#IBOutlet var codeTextView: NSTextView!
#IBOutlet weak var counterTextField: NSTextField!
#IBOutlet weak var languageTextField: NSTextField!
//public var editor = Editor()
//var rootNode: Node?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
//rootNode = Path(Path.userDownloads).node
// Issue is here
if let windowController = NSApplication.shared.mainWindow?.windowController as? MainWindowController {
windowController.delegate = self
}
else {
print("Doesnt work") // prints this
}
//treeOutlineView.reloadData()
}
}
MainWindowController
public protocol MainWindowControllerProtocol {
func didOpenFile()
}
class MainWindowController: NSWindowController {
var delegate: MainWindowControllerProtocol?
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
#IBAction func openFile(_ sender: Any) {
print("In here") // this is called?
delegate?.didOpenFile() // but this never is apparently
}
}
Maybe this topic should help.
This method might return nil if the application’s nib file hasn’t
finished loading, if the receiver is not active, or if the application
is hidden.
Have you checked if NSApplication.shared.mainWindow is nil or just NSApplication.shared.mainWindow?.windowController cannot be casted to your controller class ?

How can I pass data from a parent view controller to an embedded view controller in Swift?

I have a view controller embedded in another VC.
I would like to get the value of a variable from the main VC inside the embedded one. Specifically, I would like to change the text of label2 based on the value of label1.
I tried with "prepareForSegue", but it seems it's not triggered for embedded view controllers. I tried to isolate the problem in a test project:
Code for main VC:
class MyViewController: UIViewController {
#IBOutlet weak var label1: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Hello"
}
}
Code for embedded VC:
class EmbeddedVC: UIViewController {
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Thanks for your help :)
A way to achiеve this is to get the child view controller instance in the parent's viewDidLoad. It appears that the parent's viewDidLoad: gets called after the child's viewDidLoad:, which means the label is already created in the child's view.
override func viewDidLoad() {
super.viewDidLoad()
if let childVC = self.childViewControllers.first as? ChildVC {
childVC.someLabel.text = "I'm here. Aye-aye."
}
}
First of all you can't set directly EmbeddedVC's lable2.text In prepareForSegue
because call sequence following below
MainVC's prepareForSeque this time EmbeddedVC's label2 is nil
EmbeddedVC's viewDidLoad called then label2 loaded
MainVC's viewDidLoad called then label1 loaded
so if you assign MainVC's label1.text to EmbeddedVC's label2.text in prepareForSeque
both label1 and label2 are nil so did not work
There are two way to solve this question
First Solution
MainViewController has EmbeddedVC and when MainVC's viewDidLoad called, assign label1.text to embeddedVC.label2.text
class MyViewController: UIViewController {
#IBOutlet weak var label1: UILabel!
var embeddedVC: EmbeddedViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Hello"
embeddedVC?.label2.text = label1.text
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let embeddedVC = segue.destination as? EmbeddedViewController {
self.embeddedVC = embeddedVC
}
}
}
class EmbeddedViewController: UIViewController {
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Second Solution, use protocol and get MainVC's label text when viewWillAppear or viewDidAppear (later viewDidLoad called)
protocol EmbeddedVCDelegate: class {
func labelText() -> String?
}
class MyViewController: UIViewController, EmbeddedVCDelegate {
#IBOutlet weak var label1: UILabel!
// MARK: EmbeddedVCDelegate
func labelText() -> String? {
return label1.text
}
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Hello"
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let embeddedVC = segue.destination as? EmbeddedViewController {
embeddedVC.delegate = self
}
}
}
class EmbeddedViewController: UIViewController {
#IBOutlet weak var label2: UILabel!
weak var delegate: EmbeddedVCDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
label2.text = delegate?.labelText()
}
}
You should try to use prepareForSegue like this:
if segue.identifier == "identifier" {
guard let destinationViewController = segue.destination as? VC2 else { return }
destinationViewController.label2.text = mytext
}
Where the segue identifier you assign in storyboard

How to add a UIView which is created in storyboard as a pop-up in Swift?

I did the following:
1. Dragged UIView to place it in the ViewController ribbon
Created a custom UIView class and added the outlets to the 'Edit Profile View' view fields:
import UIKit
class EditProfileView: UIView {
let globalDataHandler = GlobalDataHandler.sharedInstance
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var userNameTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBAction func saveEditButton(sender: AnyObject) {
}
#IBAction func cancelEditButton(sender: AnyObject) {
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
}
Gave 'EditProfileView' class as the Custom Class for the 'Edit Profile View' view in Storyboard.
Created an object for 'EditProfileView' class in ProfileViewController and added the 'Edit Profile View' view to the main view upon clicking edit button in ProfileViewController.
class ProfileViewController: UIViewController {
let profileView = EditProfileView()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func editProfileButton(sender: AnyObject) {
profileView.firstNameTextField.text = "First Name"
profileView.lastNameTextField.text = "Last Name"
profileView.userNameTextField.text = "User Name"
profileView.emailTextField.text = "Email"
let testFrame : CGRect = CGRectMake(50,100,300,300)
profileView.frame = testFrame
self.view.addSubview(profileView)
}
}
But, the 'Edit Profile View' view doesn't appear on ProfileViewController.
Please help.
You have to link your UIView and your View (should be a distinct UIViewController) in the Xib.
profileView = storyboard.instantiateViewControllerWithIdentifier("ProfileViewController")
You must have an UIPresentationController for your ProfileVC
class ProfilePresentationController : UIPresentationController {
override func frameOfPresentedViewInContainerView() -> CGRect {
return CGRect(x: (presentingViewController.view.frame.width / 2.0) - 150.0, y: (presentingViewController.view.frame.height / 2.0) - 100.0, width: 300.0, height: 200.0)
}
}
Your EditProfileView must implement the following delegate:
UIViewControllerTransitioningDelegate
the following properties of your profileView must also be set to:
profileView.modalPresentationStyle = UIModalPresentationStyle.Custom
profileView.transitioningDelegate = self
After that you can implement the delegate required method
func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController? {
return ProfilePresentationController(presentedViewController: presented, presentingViewController: presenting)
}