I have a UIViewController in which I added a UIView. In that UIView I added some UIImageViews through programming. What I need is that when I click the image it shows in a new UIViewController.
ViewController : UIViewController {
myUIview[[imageview] [ ] [ ] [ ] [ ] ]
}
If I understand correctly you want to segue to another ViewController when your users press on an UIImageView. So here is my solution using an UITapGestureRecognizer (put this code in viewDidLoad):
yourImageView.isUserInteractionEnabled = true
let yourImageTapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.test(_ :)))
yourImageTapGesture.delegate = self
yourImageTapGesture.numberOfTapsRequired = 1
yourImageView.addGestureRecognizer(yourImageTapGesture)
Then in your ViewController you have to make the function test, which is triggered when somebody taps on your UIImageView:
func test(_ sender: AnyObject) {
self.performSegue(withIdentifier: "YourSegueName",sender: self)
}
Important: "YourSegueName" is the Identifier of your Segue in your Storyboard. You can set it by clicking on your Segue:
Keep in my mind that your ViewController needs to inherit from one more class:
class ViewController: UIViewController, UIGestureRecognizerDelegate {...}
Related
I am having a problem accessing my UIButton that's inside a ContainerView from another ViewController.
If the user taps the button a SubView should appear inside of my ViewController. I tried dragging the button in my ViewController file to create an #IBAaction func tapped() but that is not working.
It only works inside of the ContainerView.swift file. But I can not create my Subview there...
I hope you get my problem, I am grateful for every help!
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func addButtonTapped(_ sender: Any) {
print("add Button")
}
You can reach your ViewController inside your ContainerView using its parent property. So, inside your ContainerView class:
if let parentVC = self.parent as? ViewController {
parentVC.showSubView() // your method to show the sub view.
}
You can achieve this using NotificationCenter and Delegates. Here is how you can achieve it with NotificationCenter
In your ContainerViewController you can post notification on button click
#IBAction func yourBtnTap(sender : UIButton) {
NotificationCenter.default.post(name: Notification.Name("myBtnTapped"), object: nil)
}
In your CurrentViewController you have to first register to receive this notification. So in your viewDidLoad, do this:
NotificationCenter.default.addObserver(self, selector: #selector(self.myBtnTappedAction(notification:)), name: Notification.Name("myBtnTapped"), object: nil)
Now in your CurrentViewContoller create myBtnTappedAction function that will be called whenever the button is tapped.
#objc func myBtnTappedAction(notification : Notification) {
// now you can perform all your actions here. this function will be called everytime the button in the container view is tapped.
}
I'm new to IOS and learning the IDE at the moment. I was wondering if its possible to link an imageView, when clicked, to a View Controller
Sure. First, in viewDidLoad of your UIViewController make it tappable:
imageView.isUserInteractionEnabled = true
Then assign the gesture recognizer:
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageTap)))
Once the action is triggered, perform a transition to a new VC:
// Func in your UIViewController
#objc func imageTap() {
// present modally
self.present(YourNewViewController())
// or push to the navigation stack
self.navigationController?.push(YourNewViewController())
// or perform segue if you use storyboards
self.preformSegue(...)
}
Yes. It is possible. You'll need to add a tap gesture recogniser to image view and in the function perform segue.
SWIFT 4
let singleTap = UITapGestureRecognizer(target: self,action:Selector(“imageTapped”))
yourImageView.isUserInteractionEnabled = true
yourImageView.addGestureRecognizer(singleTap)
Function to handle Tap:
#objc func imageTapped() {
performSegue(withIdentifier: "yourNextScreen", sender: "")
}
Yes. You can bind a tap gesture recognizer to your imageview. You can follow this link here on a previous answer on how to do it programmatically
You could do it completely in the interface builder by putting a UIButton, with a transparent background and no text, over the ImageView and then control drag the button to the viewcontroller you want to trigger a segue on touch.
Of course it is. You should add a UITapGestureRecognizer to the UIImageView and add a selector to trigger the pushing a new viewcontroller method.
For example;
#IBOutlet weak var imageView: UIImageView! {
didSet {
let imageTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
imageView.addGestureRecognizer(imageTapGestureRecognizer)
imageView.isUserInteractionEnabled = true
}
}
func imageTapped() {
//navigate to another view controller
}
add gesture and if you want to animate it then see this pod
In my project I have UINavigationController with three embedded UIViewControllers. On the first one I add balanceLabel and refreshButton to navigation bar. When click on button first view controller send url request and show return value on label.
#IBAction func refreshButtonAction(_ sender: UIBarButtonItem) {
let operation = GetInfoOperation(...)
operation.completionBlock = { [weak self] in
DispatchQueue.main.async {
guard let balance = operation.output?.value?.balance else { return }
self?.balanceLabel.text = balance
let significantDigits = Int(Double(balance.toInt64!) * pow(10, -10))
}
}
queue.addOperation(operation)
}
How can I get the same behaviour on other ViewControllers without duplicate #IBAction func refreshButtonAction(_ sender: UIBarButtonItem) in each ViewController?
you can archive this by extension, using inheritance,
create the view controller you want with all the common feature you want and then instead of inheriting directly from UIViewController inherit from that base viewController
your base controller BaseViewController
class BaseViewController: UIViewController {
//all comman functionallity
//add your button here
}
class ChildOneViewController: BaseViewController {
//this class will get all the functionality from BaseViewController
//you can access the BaseViewController button here
//add function for ChildOneViewController
}
class ChildtwoViewController: BaseViewController {
//this class will get all the functionality from BaseViewController
//you can access the BaseViewController button here
//add function for ChildtwoViewController
}
App has two View Controllers: ViewController (this is the main View Controller that displays the majority of the app's content) and SecondViewController (accessible via a UIButton on ViewController; SecondViewController is only used to display a user's inventory, and a UIButton within SecondViewController allows the user to return to the original view, ViewController). Currently, the app uses the "Show" action segue to switch between View Controllers when the user presses the appropriate UIButton. However, after switching from ViewController to SecondViewController, and then pressing the UIButton to return to ViewController, the properties of ViewController have been reverted to the properties that occur when the app launches (background color is changed, certain text fields appear that shouldn't).
So, how do I "save the state" of ViewController when the user moves to SecondViewController, so that the user resumes where they left off when they return to ViewController?
What you are looking for is an unwind segue. Here's the simplest way of how to create it:
In your ViewController (or, basically any other view controller you are willing to pop to) create an IBAction that accepts an instance of a segue (function name doesn't really matter):
#IBAction func unwindToThisVC(segue: UIStoryboardSegue) { }
In the storyboard, go to SecondViewController, and control + drag from your UIButton to the Exit outlet of ViewController and then select the IBAction you've created in step 1:
More on Unwind Segues
The way you are doing it now (using Show from the second to get back to the first) actually brings up a third VC.
What you want to do is dismiss the second view controller.
The normal way is to implement a protocol for the second one that the first one implements and then to have a function in that protocol for the second one to let the first one know it is done.
When the function is called, the first one dismisses the second and then it will be shown again with its state intact.
Here is a simple example of segue and unwind that you can adapt to your problem... Assume that you have ViewController with label and a button and a SecondViewController with label and a button.
For the first ViewController...
import UIKit
//steps to receive data back from SecondViewController...
//1. create protocol in the SecondViewController (see SecondViewController code)
//2. conform to the protocol
class ViewController: UIViewController, UnwindSegue {
//3. method that gets triggred.
func dataReceived(dataSegued: String) {
labelOne.text = dataSegued
}
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var labelOne: UILabel!
var textReceived : String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btPressed(_ sender: Any) {
performSegue(withIdentifier: "goToSecondController", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSecondController" {
let destinationVC = segue.destination as! SecondViewController
destinationVC.textSegued = textField.text!
//4. create delegate in the SecondViewController (see SecondViewController code)
//5. set ourselves up as delegate of SecondViewController
destinationVC.delegate = self
//6. then dismiss the SecondViewController (see SecondViewController code)
}
}
}
Then for your SecondViewController...
import UIKit
//1. create protocols and delegates to transfer data back
protocol UnwindSegue {
//single required method with a single parameter
func dataReceived(data:String)
}
class SecondViewController: UIViewController {
var textSegued : String?
//4. create delegate of the protocol of type CanReceive that can be a nil. If it is nil, it doesn't go anywhere when BT is pressed
var delegate : UnwindSegue?
#IBOutlet weak var label: UILabel!
#IBOutlet weak var secondTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
label.text = textSegued
}
#IBAction func btTwoPressed(_ sender: Any) {
//this is not triggered if var delegate is nil (as defined as optional)
delegate?.dataReceived(data: secondTextField.text!)
//6. dismiss the 2nd VC so you can see the fist VC
dismiss(animated: true, completion: nil)
}
}
I have an UIView class that contains a UILabel. I have added a UITapGestureRecognizer for the UILabel and want to do a performSegue to open a new UIViewController on tap of the UILabel.
The problem is that I can't use performSegue in UIView class.
Can anyone please help to use performSegue in UIView class?
I have added a tap gesture to my label as,
nameLabel.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(tapFunction))
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
tap.isEnabled = true
nameLabel.addGestureRecognizer(tap)
Now in my tapFunction,
func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
self.performSegue(withIdentifier: "memberSegue", sender: self)
}
But I get an error:
"Value of type UIViewController has no member performSegue"
as it is an UIView Class.
You should try and separate any functionality from your UIViews. A best practice is your UIViewControllers to be responsible for any functionality in your app and your UIViews to be used only for displaying elements. Thus I would suggest that you make your nameLabel a property in your UIView, so that you can access it from your UIViewController after instantiating the UIView. Then the code in your UIViewController should look like this:
let yourView = new YourView()
let tap = UITapGestureRecognizer(target: self, action: #selector(tapFunction))
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
tap.isEnabled = true
yourView.nameLabel.addGestureRecognizer(tap)
and you would have your tap() function in your UIViewController.
you can do it by protocol and delegate. Because actually you can not do it from UIView you should always do it from controller.
/// add this protocol in your project
protocol ViewProtocol {
func performSegueFromView()
}
class View : UIView {
/// add this line to your view
var delegate : ViewProtocol?
/// replace your tap function with this
func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
self.delegate?.performSegueFromView()
}
}
class ViewController : UIViewController, ViewProtocol {
override func viewDidLoad() {
/// create view
let view = View()
/// assign view delegate
view.delegate = self
}
/// delegate function
func performSegueFromView() {
///peform segue from controller because you can not do this from uiview anyway
self.performSegue(withIdentifier: "memberSegue", sender: self)
}
}
Make delegate in UIView Class and used to where you are using UIView in YourController class
protocol UIViewDelegate {
func tapFunction() //this function will be use in controller class which uiview are using
}
var delegate: UIViewDelegate?
func tapFunction(sender:UITapGestureRecognizer) {
delegate?.tapFunction()
}
class YourController: UIViewController, UIViewDelegate {
let yourView = YourView()
yourView.delegate = self
func tapFunction() {
self.performSegue(withIdentifier: "memberSegue", sender: self)
}
}
I would suggest you to add action for that tap gesture instead of segue.
TapRecognizer.addTarget(self, action: #selector(YourFunc))
Samle Func:
func YourFunc(){
let storyBoardHome = UIStoryboard(name: "", bundle: nil)
let memberController = storyBoardHome.instantiateViewController(withIdentifier: "")
self.navigationController?.pushViewController(memberController, animated: true)
}
Refer This : https://stackoverflow.com/a/26366366/6818278
the error you wrote is wrong, UIViewController's do have that method. Your error must be "UIVIew has no member...", as for the solution you just need to get a reference to whatever UIViewController is using this specific view.
Then use that reference to call your perform method.
For example, if your custom View is being added programmatically, you can add an extra property to your class like
weak var myVC : UIViewController?
then after instantiating it just assign it to this property.
Then the perform segue becomes:
myVC?.performSegue....
Alternatively you can just add the tap gesture recognizer from the UIViewController that is using this view, then have the view show it from there.
Or you could just use:
UIApplication.shared.keyWindow?.rootViewController.performSegue...
But if you do, you should be careful as this one might have unintended consequences depending on what you are presenting and which is the current rootViewController.