I want to pass movies's data to another controller also pass another controller when progress is finished.Can I do this with one segue ?
class LoadingScreenViewController: UIViewController {
var movies = [Movie]()
#IBOutlet weak var progress: UIProgressView!
#IBOutlet weak var countLabel: UILabel!
override func viewDidLoad()
{
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(LoadingScreenViewController.updateProgress), userInfo: nil, repeats: true)
progress.setProgress(0, animated: true)
}
func updateProgress () {
if progress.progress != 1 {
self.progress.progress += 2 / 10
} else {
UIView.animateWithDuration(0.4, animations: { () -> Void in
})
performSegueWithIdentifier("segue", sender:self)
progress.hidden = true
self.countLabel.hidden = true
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let controller : SearchViewController = segue.destinationViewController as! SearchViewController
if segue.identifier == "segue"{
controller.model = movies
}
}
}
Do following:-
extension UIViewController {
func addSearchController() {
let searchController = UISearchController(searchResultsController: nil)
self.view.addSubview(searchController.searchBar)
}
}
Just call self.addSearchController() method in viewDidLoad method of required VC. No need to pass SearchController.
Related
I have stetted up switch in my First View Controller and assigned the following action to it :-
class ThirdViewController: UIViewController {
#IBOutlet weak var Image: UIImageView!
#IBOutlet weak var playerNum1Button: UIButton!
#IBOutlet weak var toggleSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
self.toggleSwitch.setOn(UserDefaults.standard.bool(forKey: "toggleState"), animated: true)
}
#IBAction func numPlayers1(_ sender: Any) {
performSegue(withIdentifier: "3to8segue", sender: self)
}
IBAction func toggleSwitch(_ sender: UISwitch) {
if (toggleSwitch.isOn == true) {
Image.image = UIImage(named: "Night")
}
else {
Image.image = UIImage(named: "background")
}
UserDefaults.standard.set(sender.isOn, forKey: "toggleState")
}
It is Able to change the image in the First View Controller. But, how can I get that switch to change the image in 2nd View controller as well when it is turned on? Thanks for the help!
Using Notification Center
Example:
In FirstViewController:
#IBAction func onPressButton(_ sender: UIButton) {
UserDefaults.standard.set(sender.isSelected, forKey: "pressedButton")
NotificationCenter.default.post(name: "changeImageBackground", object: nil)
}
In SecondViewController:
NotificationCenter.default.addObserver(target: self, selector: #selector(didChangeImageBackground), name: "changeImageBackground", object: nil)
#objc func didChangeImageBackground() {
let changed = UserDefaults.standard.bool(forKey: "pressedButton")
if changed {
// image when pressed
} else {
// image when haven't pressed
}
}
I am making an app following the same design approach of this app https://github.com/Bailig/SurveyApp .
In the above GitHub project the controllers are designed in such a way like a common ViewController with ContainerView inside.And also this common ViewController is Embed Segue with the First Controller or very first page. The container view is getting replaced for all the next screens.
In the above project there is a thank you page in the last, in my app I placed a button on the thank you page. I want to open the very first page again on click of the button from thank you page. How can I do that from last page controller/FourthController?
ViewController
class ViewController: UIViewController {
var currentController: UIViewController?
var pageIndex = 1
var survey = Survey()
#IBOutlet weak var backButton: UIButton!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var progressLabel: UILabel!
#IBAction func nextTapped(_ sender: Any) {
switch pageIndex {
case 1:
let nextController = storyboard?.instantiateViewController(withIdentifier: "SecondController")
if let fromController = currentController, let toController = nextController as? SecondController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex += 1
setButtonAndProgressLabel()
}
case 2:
let nextController = storyboard?.instantiateViewController(withIdentifier: "ThirdController")
if let fromController = currentController, let toController = nextController as? ThirdController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex += 1
setButtonAndProgressLabel()
}
case 3:
let nextController = storyboard?.instantiateViewController(withIdentifier: "FourthController")
if let fromController = currentController, let toController = nextController as? FourthController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex += 1
setButtonAndProgressLabel()
}
default:
break
}
}
#IBAction func backTapped(_ sender: Any) {
switch pageIndex {
case 2:
let nextController = storyboard?.instantiateViewController(withIdentifier: "FirstController")
if let fromController = currentController, let toController = nextController as? FirstController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex -= 1
setButtonAndProgressLabel()
}
case 3:
let nextController = storyboard?.instantiateViewController(withIdentifier: "SecondController")
if let fromController = currentController, let toController = nextController as? SecondController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex -= 1
setButtonAndProgressLabel()
}
default:
break
}
}
#IBOutlet weak var backTapped: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
currentController = segue.destination
if let firstController = currentController as? FirstController {
firstController.survey = survey
}
setButtonAndProgressLabel()
}
func moveAndSizeChildControllers(fromController: UIViewController, toController: UIViewController) {
fromController.willMove(toParentViewController: nil)
toController.view.frame = containerView.bounds
addChildViewController(toController)
containerView.addSubview(toController.view)
// animatin
toController.view.alpha = 0
UIView.animate(withDuration: 0.5, animations: {
toController.view.alpha = 1
fromController.view.alpha = 0
}) { (completed) in
fromController.view.removeFromSuperview()
fromController.removeFromParentViewController()
toController.didMove(toParentViewController: self)
self.currentController = toController
}
}
}
You can manage it by using Notification
Add in ViewController (main)
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(navigateToFirstPage), name:NSNotification.Name(rawValue:"NavigateToFirstPage") , object: nil)
}
#objc private func navigateToFirstPage() {
pageIndex = 2
self.backTapped(UIButton())
}
Add in you fourthViewController
// This is your button from where you need to perform action
#IBAction func thanksButtonAction(_ sender: Any) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue:"NavigateToFirstPage"), object: nil)
}
I would better use delegation pattern. It's simple to manage and easily to understand.
On the top of FourthController after imports you need to add
protocol FourthControllerThankDelegate {
func didTapYourButton()
}
and then add the variable inside that class
class FourthController: UIViewController {
weak var delegate: FourthControllerThankDelegate?
...
}
then you need to call didTapYourButton() inside your button action handler
#IBAction func thanksButtonTapped(_ sender: Any) {
delegate?.didTapYourButton()
}
then inside your ViewController function nextTapped: you need to set this view controller as a delegate to FourthController
case 3:
... // I have skipped code above
toController.delegate = self
setButtonAndProgressLabel()
}
and finally you need to handle delegate action
extension ViewController: FourthControllerThankDelegate {
func didTapYoutButton {
pageIndex = 2
backTapped(self)
}
}
As you do that, backTapped handler will move you to first page. This is not the best way to move back. To improve that you can create a function "displayMeFirstPage" and move there part of the logic from backTapped() case: 2 and call it inside that case and inside delegate handler. There are a lot of ways to improve navigation. if you have any questions please let me know.
I'm going to include my full code in this but I will try to give pointers to where the relevant bits are. Basically I am returning to a view controller from an Unwind Segue with some new data. I am using that data successfully in the 'NBARotoHome' VC but I additionally need to pass some of that data through an embedded Nav controller to 'NBARotoTabPager' vc.
I am trying to do this using the 'UpdateChildView' delegate (at the top of the first block of code) and calling its method in 'loadViewData() (in the 'if statement' near the bottom of the first block).
protocol UpdateChildView : class {
func updateView()
func test()
var playerSelected: Player? { get set }
}
class RotoViewRoundCell: UITableViewCell{
#IBOutlet weak var categoryLabel: UILabel!
}
class RotoViewRoundHeader: UITableViewCell{
}
class NBARotoHome: UIViewController{
#IBOutlet weak var posPaidLabel: UILabel!
#IBOutlet weak var progressIndicator: UIProgressView!
#IBOutlet weak var vsLabel: UILabel!
#IBOutlet weak var fantasyFundsAmountLabel: UILabel!
#IBOutlet weak var fantasyFundsLabel: UILabel!
#IBOutlet weak var playerName: UILabel!
#IBOutlet weak var roundIndicator: UILabel!
var selectedPlayer: Player!
var firstNavController: UINavigationController!
weak var updateChildView : UpdateChildView?
override func viewDidLoad() {
super.viewDidLoad()
loadViewData()
firstNavController = self.navigationController
let rightBarButton = UIBarButtonItem(title: "Select", style: UIBarButtonItemStyle.plain, target: self, action: #selector(myRightSideBarButtonItemTapped(_:)))
self.navigationItem.rightBarButtonItem = rightBarButton
self.title = "NBA Roto"
}
func myRightSideBarButtonItemTapped(_ sender:UIBarButtonItem!){
performSegue(withIdentifier: "ShowDraft", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowDraft" {
let navVC = segue.destination as? UINavigationController
let nbaDraftList = navVC?.viewControllers.first as! NBADraftList
nbaDraftList.mainNavController = firstNavController
}
if (segue.identifier == "buyNavControllerChild"){
// let navVC = segue.destination as? UINavigationController
// let buyVC = navVC?.viewControllers.first as! NBARotoTabPager
// buyVC.delegate = self
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
#IBAction func prepareForUnwind(segue: UIStoryboardSegue) {
}
func loadViewData(){
if((selectedPlayer) != nil){
roundIndicator.text = "Upcoming: " + selectedPlayer.game_time
playerName.text = selectedPlayer.Name
vsLabel.text = selectedPlayer.visiting + " # " + selectedPlayer.home
fantasyFundsLabel.text = ""
fantasyFundsAmountLabel.text = ""
updateChildView?.test()
// updateChildView?.playerSelected = selectedPlayer
// updateChildView?.updateView()
}else{
roundIndicator.text = "Select a Player"
playerName.text = "No Player Selected"
vsLabel.text = "--"
fantasyFundsLabel.text = "Fantasy Funds"
fantasyFundsAmountLabel.text = "$10,000"
}
}
}
Because I haven't been able to get the delegate to work, I have been playing around with setting its delegate property in the above 'prepare' method -'buyVC.delegate = self' - but I'm getting 'buyVC has no member delegate' so that has been a dead end.
The next bit of code is the NBARotoTabPager vc which is embedded in the navigation controller. For reasons I'm no longer sure about I decided to make it a subclass of NBARotoHome, but its basically a custom tab pager that uses a segmented control to switch between two additional vcs.
The most important step at this point is just getting the 'test' function to work (which just prints 'test'. Its implemented in the below block of code second from the bottom above updateView).
class NBARotoTabPager: NBARotoHome, UpdateChildView{
#IBOutlet weak var segmentedControl: UISegmentedControl!
#IBOutlet weak var scoreKey: UIBarButtonItem!
#IBOutlet weak var standings: UIBarButtonItem!
var playerSelected: Player?
override func viewDidLoad() {
navigationController?.navigationBar.barTintColor = UIColor(red: 27/255, green: 27/255, blue: 27/255, alpha: 1)
scoreKey.setTitleTextAttributes([NSFontAttributeName: UIFont(name: "Helvetica", size: 13.0)!], for: UIControlState.normal)
scoreKey.tintColor = UIColor.blue
standings.setTitleTextAttributes([NSFontAttributeName: UIFont(name: "Helvetica", size: 13.0)!], for: UIControlState.normal)
standings.tintColor = UIColor.blue
setupView()
}
private func setupView() {
setupSegmentedControl()
updateView()
}
private func setupSegmentedControl() {
// Configure Segmented Control
segmentedControl.removeAllSegments()
segmentedControl.insertSegment(withTitle: "Live", at: 0, animated: false)
segmentedControl.insertSegment(withTitle: "Avg / +", at: 1, animated: false)
segmentedControl.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged)
segmentedControl.selectedSegmentIndex = 0
}
func selectionDidChange(_ sender: UISegmentedControl) {
updateView()
}
private lazy var viewLiveTab: NBARotoLive = {
// Load Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "NBARotoLive") as! NBARotoLive
if((self.playerSelected) != nil){
viewController.selectedPlayer = self.playerSelected
}
// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
private lazy var viewAvgsTab: NBARotoAvgs = {
// Load Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "NBARotoAvgs") as! NBARotoAvgs
if((self.playerSelected) != nil){
viewController.selectedPlayer = self.playerSelected
}
// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
}()
private func add(asChildViewController viewController: UIViewController) {
// Add Child View Controller
addChildViewController(viewController)
// Add Child View as Subview
view.addSubview(viewController.view)
// Configure Child View
viewController.view.frame = view.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Notify Child View Controller
viewController.didMove(toParentViewController: self)
}
private func remove(asChildViewController viewController: UIViewController) {
// Notify Child View Controller
viewController.willMove(toParentViewController: nil)
// Remove Child View From Superview
viewController.view.removeFromSuperview()
// Notify Child View Controller
viewController.removeFromParentViewController()
}
internal func test(){
print("test")
}
internal func updateView() {
if segmentedControl.selectedSegmentIndex == 0 {
let position = viewAvgsTab.tableView.contentOffset.y;
viewLiveTab.tableView.contentOffset = CGPoint(x:0, y:position);
remove(asChildViewController: viewAvgsTab)
add(asChildViewController: viewLiveTab)
} else {
let position = viewLiveTab.tableView.contentOffset.y;
viewAvgsTab.tableView.contentOffset = CGPoint(x:0, y:position);
remove(asChildViewController: viewLiveTab)
add(asChildViewController: viewAvgsTab)
}
}
}
I've looked at a lot of examples but I don't understand the whole 'setting the delegate' thing i.e. theSecondViewController.delegate = self. Sometimes I see examples where you don't need to do this. And other times it seems like my VCs don't even have a delegate property. So I'm not sure if that's my specific problem or not but any direction would be greatly appreciated. Thanks
There are three steps to implement a delegate.
create a protocol.. (you've already done this by creating a updateChildView protocol)
you need to implement this protocol in the class you wish to receive and process this data.. (you've not done this step and thats why you cant set buyVC.delegate = self)
you need to add a property in ViewController2 called "delegate" and make it as a type of your protocol in step 1 (you've not done this step and there is no property called "delegate" in vc2 .. that's why you get this error 'buyVC has no member delegate')
Here's a quick example:
Protocol:
protocol UpdateChildView{ //removed :class
func updateView()
func test()
var playerSelected: Player? { get set }
}
Viewcontroller A:
class NBARotoHome: UIViewController, UpdateChildView { //added conformance to the protocol
//add the methods for conforming to protocol and add your implementation
func updateView() {
//add your implementation
}
func test(){
//add your implementation
}
var playerSelected: Player? {
//add your implementation
}
prepare(for: Segue) {
/** code for passing data **/
let navVC = segue.destination as? UINavigationController
let buyVC = navVC?.viewControllers.first as! NBARotoTabPager
buyVC.delegate = self
//sets the delegate in the new viewcontroller
//remember.. delegate is a property in the next vc
// and the property only accepts any viewcontroller that is implements updatechildview protocol
present(vc2)
}
}
viewcontroller2 :
class viewControllerB: UIViewController {
var delegate: UpdateChildView? //add this
viewdidload {
delegate?.test() //call the func in the previous vc
}
}
I am making a game that when a button is pressed twice, it will transfer to another view controller. Right now the users reaction time is timed in view controller a. I would like the time to be segued to view controller b and when in view controller b the time be subtracted by 1. Right now the time is not being segued. When the button is pressed twice the view controller changes but the text is not being transferred.
import UIKit
class ViewController: UIViewController {
#IBOutlet var labelx: UILabel!
#IBOutlet var startx: UIButton!
#IBOutlet var pressSoccerBall: UIButton!
var level = 0
var timer: Timer?
var isRunning: Bool {
get {
return timer != nil
}
}
var counter = 0.0
override func viewDidLoad() {
super.viewDidLoad()
labelx.text = String(format: "%.1f", counter)
startx.isEnabled = true
}
#IBAction func startTimer(_ sender: Any) {
if isRunning {
return
}
refreshTimer()
}
#IBAction func PressSoccerBall(_ sender: Any) {
level += 1
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController : winViewController = segue.destination as! winViewController
DestViewController.LebelText = labelx.text!
}
func refreshTimer() {
if let timer: Timer = timer {
timer.invalidate()
}
timer = Timer.scheduledTimer(timeInterval: 0.1,target: self,selector: #selector(updateTimer),userInfo: nil, repeats: true)
startx.isEnabled = false
}
func updateTimer() {
counter += 0.1
labelx.text = String(format: "%.1f", counter)
if counter < 9.9 && level == 2 {
let nextc = self.storyboard?.instantiateViewController(withIdentifier: "winViewController") as? winViewController
self.present(nextc!, animated: true, completion: nil)
}
}
}
VIEW CONTROLLER B
import UIKit
class winViewController: UIViewController {
#IBOutlet var winningLabel: UILabel!
public var LebelText: String?
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
guard let unwrapedText = self.LebelText else {
return
}
if let myInt = Double(unwrapedText){
let myInt = myInt - 1
self.winningLabel.text = String(myInt)
} else {
return
}
}
}
You're not using segues. You are creating the winViewController and then calling present to show it. So, prepareForSegue will never be called.
Simply set the LebelText property on nextc before presenting it:
func updateTimer() {
counter += 0.1
labelx.text = String(format: "%.1f", counter)
if counter < 9.9 && level == 2 {
if let nextc = self.storyboard?.instantiateViewController(withIdentifier: "winViewController") as? winViewController {
nextc.LebelText = labelx.text
self.present(nextc, animated: true, completion: nil)
}
}
}
In my current project i have detail view that shows a specific record from my table view. I have the following labels
#IBOutlet weak var vacationImageView: UIImageView!
#IBOutlet weak var percentSaved: UILabel!
#IBOutlet weak var cost: UILabel!
#IBOutlet weak var saved: UILabel!
#IBOutlet weak var circleProgressView: CircularProgressView!
#IBOutlet weak var daysDepart: UILabel!
I call a popover that I want to send the current text value of saved to my popup, allow the user to edit it and send it back to the view. Here is my popover call.
#IBAction func addPopover(sender: UIView) {
let savingsInformationViewController = storyboard?.instantiateViewControllerWithIdentifier("SavingsAddPopover") as UIViewController
savingsInformationViewController.modalPresentationStyle = .Popover
savingsInformationViewController.preferredContentSize = CGSizeMake(200, 200)
let popoverController = savingsInformationViewController.popoverPresentationController
popoverController?.sourceView = sender
popoverController?.permittedArrowDirections = .Any
popoverController?.delegate = self
presentViewController(savingsInformationViewController, animated: true, completion: nil)
}
I would have thought I could reference the data object from the popover but can't..at least not the way I'm thinking.
class ViewController: UIViewController,SavingViewControllerDelegate,UIPopoverPresentationControllerDelegate{
#IBOutlet var labelText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func buttonPopOverClick(sender: UIButton)
{
let savingsInformationViewController = storyboard?.instantiateViewControllerWithIdentifier("SavingsAddPopoverVC") as SavingViewController
savingsInformationViewController.delegate = self
savingsInformationViewController.strSaveText=labelText.text
savingsInformationViewController.modalPresentationStyle = .Popover
if let popoverController = savingsInformationViewController.popoverPresentationController {
popoverController.sourceView = sender
popoverController.sourceRect = sender.bounds
popoverController.permittedArrowDirections = .Any
popoverController.delegate = self
}
presentViewController(savingsInformationViewController, animated: true, completion: nil)
}
func saveText(strText: NSString) {
labelText.text=strText
}
// MARK: - UIPopoverPresentationControllerDelegate
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle {
return .FullScreen
}
func presentationController(controller: UIPresentationController!, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController! {
return UINavigationController(rootViewController: controller.presentedViewController)
}
}
protocol SavingViewControllerDelegate
{
func saveText(var strText : NSString)
}
class SavingViewController: UIViewController {
#IBOutlet var textField: UITextField!
var delegate : SavingViewControllerDelegate?
var strSaveText : NSString!
override func viewDidLoad() {
super.viewDidLoad()
textField.text = strSaveText
// Do any additional setup after loading the view.
}
#IBAction func buttonDone(sender: UIButton)
{
if (self.delegate) != nil
{
delegate?.saveText(textField.text)
self.dismissViewControllerAnimated(true, nil)
}
}
}
just to point out
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle {
return .none
}
not woking properly on ios 12 /xcode 11, at least for popover tableview controller
The call below works
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}