Uibutton Target Action Inside Uiview

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:

  1. move addTarget into view controller viewDidLoad:
myView.deleteButton.addTarget(self, action: #selector(showDeleteAlert), for: UIControl.Event.touchUpInside)

  1. 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



Leave a reply



Submit