Good Day,
I want to create a custom alert for gather information from the user. However, it will not load and crashes with the following code:
xib file
import Foundation
import UIKit
class WorkoutAlert: UIView {
static let instance = WorkoutAlert()
#IBOutlet var parentView: UIView!
#IBOutlet weak var alertView: UIView!
#IBOutlet weak var titleLabel: UILabel!
#IBAction func workoutTextField(_ sender: UITextField) {
}
#IBAction func datePicker(_ sender: UIDatePicker) {
}
#IBAction func cancelButtonPressed(_ sender: UIButton) {
parentView.removeFromSuperview()
}
#IBAction func doneButtonPressed(_ sender: UIButton) {
}
override init(frame: CGRect) {
super.init(frame: frame)
Bundle.main.loadNibNamed("WorkoutAlert", owner: self, options: nil)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func commonInit () {
alertView.layer.cornerRadius = 10
parentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
parentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
func showAlert(title: String) {
self.titleLabel.text = title
UIApplication.shared.keyWindow?.addSubview(parentView)
}
// MARK: - End of Code
}
Relevant code for the ViewController using the xib:
class WorkoutViewController: UIViewController {
#IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
WorkoutAlert.instance.showAlert(title: "Add a new workout")
}
}
Constraints for the xib
Any assistance is greatly appreciated. I'm a novice and have found many ways and examples for creating alerts instead of using the standard alert controller.
You need to implement init methods according to your needs. But better to implement boths and you don't need singleton pattern here
class WorkoutAlert: UIView {
#IBOutlet var parentView: UIView!
#IBOutlet weak var alertView: UIView!
#IBOutlet weak var titleLabel: UILabel!
#IBAction func workoutTextField(_ sender: UITextField) {
}
#IBAction func datePicker(_ sender: UIDatePicker) {
}
#IBAction func cancelButtonPressed(_ sender: UIButton) {
parentView.removeFromSuperview()
}
#IBAction func doneButtonPressed(_ sender: UIButton) {
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
public override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
private func commonInit () {
Bundle.main.loadNibNamed("WorkoutAlert", owner: self, options: nil)
alertView.layer.cornerRadius = 10
parentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
parentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
func showAlert(title: String) {
self.titleLabel.text = title
UIApplication.shared.keyWindow?.addSubview(self)
}
// MARK: - End of Code
}
In your controller
class WorkoutViewController: UIViewController {
#IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
let alert = WorkoutAlert(frame: self.view.bounds) // or can set frame here WorkoutAlert(frame: frame here)
alert.showAlert(title: "Add a new workout")
}
}
Related
I have some issues with my customs alertView when tried to compile it it will give me the following errors
Value of type 'CastingPromptViewDelegate' has no member
'removeFromSuperview' Argument type 'CastingPromptView' does not
conform to expected type 'CastingPromptViewDelegate'
on my watchVC I have this
private lazy var castingPromptView: CastingPromptView = {
let view = CastingPromptView.instanceFromNib(castDeviceName: "test", imageURLString: "https://dsfsdf.jpg")
view.translatesAutoresizingMaskIntoConstraints = false
view.delegate = self
return view
}()
//cast CastingPromptView
class CastingPromptView: UIView{
// MARK: - IBOutlets
#IBOutlet weak var castTODeviceLabel: UILabel!
#IBOutlet weak var videoImage: URLImageView?
#IBOutlet weak var playCastingButton: UIButton!
#IBOutlet weak var stopCastingButton: UIButton!
#IBOutlet weak var cancelButton: UIButton!
// MARK: - Properties
public var delegate: CastingPromptViewDelegate?
class func instanceFromNib(castDeviceName:String,imageURLString:String) -> CastingPromptView {
let view = UINib(nibName: "CastingPromptView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! CastingPromptView
view.castTODeviceLabel.text = castDeviceName
view.setupView()
return view
}
override init(frame: CGRect) {
super.init(frame: frame)
}
//initWithCode to init view from xib or storyboard
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
private func setupView() {
self.backgroundColor = .white
self.layer.borderColor = UIColor(red: 0.98, green: 0.98, blue: 0.98, alpha: 1.00).cgColor
self.layer.borderWidth = 1
self.layer.cornerRadius = 12
}
#IBAction func dismissView(_ sender: Any) {
self.delegate?.dismissAlert(sender: self) ->> conform to expected type 'CastingPromptViewDelegate'
}
#IBAction func stopCasting(_ sender: Any) {
}
#IBAction func playCasting(_ sender: Any) {
}
}
// MARK: - Delegate
protocol CastingPromptViewDelegate {
func dismissAlert(sender: CastingPromptViewDelegate)
}
extension WatchVC:CastingPromptViewDelegate {
func dismissAlert(sender: CastingPromptViewDelegate) {
sender.removeFromSuperview() -->Value of type 'CastingPromptViewDelegate' has no member 'removeFromSuperview'
self.backgroundView.removeFromSuperview()
}
Try this out:
protocol CastingPromptViewDelegate {
func dismissAlert(sender: CastingPromptView) // instead of CastingPromptViewDelegate
}
Then your extension will be:
extension WatchVC:CastingPromptViewDelegate {
func dismissAlert(sender: CastingPromptView) {
sender.removeFromSuperview()
self.backgroundView.removeFromSuperview()
}
}
I am trying to create a verification process in 4 steps, in order to make my code more efficient, I decided to use Child views and just update the UI accordingly.
I managed to add my child view to my MasterView, however, I am unable to click the button inside my child view.
I already checked the view hierarchy and there is nothing on top of my button. I also tried to add the action programmatically, re-added the button but I can't make it work. I am new to swift development so probably I am missing something.
Child view Code
protocol IdentityVerificationIntroChildViewControllerDelegate{
func startVIProcess(_ sender: Any)
}
class IdentityVerificationIntroChildViewController: UIView{
#IBOutlet var contentView: UIView!
var delegate: IdentityVerificationIntroChildViewControllerDelegate?
#IBOutlet weak var mStartVIBtn: UIButton!
override init(frame: CGRect){
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
Bundle.main.loadNibNamed("IdentityVerificationIntroChildView", owner: self, options: nil)
mStartVIBtn.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
#objc func buttonAction(sender: UIButton!) {
print("works")
}
}
Master view code
final class MasterIdentityVerificationViewController: UIViewController {
#IBOutlet weak var mContainerView: UIView!
#IBOutlet weak var mStepIndicator: StepIndicatorView!
private var currentView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
setChildView(subView: IdentityVerificationIntroChildViewController())
}
private func setChildView(subView: UIView){
currentView?.removeFromSuperview()
currentView = subView
currentView?.translatesAutoresizingMaskIntoConstraints = false
guard let currentView = currentView else { return }
mContainerView.addSubview(currentView)
NSLayoutConstraint.activate([
currentView.topAnchor.constraint(equalTo: mContainerView.topAnchor),
currentView.trailingAnchor.constraint(equalTo: mContainerView.trailingAnchor),
currentView.leadingAnchor.constraint(equalTo: mContainerView.leadingAnchor),
currentView.bottomAnchor.constraint(equalTo: mContainerView.bottomAnchor)
])
}
}
extension MasterIdentityVerificationViewController: IdentityVerificationIntroChildViewControllerDelegate{
func startVIProcess(_ sender: Any) {
performSegue(withIdentifier: "fromVIIntroToVIIDCapture", sender: sender)
print("adfsdfs")
}
}
View Hierarchy, the problematic button is Highlighted
Green Area is where Child views are getting switched
I would really appreciate any help. Thanks
I have created a custom view xib and give that view class. Now I take a view in main vc and give that class but now I want to access custom view button action method in my main vc. So how can I do that?
Here is my custom view
import UIKit
class TextCustomisationVC: UIView {
#IBOutlet var contentView: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit(){
Bundle.main.loadNibNamed("TextCustomisationVC", owner: self, options: nil)
addSubview(contentView)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
#IBAction func btnCloseCustomisation_Click(_ sender: Any) {
}
#IBAction func btnApplyCustomisation_Click(_ sender: Any) {
}
}
Now I create an outlet in my main VC and give that same class I can access those class outlets but now I want to access above button action method So how can I do that?
You can use delegate here which you can implement in the main VC.
create a protocol like this:
protocol ButtonActionDelegate {
func closeButtonPressed(_ sender:UIButton)
func applyButtonPressed(_ sender:UIButton)
}
Then create instance of the delegate in your view like this:
var delegate:ButtonActionDelegate?
Implement this delegate in the main VC like this:
extension mainVC : ButtonActionDelegate {
func closeButtonPressed(_ sender: UIButton) {
}
func applyButtonPressed(_ sender: UIButton) {
}
}
Then you can call the delegate methods respectively like this:
#IBAction func btnCloseCustomisation_Click(_ sender: Any) {
self.delegate?.closeButtonPressed(sender)
}
#IBAction func btnApplyCustomisation_Click(_ sender: Any) {
self.delegate?.applyButtonPressed(sender)
}
You can try
let cusView = TextCustomisationVC(frame:///)
if btn sender is used inside function
cusView.btnCloseCustomisation_Click(cusView.closeBtn)
otherwise send any dummy button
cusView.btnCloseCustomisation_Click(UIButton())
Edit:
protocol CustomTeller {
func closeClicked(UIButton)
}
class TextCustomisationVC: UIView {
var delegate: CustomTeller?
#IBAction func btnCloseCustomisation_Click(_ sender: UIButton) {
self.delegate?.closeClicked(sender:sender)
}
}
// in mainVC
let cusView = TextCustomisationVC(frame:///)
cusView.delegate = self
and implement
func closeClicked(sender:UIButton) {
// close button called
}
I actually have a custom uiview that works, and I think everything in the uiview that doesn't work is set up the same as the one that works. Here is the code:
protocol SessionDisplayViewDelegate: class
{
func homeButtonTapped()
}
class SessionDisplayView: UIView
{
#IBOutlet var view: UIView!
#IBOutlet weak var accountImage: UIButton!
#IBOutlet weak var mySKView: SKView!
#IBOutlet weak var sessionTitle: UILabel!
weak var delegate: SessionDisplayViewDelegate?
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)!
commonInitialization()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInitialization()
}
func commonInitialization()
{
Bundle.main.loadNibNamed("SessionDisplayView", owner: self, options: nil)
self.addSubview(self.view)
//accountImage = UIImage(data: ShareData.sharedInstance.accounts[ShareData.sharedInstance.indexOfCurrentAccount].picture!, scale: 1.0)
}
func onView()
{
let curScene = MyScene(size: mySKView.bounds.size)
curScene.scaleMode = SKSceneScaleMode.aspectFill
mySKView.presentScene(curScene)
let myImage = UIImage(data: (ShareData.sharedInstance.accounts[ShareData.sharedInstance.indexOfCurrentAccount]?.picture!)! as Data, scale: 0.5)
accountImage.setImage(myImage, for: UIControlState())
sessionTitle.text = ShareData.sharedInstance.accounts[ShareData.sharedInstance.indexOfCurrentAccount]?.name
var myTest = sessionTitle.text
self.view.setNeedsDisplay()
}
#IBAction func homeButtonTouched(_ sender: UIButton)
{
delegate?.homeButtonTapped()
}
}
I don't know that the self.view.setNeedsDisplay() needs to be called- I'm just trying to make it work. The title doesn't change even though the variable for the title does change- I've checked that, and that is working. Either there's a connection issue between the label and the variable, or the view controller isn't getting the update signal to change the view controller. I don't know which- and I don't know how to nail down which it is, either. Any ideas on how to fix this would be deeply appreciated. Here is the ViewController code:
class SessionDisplayViewController: UIViewController, SessionDisplayViewDelegate
{
#IBOutlet weak var mySessionView: SessionDisplayView!
func homeButtonTapped()
{
self.performSegue(withIdentifier: "ReturnHome", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
mySessionView.onView()
mySessionView.sessionTitle.text = "Test"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override var shouldAutorotate : Bool {
if (UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft) || (UIDevice.current.orientation == UIDeviceOrientation.landscapeRight) || (UIDevice.current.orientation == UIDeviceOrientation.unknown)
{
return true
}
else
{
return false
}
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return [UIInterfaceOrientationMask.portrait, UIInterfaceOrientationMask.portraitUpsideDown]
}
override var preferredStatusBarStyle : UIStatusBarStyle
{
return UIStatusBarStyle.lightContent
}
}
Any thoughts or suggestion on how to get the UIView to update would be most welcome. Thanks.
Sincerely,
Sean
How does you add your custom view to your root view? From code or from xib/storyboard? If you done that by xib/storyboard you must override awakeFromNib method in your custom view class and call commonInitialization inside it. init() method was call only if you create your view by code.
I have created a custom view from xib(freeform) in which there are two button (Login and cancel) and i have present it at a view according to some condition. Custom view get present on another view nicely but the button(Login an cancel) not getting any touch event.
Code of custom class and init method:
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
}
#IBAction func cancelButtonAction(sender: AnyObject) {
}
}
This is the block of code from where i have add the custom view as a subview.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if Reachability.isConnectedToNetwork() {
categoryObj = categoryArray .objectAtIndex(indexPath.row) as! TECategoryDetails
if categoryObj.categoryType == "premium" {
let screen = UIScreen.mainScreen().bounds
customView = customAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
else{
watchAllFlag = false
self.performSegueWithIdentifier("Episode", sender: self)
}
}
else {
self.showAlertPopUp()
}
}
You can also do like this way.
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
loginButton.addTarget(self, action: Selector(“loginButtonAction:”), forControlEvents: .TouchUpInside)
cancelButton.addTarget(self, action: Selector(“cancelButtonAction:”), forControlEvents: .TouchUpInside)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
func loginButtonAction(sender: AnyObject) {
}
func cancelButtonAction(sender: AnyObject) {
}
}
Check it, its working:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func displayAlertBtnTapped(sender: AnyObject) {
let screen = UIScreen.mainScreen().bounds
let customView = CustomAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
}
CustomAlertView.swift:
import UIKit
class CustomAlertView: UIView {
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CustomAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
print("Login button clicked");
}
#IBAction func cancelButtonAction(sender: AnyObject) {
print("Cancel button clicked");
}
}
For testing, use the following GitHub link:
https://github.com/k-sathireddy/AlertViewSample