Button in center of cell programatically - ios

I am trying to make it so that there is a 'Reset Progress' button inside the centre of a cell. Other posts I have found only show how to add a button on the left side or the right side, or require prior steps in the Interface Builder.
How can I add a button in the centre of a cell programmatically without any steps in the Interface Builder?

class YourCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(button)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var button: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
return button
}()
override func layoutSubviews() {
super.layoutSubviews()
button.frame = CGRect(x: 0, y: 0, width: 150, height: 50)
button.center = self.center
}
#objc func buttonAction() {
print("Button has been pressed")
}
}

Download a library called "TinyConstraints" which is a standard in iOS App Development.
Import it into your SWIFT File.
Add a subview of that button to your tableView Cell.
Then try something like: Button.centreXAxisInSuperView() or YAxis if you need be, or both... that'll center it for sure.

Related

How to make UIButton clickable outside frame of it's grand parent view

I have a series of buttons that exist outside the frame of its grand parent view. These buttons are not able to be clicked now, and I am not able to move the buttons, so how can I make them clickable outside the frame of the grand parent view? The button exists inside the a small circular UIView, and that UIView lives outside of the frame of it's parent view. I've tried using a hit test but it is still not triggering
Here is my button:
class ButtonNode: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect, agree: Bool) {
self.init(frame: frame)
setupView()
}
required init(coder aDecoder: NSCoder) {
fatalError("This class does not support NSCoding")
}
func setupView(){
self.setTitle("+10", for: .normal)
self.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
self.setTitleColor(.lightGray, for: .normal)
self.isUserInteractionEnabled = true
self.layer.borderWidth = 1.0
self.layer.borderColor = UIColor.lightGray.cgColor
self.layer.cornerRadius = 15
}
}
This is the setup in the parent view:
var rightLastNodeButton:UIButton?
var leftLastNodeButton:UIButton?
leftButton = ButtonNode(frame: CGRect(x: leftX, y: y, width: width, height: height), agree: false)
rightButton = ButtonNode(frame: CGRect(x: rightX, y: y, width: width, height: height), agree: false)
leftButton?.addTarget(self, action: #selector(disagreeUsers), for: .touchUpInside)
rightButton?.addTarget(self, action: #selector(agreeUsers), for: .touchUpInside)
view.addSubview(leftButton!)
view.addSubview(rightButton!)
#objc func agreeUsers(){
delegate?.showParticipantsPressed(agree: true)
}
#objc func disagreeUsers(){
delegate?.showParticipantsPressed(agree: false)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if(rightButton!.frame.contains(point)) {
return rightButton
}
if(leftButton!.frame.contains(point)){
return leftButton
}
return super.hitTest(point, with: event)
}
I had a similar issue and what worked for me was bringing the buttons to the front of the subview. Then it would work.
view.bringSubiewToFront(exampleButton)
or sending the other subviews back
view.sendSubViewToBack(viewlayer)

Swift 4. iOS 13. UIButton inside a UITableViewCell - how to touch and scroll?

