touch up inside (#IBAction) does not work with UIButton subclass - ios

I created a subclass of UIButton:
import UIKit
#IBDesignable
class CheckboxButton: UIButton {
#IBInspectable var checkboxBackgroundColor: UIColor = Project.Color.baseGray
#IBInspectable var textColor: UIColor = Project.Color.mainDarkText
#IBInspectable var checkboxHighlightedBackgroundColor: UIColor = Project.Color.main
#IBInspectable var highlightedTextColor: UIColor = Project.Color.mainBrightText
// MARK: - Properties
var isChecked: Bool = false {
didSet {
changeState()
}
}
// MARK: - Overrides
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
if isChecked {
isChecked = false
} else {
isChecked = true
}
return false
}
override func prepareForInterfaceBuilder() {
changeState()
}
// MARK: - #IBActions
// MARK: - Functions
private func setupView() {
isUserInteractionEnabled = true
changeState()
}
private func changeState() {
if isChecked {
backgroundColor = checkboxHighlightedBackgroundColor
self.setTitleColor(highlightedTextColor, for: .normal)
} else {
backgroundColor = checkboxBackgroundColor
self.setTitleColor(textColor, for: .normal)
}
}
}
Now I added a button inside the storyboard and gave it the class CheckboxButton. Everything works. Then I added an IBAction like this:
#IBAction func pointBtnTapped(_ sender: CheckboxButton) {
print("tapped")
selectButton(withNumber: sender.tag)
}
But this doesn't work (nothing prints out). It works with a normal button, but not if the button is the subclass CheckboxButton. Do you have any ideas?
Edit: screenshots
https://www.dropbox.com/s/ewicc349ag9l6y2/Screenshot%202016-10-06%2023.41.39.png?dl=0
https://www.dropbox.com/s/vxevzscueproivc/Screenshot%202016-10-06%2023.42.33.png?dl=0
(couldn't embed them here. Don't know why)
Thank you!

You broke UIButton by overriding beginTracking() and always returning false. This brainwashes the button into thinking it's never being clicked.
What was your intent there? In any case, return true there and your code will fire the #IBAction.
EDIT: You're overthinking the issue by using a low-level method meant for highly customized behavior such as non-rectangular buttons. You just need:
How to use UIButton as Toggle Button?

Related

Add action to button from ViewController

I have a problem adding a target from a view controller to the button that is created in a view (no action when it is pressed). But if I create the button in the view controller directly then it works.
What could be wrong here?
class ViewController: UIViewController {
var mainView = MainView()
var counter:Int = 0
#objc func buttonAction(sender:UIButton!)
{
counter += 1
print("Button was predded:\(counter)")
mainView.lable1.text = "Button was predded:\(counter)"
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mainView)
mainView.buttno1.addTarget(self, action: #selector(buttonAction), for: UIControl.Event.touchUpInside)
}
}
class MainView : UIView {
var background: UIView = {
return background
}()
lazy var buttno1: UIButton = {
var btn = UIButton()
....
return btn
}()
func createButton1(){
print("Main view btn created")
background.addSubview(buttno1)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(background)
createButton1()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

IBDesignable class not updating in xcode

I have created a custom IBDesignable UISegmentedControl class.
The class has no build errors but has warnings, it does not update inside of Xcode. There are the warnings, see the screenshot below.
#IBDesignable open class UISegmentedControlBorderless : UISegmentedControl {
#IBInspectable var borderColor:UIColor = UIColor.white {
didSet {
setupUI()
}
}
#IBInspectable var textColor:UIColor = UIColor.white {
didSet {
setupUI()
}
}
#IBInspectable var textSelectedColor:UIColor = UIColor.red {
didSet {
setupUI()
}
}
required public init?(coder aDecoder:NSCoder) {
super.init(coder:aDecoder)
setupUI()
}
override init(frame:CGRect) {
super.init(frame:frame)
setupUI()
}
override open func awakeFromNib() {
super.awakeFromNib()
setupUI()
}
override open func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupUI()
}
fileprivate func setupUI() {
tintColor = borderColor
let attributes = [NSAttributedStringKey.foregroundColor: textColor]
let attributes2 = [NSAttributedStringKey.foregroundColor: textSelectedColor]
setTitleTextAttributes(attributes, for: .normal)
setTitleTextAttributes(attributes2, for: .selected)
}
}
Warnings:
Unticking inherit module
Based on the first warning in your screenshot, Xcode is not finding your UISegementedControl subclass. This is commonly caused by not setting the correct module where the class is defined, and since your subclass is defined as open, it seems likely that you have it in a framework or module outside of the target app.
So, make sure where you set the custom class for the segmented control on the storyboard that you also selected the correct module for where the subclass is defined, and you probably want to uncheck "inherit module from target" in order to do so:

Changing a delegate's property through protocol

