自定义 UIView 类中的 UIButton 不起作用
Posted
技术标签:
【中文标题】自定义 UIView 类中的 UIButton 不起作用【英文标题】:UIButton inside custom UIView class not working 【发布时间】: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 【参考方案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")
【讨论】:
呃...请不要发布代码的屏幕截图。 它已被修改,但我正在添加屏幕以显示输出以上是关于自定义 UIView 类中的 UIButton 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
为啥从自定义 UIView 向 UIButton 添加子视图不显示添加的子视图?
UIVIew 中的 UIButton 不在 iPhone 应用程序中居中
尽管 userInteractionEnabled = true,但 UIView 中的 UIButton 没有响应触摸事件