swift cannot add target to UIButton - ios

so this question is super simple, but i checked that like a 100 times but it still won't work.
Basically, when user taps on tableView cell, it open another VC with different views, depending whether or not user is owner of post.
First condition, works just fine, adding target to button, while when second is being executed, nothing happens
lazy var buttonsView = DetailButtonsView() // those are almost the same
lazy var addvertView = AdvertiseView()
// inside of buttonsView()
lazy var skipButton: UIButton = {
let button = UIButton()
button.setTitle("Пожаловаться", for: .normal)
button.setTitleColor(.mainColor, for: .normal)
button.titleLabel?.font = .getPoppinsMediumFont(on: 15)
return button
}()
override init(frame: CGRect) {
super.init(frame: .zero)
setupView() //set up constraints
}
//inside of AdvertiseView()
lazy var blackButton:UIButton = {
var button = UIButton()
button.layer.cornerRadius = 8
button.backgroundColor = .black
return button
}()
override init(frame: CGRect) {
super.init(frame: .zero)
setupView() //set up constraints
}
//
func setUpBottom() -> Void {
if dataInfo!.user_id! == UserSettings.userModel.id
{
self.backView.addSubview(addvertView) //also works
addvertView.snp.makeConstraints //works
{
(make) in
make.left.equalToSuperview()
make.top.equalTo(userView.snp.bottom).offset(24)
make.height.equalTo(450)
make.bottom.lessThanOrEqualTo(-34)
}
addvertView.blackButton.addTarget(self, action: #selector(blackButtonMethod), for: .touchUpInside) // does not add target
}
else {
backView.addSubview(buttonsView) //works
buttonsView.snp.makeConstraints { (make) in
make.left.right.equalToSuperview()
make.top.equalTo(userView.snp.bottom).offset(24)
make.bottom.lessThanOrEqualTo(-34)
}
buttonsView.skipButton.addTarget(self, action: #selector(toComplain), for: .touchUpInside) //works
}
#objc func toComplain(){ //works
let vc = ComplaintTypeViewController()
vc.advertID = dataInfo!.id!
navigationController?.pushViewController(vc, animated: true)
}
#objc func blackButtonMethod(){ //does not work
print("hello")
parameters["action"] = "hot"
parameters["advert_id"] = String(describing: dataInfo!.id)
updateAdvert(parameters: parameters)
}

The target is probably added, but you cannot interact with it. That usually happens when constraints/frame is not set right. I see that the skip button uses:
button.setTitle("Пожаловаться", for: .normal)
which will infer autolayout width/height.
I don't see black blackButton's autolayout constraints or label set anywhere.

Related

UIBarButtonItem not Showing

So Im trying to create a UIBarButtonItem with a custom UIView by subclassing it like so.
import UIKit
import SnapKit
class LocationManager: UIBarButtonItem {
let createdView = UIView()
lazy var currentCityLabel: UILabel = {
let currentCityLabel = UILabel()
currentCityLabel.text = "Philadelphia, PA"
guard let customFont = UIFont(name: "NoirPro-SemiBold", size: 20) else {
fatalError("""
Failed to load the "CustomFont-Light" font.
Make sure the font file is included in the project and the font name is spelled correctly.
"""
)
}
currentCityLabel.adjustsFontForContentSizeCategory = true
return currentCityLabel
}()
lazy var downArrow: UIImageView = {
let downArrow = UIImageView()
downArrow.contentMode = .scaleAspectFit
downArrow.image = UIImage(named: "downArrow")
return downArrow
}()
override init() {
super.init()
setupViews()
}
#objc func setupViews(){
customView = createdView
createdView.addSubview(currentCityLabel)
currentCityLabel.snp.makeConstraints { (make) in
make.left.equalTo(createdView.snp.left)
make.top.bottom.equalTo(createdView)
}
createdView.addSubview(downArrow)
downArrow.snp.makeConstraints { (make) in
make.left.equalTo(currentCityLabel.snp.right).offset(5)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
However, when I create it and assign it in my viewController I see nothing
import UIKit
class ViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
#objc func setupViews(){
guard let collection = collectionView else {
return
}
collection.backgroundColor = .white
let customLeftBar = LocationManager()
self.navigationController?.navigationItem.leftBarButtonItem = customLeftBar
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I've looked at other post and none seem to quite match my situation. I'm beginning to think it is because I didn't give the UIView a frame but I am not exactly sure how I would do that in this instance if that is the case. Anyone see anything I don't that could potentially help me solve this problem. Also setting a target doesn't work I tried two different ways and none of them triggers a thing
#objc func setupBarButtonItems(){
let customLeftBar = LocationManager()
customLeftBar.action = #selector(self.leftBarPressed)
customLeftBar.target = self
customLeftBar.customView?.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.leftBarPressed))
customLeftBar.customView?.addGestureRecognizer(tapGesture)
navigationItem.leftBarButtonItem = customLeftBar
}
#objc func leftBarPressed(){
print("left bar tapped")
}
Change your adding line from
self.navigationController?.navigationItem.leftBarButtonItem = customLeftBar
to
self.navigationItem.leftBarButtonItem = customLeftBar
When add the barItem, you need to add it via navigationItem of the ViewController, not NavigationController
EDITED for add the action
Your custom UIBarButtonItem is a Custom View's BarButtonItem, so the target and selector will not working.
You can add your custom action by adding a button into your customView, and send the action via closure
Init your closure
var didSelectItem: (() -> Void)?
Add the create button code in your #objc func setupViews()
let button = UIButton(type: .custom)
createdView.addSubview(button)
button.snp.makeConstraints { (maker) in
maker.top.bottom.leading.trailing.equalTo(createdView)
}
// button.backgroundColor = UIColor.cyan // uncomment this line for understand about the barbuttonitem's frame
button.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
and add the function
#objc func didTap(_ button: UIButton) {
print("Did tap button")
}
In your viewController, you can get the tap action by
customLeftBar.didSelectItem = { [weak self] in
self?.leftBarPressed()
}
Unfortunately, your barbuttonitem's default frame is 30x30, so you must be set the frame for your barbuttonitem. If not, you can only catch the tap action in 30x30 area (uncomment the code for see it)