I have controllingView, that needs to change a property in presentingView. They are both in the same ViewController.
I can let them communicate by making presentingView delegate of controllingView. But it would be far more elegant and flexible, if I could just change the property directly (since
I need to change the presentingView's property's property actually)
I have seen it done in this question: Accessing protocol property in Swift class.
But in controllingView, calling delegate.propertyINeedToChange is nil.
How do I change a delegate's property from the delegating object?
Here is the code:
class MainViewController : UIViewController {
var controllingView = ControllingView()
let presentingView = PresentingView()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
view.addSubview(controllingView)
view.addSubview(presentingView)
self.view = view
controllingView.delegate = presentingView
}
}
class ControllingView: UIView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
//ControlsView Setup
self.backgroundColor = UIColor(displayP3Red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0)
setupViews()
}
let testSLDR = UISlider()
var delegate: ControlsViewDelegate?
func setupViews() {
self.addSubview(testSLDR)
testSLDR.addTarget(self, action: #selector(testSLDRchanged), for: .valueChanged)
}
#objc func testSLDRchanged() {
delegate?.button?.backgroundColor = UIColor.red
}
}
class PresentingView: UIView, ControlsViewDelegate {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
let button = Button()
self.addSubview(button)
}
var button: Button?
}
protocol ControlsViewDelegate {
var button: Button? { get set }
}
class Button: UIButton { ... }
As the views are initialized in the same view controller you don't need protocol / delegate
Delete the protocol and the associated code
In ControllingView declare a weak Button property
weak var presentingButton : Button?
Replace the line to set the delegate with a line to assign the button of PresentingView to the presentingButton property
controllingView.delegate = presentingView
controllingView.presentingButton = presentingView.button
In the action change the color
#objc func testSLDRchanged() {
presentingButton?.backgroundColor = UIColor.red
}

iOS - UIButton become first responder to open keyboard

I need to open keyboard on button click for UIButton (not using/for UITextField). I have tried to create custom button by overriding variable canBecomeFirstResponder but it's not working.
Is there any other way to do so?
Note: I want to set UIPIckerView as an input view of UIButton in key board frame.
Here is my code.
class RespondingButton: UIButton {
override var canBecomeFirstResponder: Bool {
return true
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
// common init
}
}
In my view controller, I connected button action.
class TestViewController: UIViewController {
#IBAction func testBecomeFirstResponder(button: RespondingButton){
button.becomeFirstResponder() // Not working.
}
}
Here is what I would do.
Create transparent textField 1x1px, lets say it is myTextField.
Then add your desired button. In the button action make the myTextField.becomeFirstResponder().
Create view:
let pvBackground: UIView = {
let v = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
v.backgroundColor = .white
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
In viewDidLoad:
pvBackground.addSubview(yourPickerView)//add the picker into the pvBackground
myTextField.inputView = pvBackground
I added the pickerView into the another view to be able to customize it more.
Add conformance to UIKeyInput like this. It should work.
class RespondingButton: UIButton, UIKeyInput {
override var canBecomeFirstResponder: Bool {
return true
}
var hasText: Bool = true
func insertText(_ text: String) {}
func deleteBackward() {}
}

Custom UIButton setSelected weird behavior

I'm new to swift and I'm just trying to create a subclass of uibutton. Except that I have this weird blue rounded rect appearing when the button is selected as shown below. When all I want is a nice white border.
The code of my class :
import UIKit
import QuartzCore
#IBDesignable
class ColorButton: UIButton {
//MARK: PROPERTIES
#IBInspectable var stickerColor: UIColor = UIColor.whiteColor() {
didSet {
configure()
}
}
override var selected: Bool {
willSet(newValue) {
super.selected = newValue;
if selected {
layer.borderWidth = 1.0
} else {
layer.borderWidth = 0.0
}
}
}
//MARK: Initializers
override init(frame : CGRect) {
super.init(frame : frame)
setup()
configure()
}
convenience init() {
self.init(frame:CGRectZero)
setup()
configure()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
configure()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
configure()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
configure()
}
func setup() {
//Border color
layer.borderColor = UIColor.whiteColor().CGColor
//Corner Radius
setUpCornerRadius()
}
func configure() {
backgroundColor = stickerColor
}
override func layoutSubviews() {
super.layoutSubviews()
setUpCornerRadius()
}
func setUpCornerRadius() {
layer.cornerRadius = CGRectGetWidth(bounds) * 0.205
}
}
I have checked your code. and I got same issue.
but If you set button type as Custom then this problem will not occur
Output :
Found something for buttonType :
You may find the discussion at CocoaBuilder's thread How to subclass UIButton? helpful, particularly Jack Nutting's suggestion to ignore the buttonType:
Note that this way the buttonType isn't explicitly set to anything,
which probably means that it's UIButtonTypeCustom. The Docs don't
seem to actually specify that, but since that's the 0 value in the
enum, that's likely what happens (and that seems to be the observable
behavior as well)
Source : https://stackoverflow.com/a/10278515/3202193

Resources