How to set addtarget to custom UIView - ios

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

Related

Changing isSecureTextEntry is being used on a wrong textField

I made a subclass of a UIView with a text field and a button which allows to configure if text field is secured via isSecureTextEntry property.
I am using two instances of that view one for setting a password and another one for confirming it in a view controller like this
let passwordTextField = PasswordTextFieldView(placeholder: "New password")
let confirmPasswordTextField = PasswordTextFieldView(placeholder: "Confirm password")
Text field subclass code
final class PasswordTextFieldView: UIView {
lazy var textField: UITextField = {
let textField = UITextField()
textField.textColor = .black
textField.placeholder = placeholder
textField.textAlignment = .left
textField.textContentType = .password
textField.autocorrectionType = .no
textField.isSecureTextEntry = true
return textField
}()
private let securedButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(systemName: "eye.slash.fill")?.withRenderingMode(.alwaysTemplate), for: .normal)
button.tintColor = .gray
button.addTarget(self, action: #selector(securedButtonTapped), for: .touchUpInside)
return button
}()
private var isSecured: Bool = true
var placeholder: String
required init(placeholder: String) {
self.placeholder = placeholder
super.init(frame: CGRect.zero)
// Layout views
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc func securedButtonTapped() {
isSecured.toggle()
securedButton.setImage(UIImage(systemName: isSecured ? "eye.slash.fill" : "eye.fill"), for: .normal)
textField.isSecureTextEntry = isSecured
}
}
So the problem is, that tapping a button changes isSecureTextEntry on a textField which is being edited. How to fix it?
When you create your let variable with a self calling block, you shouldn't use self as it's not determined at that moment. You can add print to see it's value, it's not your view, because the view is not yet created.
Sometimes it'll be correct value at the end(I tried running your code and it run fine on my simulator), and sometimes it's not.
You have two options in such cases:
Replace let with lazy var. In this case self if always gonna be determined
private lazy var securedButton: UIButton = {
...
}
Move adding target to your init. If you're using many inits don't forget to add to all of them, preferably moving to an other function. I prefer this way to make sure all my props are let if I don't need to change it. Like this:
required init(placeholder: String) {
self.placeholder = placeholder
super.init(frame: CGRect.zero)
initialize()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
initialize()
// I know you're not using this initializer, just in case you'd need in future
}
private func initialize() {
securedButton.addTarget(self, action: #selector(securedButtonTapped), for: .touchUpInside)
}

swift cannot add target to UIButton

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.

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

Modify class from another view controller

I'm using this code to customize UIButtons on my main ViewController and have placed it in it's own separate .swift file to be referenced wherever a UIButton exists. I want to be able to modify the properties of the MyCustomButton from within my main ViewController after a button is pressed.
For example, I press a button that's using the properties from MyCustomButton and its color changes.
I'm just getting into swift and am not greatly familiar with it's ins and outs quite yet. Any help is appreciated.
import Foundation
import UIKit
class MyCustomButton: UIButton {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.cornerRadius = 25;
self.layer.borderColor = UIColor.blackColor().CGColor
self.layer.borderWidth = 3
self.backgroundColor = UIColor.redColor()
self.tintColor = UIColor.whiteColor()
self.setTitle("", forState: UIControlState.Normal)
self.titleLabel?.numberOfLines = 0
self.titleLabel?.textAlignment = NSTextAlignment.Center
}
}
You can try to override layoutSubviews method:
override func layoutSubviews() {
super.layoutSubviews()
if self.state == UIControlState.Highlighted {
// DO WHAT YOU WANT
} else {
// RESET TO NORMAL
}
}
KVO or delegate protocol (Swift) would work! Either of these would allow you to manipulate the properties of your UI elements when a specific action occurs.
If you want to create new class and change button default behaivour, you should override functions like this one
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
super.pressesBegan(presses, withEvent: event)
// add your implementation here
}
// func pressesCancelled
// func pressesChanged
// func pressesEnded
// etc.
But if you just want to change button properties on button tap, you can do it on button callback method:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 100)
button.setTitle("My Button", forState: UIControlState.Normal)
button.addTarget(self, action: "someAction:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
}
func someAction(sender: UIButton) {
print("My Button tapped")
sender.setTitle("Now Tapped", forState: UIControlState.Normal)
}

Resources