I am going to create a dictionary app with a list of words and their translations. My idea is next - when to click / touch the word (text on the UIButton) - the word will be voiced. But I see the issue with scrolling the UITableView - I can scroll it only if I touch the delimiter between table rows
let srollView = UIScrollView()
let tableRect = CGRect(x: 0, y: 0, width: listContentWidth, height: listContentHeight)
myTableView = UITableView(frame: tableRect, style: UITableView.Style.plain)
myTableView.register(ListTableViewCell.self, forCellReuseIdentifier: cellId) //Registration of my Custom ListTableViewCell
myTableView.dataSource = self
myTableView.delegate = self
myTableView.delaysContentTouches = true;
myTableView.canCancelContentTouches = true;
srollView.addSubview(myTableView)
How to use UIButtons inside of the UITableViewCell. which I create programmatically:
class ListTableViewCell: UITableViewCell {
private let textBtn: UIButton = {
let btn = UIButton()
//...
return btn
}()
private let translationBtn: UIButton = {
let btn = UIButton()
//...
return btn
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let stackView = UIStackView(arrangedSubviews: [
textBtn,
translationBtn
])
stackView.alignment = .fill
stackView.distribution = .fillEqually
stackView.axis = .horizontal
stackView.spacing = 5
stackView.translatesAutoresizingMaskIntoConstraints = false
//...
addSubview(stackView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You need to add target for that button.
textBtn.addTarget(self, action: #selector(yourFunction(sender:)), for: .touchUpInside)
And of course you need to set tag of that button since you are using it.
textBtn.tag = indexPath.row
To get the tag in your function:
#objc func yourFunction(sender: UIButton){
let buttonTag = sender.tag
}
Some things to consider:
You need to add the subview to the cells contentView and not to the cell itself.
Cells are being reused: so subclass UITableViewCell and add the button to its initializer.

Swift: Custom UIButton Class in View Controller Touch Event Not Trigger?

I created a custom UIButton class as so:
class CustomButton: UIButton
{
required init(frame: CGRect, title: String, alignment: NSTextAlignment)
{
super.init(frame: frame)
// Set properties
// self.addTarget(self,
// action: #selector(touchCancel),
// for: .touchUpInside)
}
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
// #objc fileprivate func touchCancel()
// {
// print("TOUCHED")
// }
}
In my main UIViewController, I have the following implementation:
class MainViewController: UIViewController
{
fileprivate var customBtn: CustomButton {
let frame = CGRect(x: 48.0,
y: 177.0,
width: 80.0,
height: 40.0)
let custom = CustomButton(frame: frame,
title: "Test",
alignment: NSTextAlignment.right)
return custom
}
override func viewDidLoad()
{
super.viewDidLoad()
view.addSubView(customBtn)
customBtn.addTarget(self,
action: #selector(touchCancel),
for: .touchUpInside)
}
#objc public func touchCancel()
{
print("TOUCHED")
}
}
However, adding a target to customBtn in my main UIViewController does not get triggered. As shown in the CustomButton class with the commented out code, I can add a target there, which does get triggered.
I'm just wondering why a defined function in another class cannot be used to add as a target to a custom UIButton?....or maybe my implementation is incorrect?
Thanks!
You may need a closure not a computed property
lazy var customBtn: CustomButton = {
let frame = CGRect(x: 48.0, y: 177.0, width: 80.0, height: 40.0)
let custom = CustomButton(frame: frame, title: "Test",alignment: NSTextAlignment.right)
return custom
}()
Here inside MainViewController
customBtn.addTarget(self,
action: #selector(touchCancel),
for: .touchUpInside)
you add the target to a newly created instance not to the one you added as a subview and it's the main difference between your implementation ( computed property ) and closure

IBDesignable Subclass of TextField renders to IB but not to simulator / device

I created a subclass of UITextField that adds a floating button to the right hand side of the text-field. It's all good in the IB, but for some reason the button image does not show up in the simulator or on the device.
Using the view debugger, I can see the button is there, right where it is supposed to be. I can even tap it and get the target action to trigger. However, the image is not visible on the screen.
I tried messing with the clipsToBounds properties of both the TextView and the button to no avail.
I also know the image asset is working, because I made an an image view and set the image to the same image asset, and it appears just fine. The class for the TextField is below:
#IBDesignable
class ButtonedTextField: UITextField {
#IBInspectable var buttonImage: UIImage?
var button: UIButton?
var buttonAction: (() -> ())?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
configure()
}
#objc private func buttonActionWrap() {
buttonAction?()
}
private func configure() {
let button = UIButton(type: .custom)
button.addTarget(self, action: #selector(buttonActionWrap), for: .touchUpInside)
let height = self.frame.height
let buttonHeight = height - 10
button.frame = CGRect(x: self.frame.width - (buttonHeight + 10), y: 5, width: buttonHeight, height: buttonHeight)
button.setImage(buttonImage, for: .normal)
self.button = button
self.addSubview(button)
bringSubview(toFront: button)
}
}
Any thoughts?

UIButton will not respond

I'm currently working through Apple's Swift tutorial. In it, i am trying to make a custom button respond to tap and in turn print to the console. It seems to not be responding at all to any taps, or at the very least will not print it's response to the console.
Code is below, if anymore is needed please let me know.
import UIKit
class RatingControl: UIView {
//MARK: Initializaion
required init?(coder aDecoder: NSCoder) { // overrides it's superclass implementation of the initializer
super.init(coder: aDecoder)
let button = UIButton(frame: CGRect(x:0, y:0, width: 44, height: 44))
button.backgroundColor = UIColor.redColor()
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)
addSubview(button)
func intrensicContentSize() -> CGSize {
return CGSize(width: 240, height: 44)
}
}
//MARK: Button Action
func ratingButtonTapped(button:UIButton) {
print("will it print?")
}
}
Please try .TouchUpInside instead of TouchDown
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchUpInside)

Resources