【问题标题】:UIButton inside custom UIView class not working自定义 UIView 类中的 UIButton 不起作用
【发布时间】:2018-03-22 13:59:08
【问题描述】:

我知道这个问题已经被问过很多次了,但没有一个解决方案对我有用。

我有一个自定义 UIView 类,用于显示警报消息。我添加了 UIButton 来关闭视图。但是,当我选择它时,什么也没有发生。

import UIKit
public class Alert: UIView {

    public var image: UIImage?
public var title: String?
public var message: String?
public var closeButtonText: String?

public var dialogBackgroundColor: UIColor = .white
public var dialogTitleTextColor: UIColor = .black
public var dialogMessageTextColor: UIColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
public var dialogImageColor: UIColor = UIColor(red:0.47, green:0.72, blue:0.35, alpha:1.0)
public var overlayColor: UIColor = .black
public var overlayOpacity: CGFloat = 0.66

public var paddingSingleTextOnly: CGFloat = 8
public var paddingTopAndBottom: CGFloat = 24
public var paddingFromSides: CGFloat = 8
public var seperatorHeight: CGFloat = 6

private var height: CGFloat = 0
private var width: CGFloat = 0
private var maxSize: CGSize = CGSize()
private let marginFromSides: CGFloat = 80

public lazy var imageSize: CGSize = CGSize(width: 75, height: 75)

public var overlay = false
public var blurOverlay = true

//animation duration
public var duration = 0.33

private var onComplete: (() ->  Void)?

@objc public var titleFont: UIFont =  UIFont.systemFont(ofSize: 18)
@objc public var messageFont: UIFont = UIFont.systemFont(ofSize: 15)


private lazy var backgroundView: UIView = {
    let view = UIView()
    view.alpha = 0
    return view
}()

public let dialogView: UIView = {
    let view = UIView()
    view.layer.cornerRadius = 6
    view.layer.masksToBounds = true
    view.alpha = 0
    view.clipsToBounds = true
    return view
}()

private lazy var imageView: UIImageView = {
    let view = UIImageView()
    view.contentMode = .scaleAspectFit
    return view
}()

public lazy var closeButton: UIButton = {
    let button = UIButton()
    return button
}()

private lazy var titleLabel: UILabel = {
    let label = UILabel()
    label.numberOfLines = 0
    label.textAlignment = .center
    return label
}()

private lazy var messageLabel: UILabel = {
    let label = UILabel()
    label.numberOfLines = 0
    label.textAlignment = .center
    return label
}()

@objc func closeButtonTapped(sender: UIButton){
    dismiss()
}

private func calculations() {
    height += paddingTopAndBottom
    maxSize = CGSize(width: frame.width - marginFromSides * 2, height: frame.height - marginFromSides)
}

public convenience init(title:String, message: String, image:UIImage) {
    self.init(frame: UIScreen.main.bounds)
    self.title = title
    self.message = message
    self.image = image
}

public convenience init(title:String, image:UIImage) {
    self.init(frame: UIScreen.main.bounds)
    self.title = title
    self.image = image
}

public convenience init(title: String, message: String) {
    self.init(frame: UIScreen.main.bounds)
    self.title = title
    self.message = message
}

public convenience init(message: String) {
    self.init(frame: UIScreen.main.bounds)
    paddingTopAndBottom = paddingSingleTextOnly
    paddingFromSides = paddingSingleTextOnly * 2
    self.message = message
}

override init(frame: CGRect) {
    super.init(frame: frame)
}

public required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

private func createOverlay() {
    backgroundView.frame = frame
    backgroundView.backgroundColor = overlayColor
    backgroundView.isUserInteractionEnabled = true
    addSubview(backgroundView)
    if let window = UIApplication.shared.keyWindow {
        window.addSubview(backgroundView)
    } else if let window = UIApplication.shared.delegate?.window??.rootViewController {
        window.view.addSubview(self)
    }
}

private func createBlurOverlay() {
    backgroundView.frame = frame
    //Blur Effect
    let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
    let blurEffectView = UIVisualEffectView(effect: blurEffect)
    blurEffectView.frame = frame
    blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    backgroundView.addSubview(blurEffectView)
    addSubview(backgroundView)
    if let window = UIApplication.shared.keyWindow {
        window.addSubview(backgroundView)
    } else if let window = UIApplication.shared.delegate?.window??.rootViewController {
        window.view.addSubview(self)
    }
}

private func createTitle(title: String) {
    titleLabel.font = titleFont
    titleLabel.text = title
    titleLabel.frame.origin.y = height + 2
    let titleLabelSize = titleLabel.sizeThatFits(maxSize)
    handleSize(size: titleLabelSize)
    titleLabel.frame.size = titleLabelSize
    titleLabel.textColor = self.dialogTitleTextColor
    dialogView.addSubview(titleLabel)
}

private func createMessage(message: String) {
    messageLabel.font = messageFont
    messageLabel.text = message
    messageLabel.frame.origin.y = height
    let messageLabelSize = messageLabel.sizeThatFits(maxSize)
    messageLabel.frame.size = messageLabelSize
    messageLabel.textColor = self.dialogMessageTextColor
    handleSize(size: messageLabelSize)
    dialogView.addSubview(messageLabel)
}


private func createImage(image: UIImage) {
    imageView.image = image.withRenderingMode(.alwaysTemplate)
    imageView.frame.origin.y = height
    imageView.frame.size = imageSize
    imageView.tintColor = self.dialogImageColor
    handleSize(size: imageSize)
    dialogView.addSubview(imageView)
}

private func createButton(){
    closeButton.setTitle("Close", for: .normal)
    closeButton.tintColor = UIColor.white
    closeButton.frame.origin.y = height + 20
    let closeButtonSize = CGSize(width: width - 60, height: 60)
    closeButton.frame.size = closeButtonSize
    closeButton.layer.cornerRadius = 6
    closeButton.backgroundColor = Color.NavigationBar.tintColor
    closeButton.isUserInteractionEnabled = true
    handleSize(size: closeButtonSize)
    dialogView.addSubview(closeButton)
}

private func createDialog() {
    centerAll()
    height += paddingTopAndBottom
    dialogView.frame.size = CGSize(width: width, height: height)
    dialogView.backgroundColor = self.dialogBackgroundColor
    dialogView.isUserInteractionEnabled = true
    addSubview(dialogView)
    self.dialogView.center = self.center
    self.dialogView.transform = CGAffineTransform(scaleX: 1.15, y: 1.15)
    if let window = UIApplication.shared.keyWindow {
        window.addSubview(dialogView)
        closeButton.addTarget(self, action: #selector(closeButtonTapped(sender:)), for: .touchUpInside)
    } else if let window = UIApplication.shared.delegate?.window??.rootViewController {
        UIApplication.topViewController()?.view.addSubview(self)
        window.view.addSubview(self)
        closeButton.addTarget(self, action: #selector(closeButtonTapped(sender:)), for: .touchUpInside)
    }
}

private func centerAll() {
    if ((messageLabel.text) != nil) {
        messageLabel.frame.origin.x = (width - messageLabel.frame.width) / 2
    }

    if ((titleLabel.text) != nil) {
        titleLabel.frame.origin.x = (width - titleLabel.frame.width) / 2
    }

    if ((imageView.image) != nil) {
        imageView.frame.origin.x = (width - imageView.frame.width) / 2
    }
    closeButton.frame.origin.x = (width - closeButton.frame.width) / 2

}

private func handleSize(size: CGSize) {
    if width < size.width + paddingFromSides * 2 {
        width = size.width + paddingFromSides * 2
    }
    if paddingTopAndBottom != paddingSingleTextOnly {
        height += seperatorHeight
    }
    height += size.height
}

private func showAnimation() {
    UIView.animate(withDuration: duration, animations: {
        if self.overlay {
            self.backgroundView.alpha = self.overlayOpacity
            self.dialogView.transform = CGAffineTransform(scaleX: 1, y: 1)
        }
        self.dialogView.alpha = 1
    })

}
public func show() {
    if let complete = onComplete {
        self.onComplete = complete
    }
    calculations()

    if self.overlay {
        if blurOverlay {
            createBlurOverlay()
        } else {
            createOverlay()
        }
    }

    if let img = image {
        createImage(image: img)
    }
    if let title = title {
        createTitle(title: title)
    }
    if let message = message {
        createMessage(message: message)
    }
    createButton()
    createDialog()

    showAnimation()

}

public func dismiss(){
    UIView.animate(withDuration: duration, animations: {
        if self.overlay {
            self.backgroundView.alpha = 0
        }
        self.dialogView.transform = CGAffineTransform(scaleX: 1.15, y: 1.15)
        self.dialogView.alpha = 0
    }, completion: { (completed) in
        self.dialogView.removeFromSuperview()
        if (self.overlay)
        {
            self.backgroundView.removeFromSuperview()
        }
        self.removeFromSuperview()
        if let completionHandler = self.onComplete {
            completionHandler()
        }
    })
}
}

我如何创建警报;

let alert = Alert(title: "hata",message: "hata mesajı ekrana basıldı", image: #imageLiteral(resourceName: "error"))
alert.show()

如果我在 UIViewController(我创建这个 UIView 的地方)中声明目标为

Alert.closeButton.addTarget(self, action: #selector(closeButtonTapped(sender:), for: .touchUPInside)

并在 UIViewController 中创建函数它正在工作。我不知道为什么它在自定义类中不起作用。

所以我的问题是如何在点击按钮时关闭警报视图?

我尝试了以下解决方案,但对我不起作用;

UIButton target action inside custom class

【问题讨论】:

  • 您的代码并没有真正显示正在发生的事情...您在哪里将按钮添加到视图中?你是如何显示视图的?请看:How to create a Minimal, Complete, and Verifiable example
  • @DonMag 我编辑了我的代码。你能检查一下吗?谢谢。
  • 你需要更彻底。我将您的代码粘贴到一个 swift 文件中,并且有几十个错误(未解析的标识符等)。将您的代码剥离到最基本的开始 - 只需要显示您的视图并添加按钮。一旦你的按钮/关闭工作,然后你可以添加其他所有内容。
  • 我添加了整个代码。这个应该可以的。 @DonMag

标签: ios swift xcode uiview uibutton


【解决方案1】:

假设这些行在函数内部 - 例如由于点击按钮:

@IBAction func didTap(_ sender: Any) {
    let alert = Alert(title: "hata",message: "hata mesajı ekrana basıldı", image: #imageLiteral(resourceName: "error"))
    alert.show()
}

您正在创建 Alert 类的实例,在其中调用 .show() 函数,然后它超出范围。

因此,只要该函数存在,alert 就不再存在,并且其中的任何代码都无法运行。

你需要有一个类级别的变量在显示时保持它:

class MyViewController: UIViewController {

    var alert: Alert?

    @IBAction func didTap(_ sender: Any) {
        alert = Alert(title: "hata",message: "hata mesajı ekrana basıldı", image: #imageLiteral(resourceName: "error"))
        alert?.show()
    }

}

这是处理Alert 视图的“错误方式”和“正确方式”的演示:https://github.com/DonMag/EmreTest

【讨论】:

  • 我认为您误解了我想要实现的目标。我在警报视图中有 UIButton,该按钮关闭警报视图。所以我不想在按钮点击功能中调用 show() 。谢谢你:)
  • 不...这是您在问题How I create the alert; 中发布的VIewController 中的代码。这两行代码是从 ViewController 中的 somewhere 调用的。无论您从哪里调用它,let alert = Alert(...) 创建的对象都会在该代码函数/方法/块完成时超出范围,并且您的新对象会消失。 view 仍然在屏幕上,但它背后的 code 不见了。
  • @EmreÖnder - 请参阅我的答案的编辑。自己试试吧……新建一个ViewController,加个按钮,用上面的代码测试一下。
  • 我编辑我的问题以更清楚。我要问的是如何关闭警报视图,而不是打开它。
  • @EmreÖnder - 如果您尝试我的回答,您会看到“警报视图”中的按钮有效 现在关闭视图。问题是,当您实例化 Alert 类并退出该代码行所在的任何函数时,您还 DESTROY 该类,因此按钮代码不能运行 - 它不再存在!试着做我给你看的,你会看到的。
【解决方案2】:

看这段代码

1- 在 UIView 类中调用 IBAction

import UIKit

public class Alert: UIView {

    public lazy var closeButton: UIButton = {
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        button.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
        return button
    }()

    func createDialog() {
          closeButton.addTarget(self, action: #selector(self.closeButtonTapped(sender:)), for: .touchUpInside)
        self.addSubview(closeButton)
    }

    @objc func closeButtonTapped(sender: UIButton){
        print("Call   1")
    }
}
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let alert = Alert(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        alert.createDialog()

        self.view.addSubview(alert)
    }

}

2- 在 UIViewController 类中调用 IBAction

import UIKit

public class Alert: UIView {

    public lazy var closeButton: UIButton = {
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        button.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
        return button
    }()

    func createDialog() {
        //  closeButton.addTarget(self, action: #selector(self.closeButtonTapped(sender:)), for: .touchUpInside)
        self.addSubview(closeButton)
    }

    @objc func closeButtonTapped(sender: UIButton){
        print("Call   1")
    }
}
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let alert = Alert(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        alert.createDialog()
        alert.closeButton.addTarget(self, action: #selector(self.closeButtonTappedController(_:)), for: .touchUpInside)
        self.view.addSubview(alert)
    }

    @IBAction func closeButtonTappedController(_ sender:UIButton){
        print("Call   2")

    }
}

【讨论】:

  • 呃...不要发布代码的屏幕截图。
  • 它已被修改,但我正在添加屏幕以显示输出
猜你喜欢
  • 2018-01-19
  • 1970-01-01
  • 2021-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-18
  • 1970-01-01
相关资源
最近更新 更多