Disable editing of UITextField Without disabling subviews [duplicate]

This question already has answers here:
Easy way to disable a UITextField?
(5 answers)
Closed 5 years ago.
I have UITextField and I put a UIButton in the left view of it. I want to disable editing of UITextField while my UIButton response to on click action. I tried textField.isUserInteractionEnabled and also textField.isEnabled but both of them also disable my UIButton. is there any way to do this? my custom UITextField class is like this
import UIKit
#IBDesignable
class UITextFieldWithButton: UITextField, UITextFieldDelegate {
private var happyButton: UIButton = UIButton(type: .system)
#IBInspectable
var buttonText: String {
get {
let string = happyButton.titleLabel!.text!
let start = string.index(string.startIndex, offsetBy: 2)
let end = string.endIndex
return String(happyButton.titleLabel!.text![start..<end])
}
set {
happyButton.setTitle(" " + newValue, for: .normal)
happyButton.sizeToFit()
self.leftView = happyButton
self.leftViewMode = .always
}
}
var isButtonEnable: Bool {
get {
return self.isButtonEnable
}
set {
happyButton.isEnabled = newValue
}
}
var buttonDelegate: UITextFieldWithButtonDelegate?
required override init(frame: CGRect) {
super.init(frame: frame)
delegate = self
happyButton.addTarget(self,action: #selector(pressButton(_:)), for: .touchUpInside)
happyButton.titleLabel?.font = UIFont(name: (font?.fontName)!, size: (font?.pointSize)!)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
delegate = self
happyButton.addTarget(self,action: #selector(pressButton(_:)), for: .touchUpInside)
happyButton.titleLabel?.font = UIFont(name: (font?.fontName)!, size: (font?.pointSize)!)
}
#objc private func pressButton(_ sender: UIButton){
if let click = buttonDelegate {
click.clickOnUITextFieldButton(self)
}
}
}
protocol UITextFieldWithButtonDelegate {
func clickOnUITextFieldButton(_ sender: UITextFieldWithButton)
}
"I tried textField.isUserInteractionEnabled and also textField.isEnabled but both of them also disable my UIButton" :your code is working fine you might have added button behind uitextfield try to move it forward in view hierarchy

accessing global variable from programmatic uibutton property

I want to use the same UIView class to record and play sound. In this view class, I add a button programmatically and I want to change the button text according to the purpose of the view. When the view is created as a player it will show play icon (or the text for now). If the view is created as a recorder it will show the record icon. But I cannot access global variable in the view from my UIButton.
class AudioPlayerView: UIView {
var isRecorder = false
override init(frame: CGRect) {
super.init(frame: frame)
...
}
let theButton: UIButton = {
let button = UIButton()
if isRecorder {
button.setTitle("▷", for: .normal)
button.addTarget(self, action: #selector(playPauseAudio), for: .touchUpInside)
} else {
button.setTitle("▢", for: .normal)
button.addTarget(self, action: #selector(recordTapped), for: .touchUpInside)
}
button.backgroundColor = .clear
button.layer.cornerRadius = 15.0
return button
}()
I have re implemented your player class. Now you do not need to create two separate view for recording and playing status. All you need is to change the isRecorder value and your button title will be change without any need to create another view.
class AudioPlayerView: UIView {
var isRecorder = false {
didSet {
if isRecorder {
theButton.setTitle("▷", for: .normal)
} else {
theButton.setTitle("▢", for: .normal)
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
if isRecorder {
theButton.setTitle("▷", for: .normal)
} else {
theButton.setTitle("▢", for: .normal)
}
//Add your button to view as subview.
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
let theButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.layer.cornerRadius = 15.0
button.addTarget(self, action: #selector(tapButton), for: .touchUpInside)
return button
}()
func tapButton() {
if isRecorder {
playPauseAudio()
} else {
recordTapped()
}
}
func playPauseAudio() {
}
func recordTapped() {
}
}
Actually, I made following in my viewcontroller class after I created the view. I simply set the button subview title and added relevant target. Now it seems to be functioning. But as a rookie, I am not sure if this is a good solution... Thanks every one who shared their comments and codes as well.
if cell.name == "recorder" {
audioPlayerView?.theButton.setTitle("▢", for: .normal)
audioPlayerView?.theButton.addTarget(audioPlayerView, action: #selector(audioPlayerView?.recordTapped), for: .touchUpInside)
} else {
audioPlayerView?.theButton.setTitle("▷", for: .normal)
audioPlayerView?.theButton.addTarget(audioPlayerView, action: #selector(audioPlayerView?.playPauseAudio), for: .touchUpInside)
}

UIButton addTarget Selector is not working

SquareBox.swift
class SquareBox {
func createBoxes() {
for _ in 0..<xy {
let button = UIButton()
button.backgroundColor = .white
button.setTitleColor(UIColor.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.black.cgColor
stack.addArrangedSubview(button)
button.addTarget(self, action: #selector(click(sender:)) , for: .touchUpInside)
}
}
#objc func click(sender : UIButton) {
print("Click")
}
}
ViewController.swift
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let boxRow = SquareBox()
boxRow.createBoxes()
}
}
Also I've tried #IBAction instead of #objc, it doesn't work, but if I use "click" function in ViewController.swift that I created this object, it's working but I need this function inside of this class.
Now that you have posted relevant information in your question, the problem is quite clear. You have a memory management issue.
In your GameViewController's viewDidLoad you create a local instance of SquareBox. This local instance goes out of scope at the end of viewDidLoad. Since there is no other reference to this instance, it gets deallocated at the end of viewDidLoad.
Since the instance of SquareBox has been deallocated, it is not around to act as the button's target. And your click method is never called.
The solution is to keep a reference in your view controller:
class GameViewController: UIViewController {
let boxRow = SquareBox()
override func viewDidLoad() {
super.viewDidLoad()
boxRow.createBoxes()
}
}
var btnfirst:UIButton!
override func viewDidLoad()
{
super.viewDidLoad()
btnfirst = UIButton(type: .system)
btnfirst.setTitle("Press", for: .normal)
btnfirst.setTitleColor(.red, for: .normal)
btnfirst.frame = CGRect(x: 100, y: 200, width: 100, height: 30)
btnfirst.addTarget(self, action: #selector(benpress( sender:)),for: .touchUpInside)
self.view.addSubview(btnfirst)
}
func benpress( sender :UIButton)
{
//Your Code Here
}
For those who did not find a solution, here is mine.
If you constructed your UIButton as
let button: UIButton = {
return UIButton()
}()
Just convert those into
lazy var button: UIButton = {
return UIButton()
}()
I think this is because of somewhat deallocation as mentioned above.
button.addTarget(self, action:#selector(self.click), for: .touchUpInside)
func click(sender : UIButton) {
// code here
}
I guess the issue is how you are setting up layout of your buttons.
Try this:
func createBoxes() {
stack.backgroundColor = UIColor.red
for _ in 0..<xy {
// Create the button
let button = UIButton()
button.backgroundColor = UIColor.red
// Add constraints
button.translatesAutoresizingMaskIntoConstraints = false
button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
// Setup the button action
button.addTarget(self, action: #selector(SquareBox.click(sender:)), for: .touchUpInside)
// Add the button to the stack
stack.addArrangedSubview(button)
}
}
#objc func click(sender : UIButton) {
print("Click")
}
button.addTarget(self, action: #selector(self.buttonTapped), for: .touchUpInside)
func buttonTapped(sender : UIButton) {
// code here
}
Replace with this :
btn.addTarget(self, action: #selector(self.click(sender:)), for: .touchUpInside)
I think something else effect to your selector method try to find in your code because your code also working in my project.

How to set addtarget to custom UIView

I have a custom UIView called Icons. Everything is working perfectly fine right now except one thing. The problem that i am having is being able to set userinteraction to be working or to either make the button i have in my class to be working. When I add a target to the button, i get an error that crashes everything and with the userinteraction to the view, i get no response.
class Icons: UIView {
let xUnit = UIScreen.mainScreen().bounds.width/20
let yUnit = UIScreen.mainScreen().bounds.height/30
var name: String = String()
var image: UIImage = UIImage()
let font = UIFont(name: "HelveticaNeue-Thin", size: 16.0)!
override init(frame: CGRect) {
super.init(frame: frame)
self.userInteractionEnabled = true
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addCustomView(name:String, image: UIImage ){
let label: UILabel = UILabel()
label.frame = CGRectMake(0, 1.5*xUnit, 3.4*xUnit, 2.7*xUnit)
label.textAlignment = NSTextAlignment.Center
label.font = font
label.text = name
self.addSubview(label)
let btn: UIButton = UIButton()
btn.frame=CGRectMake(0.3*xUnit, 0, 2.5*xUnit, 2.5*xUnit)
btn.setImage(image, forState: .Normal)
self.addSubview(btn)
}
}
And this is the class I'm trying to get connect it with which is in a completely different class
func tapSettings(tapGestureRecognizer: UITapGestureRecognizer){
let touchPoint = tapGestureRecognizer.locationInView(self.view)
if(CGRectContainsPoint(settings.frame, touchPoint)){
print("hi")
}
}
when I am trying to connect it to the button I say this:
btn.addTarget(self,action: #selector(HomeScreen.tapSettings))
and when I try and connect it to the view I say this :
let settingsTouch = UITapGestureRecognizer(target: self, action: #selector(HomeScreen.tapSettings))
settingsTouch.numberOfTapsRequired = 1
settingsTouch.numberOfTouchesRequired = 1
self.view.addGestureRecognizer(settingsTouch)
There are two problems in your code:
You are setting the target of the button to self when you should be setting it to an instance of HomeScreen, if that's where the method you want to call is declared
The argument a button action method receives is not UITapGestureRecognizer, but the clicked button instead, so you should replace your tapSettings method with something like this:
func tapSettings(button: UIButton){
try this
btn.addTarget(HomeScreen.self, action: #selector(HomeScreen.tapSettings(_:)), forControlEvents: UIControlEvents.TouchUpInside)
I hope this helps

Resources