UIButton Target Action inside UIView
I thinks it is not a good idea to know inside the view about parent structures. It is breaks encapsulation and leads to hard maintenance, bugs and extra relations.
As a simple way you can define function addTarget for your custom UIView, that will work like a bridge.
class UICustomView {
func addTarget(target: AnyObject, action: Selector, forControlEvents: UIControlEvents) {
menuControlButton.addTarget(target, action: action, forControlEvents: forControlEvents)
}
func setupViews() {...}
func toggleButton(sender: MenuControlButton!) {...}
class SomeOtherViewController {
func someInitFunc {
let viewWithButton = UICustomView()
viewWithButton.addTarget(self, "foo:", .TouchUpInside)
}
func foo(sender: AnyObject) {
let isActive = sender.toggleActive() // switches button image and returns whether active or not after
NSUserDefaults.standardUserDefaults().setBool(isActive, forKey: sender.title)
self.reloadCalendar()
}
}
Then your controller only knows that UICustomView can handle events and UICustomView have know nothing about SomeOtherViewController
If you have more than one button inside you custom view perhaps it would be a good idea to implement something like UIAlertController with type UIAlertControllerStyle.ActionSheet
Dynamic Creation UIButton AddTarget on UIView executed on UIViewController
In the method button.addTarget(self, action: #selector(optionClicked(_:)), for: .touchUpInside)
you need to provide pointer to the viewController which will receive the action.
The easiest way in your case would be to create lazy variable DrawerView with DrawerController on the init and use the drawer controller in the button action.
DrawerView.swift
class DrawerView: UIView {
private unowned let drawerController: DrawerController
init(drawerController: DrawerController) {
self.drawerController = drawerController
}
... wherever is your code placed ...
let menuOptions = ["Info", "Actions", "Users", "Patiens"]
menuOptions.forEach({
let button = UIButton()
button.setTitle($0, for: .normal)
if $0.contains(menuOptions[0]) {
button.style(with: .filled)
} else {
button.style(with: .outlined)
button.addTarget(drawerController, action: #selector(DrawerController.optionClicked(_:)), for: .touchUpInside)
actionStackView.addArrangedSubview(button)
}
})
....
}
It's important you use unowned
or weak
to prevent retain cycles and memory leaks
To create the DrawerView you can use a lazy variable:
lazy var shareView: DrawerView = DrawerView(drawerController: self)
lazy will allow you to use self, you can also use optional and create the variable later, but that's basically what lazy does.
Hope it helps!
AddTarget connected to UIButton in customView does not work. (swift5, iOS)
It is difficult to find out the actual problem on reduced example code, that is not running on itself. The use of addTarget itself is fine, so I suppose the problem is somewhere in the code, that we do not see here.
One educated guess would be a problem with the size/layout of your custom view. Depending on the view, it might happen that the bounds of the view are smaller than the button or zero, although you will still see the full button, but you cannot click it. You might notice this on a standard button if you do not get any color effects on the button while clicking it.
Another good next step would be to have a look into Xcode's View Debugger to see if there is anything wrong with the view sizes.
For reference, I gave your sample code a little edit to get it running in a Playground and your function is just triggered fine there.
import PlaygroundSupport
import UIKit
class CustomView: UIView {
var button = UIButton(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 20.0))
override init(frame: CGRect) {
super.init(frame: frame)
button.backgroundColor = .blue
button.setTitle("click me", for: .normal)
addSubview(button)
button.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
button.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ViewController: UIViewController {
var customView = CustomView()
override func viewDidLoad() {
customView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(customView)
customView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
customView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
customView.button.addTarget(self, action: #selector(someFunction), for: .touchUpInside)
}
@objc func someFunction() {
print("Some function!")
}
}
PlaygroundPage.current.liveView = ViewController()
Swift4 addTarget at UIButton doesnt work in UIView
You have to give frame to your ViewSystem. and ViewSystem's height width should be greater than button's X and Y.
var ViewSystem = UIView()
ViewSystem.frame = CGRect(x: 50, y: 100, width: 70, height: 70)
@objc func TestPressed(sender: UIButton?) {Test.text=String((sender?.tag)!)
func ButtonCreate () {
let button = UIButton()
button.frame = CGRect(x: 0, y: 0, width: 70, height: 70)
button.addTarget(self, action: #selector(TestPressed), for: .touchUpInside)
button.backgroundColor = UIColor.red
button.tag=5
ViewSystem.addSubview(button)
self.view.addSubview(ViewSystem)
}
}
How to add an action to a UIButton that is in another class
The best option would be to add the target in your controller and then call a method in your toolbarWrapper
on button press. But if you really need to keep this design, you should have a strong reference to your toolbarWrapper
in your controller class, otherwise your toolbarWrapper
is deallocated and nothing gets called. Also, the buttonTapped(_:)
method does not need to be static. Thus, in your controller:
class Controller: UIViewController {
var toolbarWrapper: CustomToolbarWrapper?
override func viewDidLoad() {
toolbarWrapper = CustomToolbarWrapper(view: view, target: self)
let toolbar = toolbarWrapper.toolbarView
view.addSubview(toolbar)
... Other code ...
}
}
And in your wrapper:
class CustomToolbarWrapper {
var toolbarView: UIView
init(view: UIView, target: Any) {
let height: CGFloat = 80
toolbarView = UIView(frame: CGRect(x: 0, y: view.frame.height - height,width: view.frame.width, height: height))
let button = UIButton()
... Some button layout code ...
button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
toolbarView.addSubview(button)
}
@objc func buttonTapped(_ sender: Any) {
print("button tapped")
}
}
Swift class with uibutton.addTarget to UIView not working
Because you need to give it a frame and add it to self.view
var mainview = UIView()
Swift addTarget to a button and call function in different View Controller file from UIview file
You have two options here:
- move
addTarget
into view controllerviewDidLoad
:
myView.deleteButton.addTarget(self, action: #selector(showDeleteAlert), for: UIControl.Event.touchUpInside)
- If you wanna make button private(which is a good practice), you can add proxy func to your
MyView
func addDeleteButtonTarget(_ target: Any?, action: Selector) {
deleteButton.addTarget(target, action: action, for: .touchUpInside)
}
And call it:
myView.addDeleteButtonTarget(self, action: #selector(showDeleteAlert))
In any case, you cant call button.addTarget(target: MyViewController, ...)
, because you need to pass an instance of the MyViewController
, not just a class name.
Action of UIButton doesn't work if the button is initialized with let and the addTarget in it in custom view, but it works in UIViewController
self
inside that block actually is the block, not the view(you can see it using print(self)
), probably because it's not yet initialised(same reason why you can't use self before super.init
), that's why I usually add targets/delegates outside of the initialisation block. With lazy var
self is already initialised, so no problem should be there.
I'm not sure why it works at all, seems kind of magic for me, and I wouldn't depend on it.
Anyway, it works fine with both custom ViewController and custom View in my case: I've added CustomView
as subview to ViewController
in the storyboard.
class ViewController: UIViewController {
private let usernameButton: UIButton = {
let button = UIButton(type: .system)
button.setTitleColor(.black, for: .normal)
button.setTitle("someTitle", for: .normal)
button.titleLabel?.font = .boldSystemFont(ofSize: 13)
button.addTarget(self, action: #selector(didTapUsername), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.insertSubview(usernameButton, at: 0)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
usernameButton.frame = view.bounds
}
@objc
func didTapUsername() {
print("ViewController", #function)
}
}
class CustomView: UIView {
private let usernameButton: UIButton = {
let button = UIButton(type: .system)
button.setTitleColor(.black, for: .normal)
button.setTitle("someTitle", for: .normal)
button.titleLabel?.font = .boldSystemFont(ofSize: 13)
button.addTarget(self, action: #selector(didTapUsername), for: .touchUpInside)
return button
}()
override func awakeFromNib() {
super.awakeFromNib()
addSubview(usernameButton)
}
override func layoutSubviews() {
super.layoutSubviews()
usernameButton.frame = bounds
}
@objc
func didTapUsername() {
print("CustomView", #function)
}
}
This shouldn't do differently for UIViewController
/UIView
, check out your logic
Related Topics
How to Add Frameworks into the Swift Project
Native-Like Momentum-Scrolling on Body in iOS Webapp
How to Make a Nsurlsesssion Get Request with Cookies
Custom Uibarbuttonitem with Bg Colour and Text Swift 3
Data Repeat in UItableview When Scrolling
Selecting All The Items in UIcollectionview iOS, Even The Cells That Are Not Visible
Uiwindow? Does Not Have Member Named Bounds
Uitableview Scroll Erases Data in Text Field Inside UItableviewcell
How to Integrate .Proto Files in Xcode Compilation
Alamofire Request Gets Stuck When Entering Background
Uialertview's Textfield Does Not Show Keyboard in iOS8
How to Dismiss a Modal Segue Then Perform Push Segue to New View Controller
Receipt Validation in iOS Returns Incorrect Info During Sandbox Testing
Swift - Add Same Navigation Bar Items to Every Page
iOS - Combine/Concatenate Multiple Audio Files
-Costtonode:' Not Sent to Gkgraphnode2D Subclass in Gameplaykit