iOS Button not work in custom view - ios

There are two custom views - viewA and viewB.ViewB is a small view added in viewA. At first viewA is filled in the whole screen. ViewB is located in the bottom of viewA(out of the screen). When click a button in viewA, viewB bottom constant of constraints will be -100, thus viewB will display in the bottom of the screen. But there is a button in viewB did not response its selector. Here is my code:
In ViewA
let viewB: ViewB = {
let view = ViewB(
view.setup()
return view
}()
viewB constraints:
viewB.snp.makeConstraints { (make) in
make.trailing.leading.equalTo(self)
make.height.equalTo(100)
make.top.equalTo(self.snp.bottom)
}
when click button to arouse viewB
UIView.animate(withDuration: 0.5) {
self.snp.updateConstraints({ (make) in
make.bottom.equalTo(-100)
})
}
self.layoutIfNeeded()
In viewB:
class ViewB: UIView {
let b: UIButton = {
let button = UIButton(type: UIButtonType.custom)
button.addTarget(self, action: #selector(btnClicked), for: UIControlEvents.touchUpInside)
button.backgroundColor = UIColor.green
button.setTitle("Button", for: .normal)
return button
}()
func btnClicked() {
print("btnClicked")
}
func setup() {
addSubview(b)
b.snp.makeConstraints { (make) in
make.leading.top.bottom.equalTo(self)
make.width.equalTo(100)
}
}
}

Your code by itself works fine. So the issue is probably something like the button being overlaid by another view which takes the touch actions. You can test this using the view debugger or provide a link to your project so one of us can take a look to see what is going on.

i think , your view is going out of its super View or Any other view is coming on its upper layer. please see by this
superview.clipsToBounds : YES

Related

addArrangedSubview vs addSubview

I'm newbie and I've wrote a customView inherited from StackView and I created a button programmatically with few attributes and when I add it to my custom view, I have two problems:
If I use addArrangedSubview(myBtn), my view ignores attributes that
I added and fills the whole width. But if I use addSubView(myBtn),
It's ok(a blue square in 44x44)
If I use addArrangedSubview(myBtn), addTarget() not works and
myBtn is not clickable, but when I use addSubView(myBtn), It works
perfectly.
Here is my custom view class:
import UIKit
class RatingControl: UIStackView {
//MARK: Initialization
override init(frame: CGRect) {
super.init(frame: frame)
setupButtons()
}
required init(coder: NSCoder) {
super.init(coder:coder)
setupButtons()
}
//MARK: Private Methods
private func setupButtons() {
// Create the button
let button = UIButton()
button.backgroundColor = UIColor.blue
// Add constraints
button.translatesAutoresizingMaskIntoConstraints = false
button.heightAnchor.constraint(equalToConstant: 44.0).isActive = true
button.widthAnchor.constraint(equalToConstant: 44.0).isActive = true
// Setup the button action
button.addTarget(self, action: #selector(ratingButtonTapped(_:)), for: .touchUpInside)
// Add the button to the stack
addArrangedSubview(button)
}
//MARK: Button Action
#objc func ratingButtonTapped(_ sender: Any) {
print("Button pressed 👍")
}
}
Here is the preview:
What's difference between addSubView() and addArrangedSubview()? why these problems happens?
I'm assuming you want to add several buttons horizontally (such as with a typical "stars" rating control).
A UIStackView, as might be guessed from its .addArrangedSubview() method, arranges its subviews, based on its .axis, .alignment, .distribution and .spacing properties, as well as its frame.
So, do some reading about UIStackView and how it can be used. Most likely, you are currently constraining your custom view with:
top
leading
trailing (or width)
So adding your button as an arrangedSubView results in it stretching to the width of the stack view, because that's the default.
Adding it as a subview simply overlays the button on the stack view, instead of allowing the stack view to arrange it, and your stack view likely then has a height of zero -- so the button cannot be tapped.
Try setting only top and leading constraints when you add your custom stack view. That should give you a 44 x 44 button that can be tapped.
As you add more buttons using .addArrangedSubview(), those buttons will be arranged horizontally, which is probably what you want.

How can I change view UIScrollVIew by paging Mode?

I made a UIScrollView and add 2 SubViews.(View1, View2)
So, I can page down if i swipe because i set .isPagingEnabled = true.
And now I make a one button in View1.
What I want to do is change View2 when i click this button.
To be specific, change view by paging mode.(not like scrolling)
button.addTarget(self, action: #selector(downBtnTapped), for: .touchUpInside)
#objc func downBtnTapped() {
if verticalScroll.contentOffset.y < self.view.bounds.height * CGFloat(2) {
verticalScroll.contentOffset.y += self.view.bounds.height
}
}
if i tried upper code, just chnage view directly, not like paging Mode
How can i solve this problem ?

Place a UIButton at bottom of UIScrollView with constraints

I have a view with three textfield/textview fields in it, and in order to make the view scrollable when the keyboard appears, I have put all the elements inside a scrollview. The elements where not outside the frame before, so the contentSize should be the same size as the full screen size and then when the keyboard appears, so when the keyboard appears i update the bottom constraints for the scrollview to be -keyboardHeight from the view bottom and then it is scrollable above the keyboard..
This all works fine, the problem is adding a button to the bottom of the scrollview that leading/trailing to the sides and bottom of the view.
See pictures:
Current view, with button hidden behind navigation bar
Where i would like the button to be. Approx 20 margin to right.left.bottom
I am using SnapKit to set my constraints, and for the button I would like to do something like this:
sharebutton.snp.makeConstraints { (make) in
make.width.left.right.equalToSuperview()
make.bottom.equalToSuperview().offset(-20)
}
(The Superview/the scrollview is already set as 20 margin from sides)
//EDIT: Code added ->
override func viewDidLayoutSubviews() {
scrollview.contentSize = CGSize(width: centerView.frame.width, height: view.frame.height)
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "title"
view.backgroundColor = .white
view.addSubview(scrollview)
scrollview.addSubview(sharebutton)
scrollview.addSubview(subjectField)
scrollview.addSubview(messageField)
scrollview.addSubview(datepicker)
scrollview.addSubview(addressTable)
addressTable.dataSource = self
addressTable.delegate = self
addressTable.separatorStyle = .none
addressTable.keyboardDismissMode = .onDrag
addressTable.separatorStyle = .singleLineEtched
subjectField.placeholder = "content"
datepicker.setTitle("topbutton", for: .normal)
datepicker.setTitleColor(.black, for: .normal)
datepicker.setTitleColor(UIColor.ME.border, for: .highlighted)
datepicker.titleLabel?.font = UIFont.ME.button
datepicker.layer.borderWidth = 1
datepicker.layer.cornerRadius = 3
datepicker.layer.borderColor = UIColor.ME.border.cgColor
datepicker.addTarget(self, action: #selector(showDates), for: .touchUpInside)
sharebutton.setTitle("Share", for: .normal)
sharebutton.backgroundColor = UIColor.ME.buttonMainBlue
sharebutton.addTarget(self, action: #selector(shareClicked), for: .touchUpInside)
scrollview.backgroundColor = .red
scrollview.snp.makeConstraints { (make) in
make.top.bottom.equalToSuperview()
make.left.width.right.equalTo(centerView)
}
datepicker.snp.makeConstraints { (make) in
make.top.equalToSuperview().offset(paddingGlobal)
make.left.width.right.equalToSuperview()
make.height.equalTo(50)
}
addressTable.snp.makeConstraints { (make) in
make.top.equalTo(datepicker.snp.bottom)
make.left.right.equalTo(datepicker)
make.height.equalTo(200)
}
subjectField.snp.makeConstraints { (make) in
make.top.equalTo(datepicker.snp.bottom).offset(20)
make.left.right.equalToSuperview()
}
messageField.snp.makeConstraints { (make) in
make.top.equalTo(subjectField.snp.bottom).offset(20)
make.height.equalTo(200)
make.left.right.equalToSuperview()
}
sharebutton.snp.makeConstraints { (make) in
make.width.left.right.equalToSuperview()
make.bottom.equalToSuperview().offset(-20)
}
}
Any thoughts ?
You need to add a UIView (for ex name it containerView) inside a scrollView subview first then add all your uielement(eg. textfield/textview, UIButton) to the subView of that containerView.
as Govind commented, I could solve it by placing my subviews in a container view.
Using StoryBoard and Constaint Xcode 11.5 iOS 13
StoryBoard View Controller Scene

UIScrollView with child UIView (holds content) not detecting taps

I'm hitting a wall. I have a UIScrollView with a child UIView (contentView) which contains the content and a button. The button is not detecting any taps. I've tested many methods, creating the button programmatically, using storyboard, and creating a UITapGestureRecognizer in the contentView... still nothing. From what I understand, UIScrollView does not delegate any touch events to it's children. How do I solve this?
You can create the button programmatically then you add it as a subview for your contentView.
let button = UIButton()
button.frame = CGRectMake(contentView.center.x-20.0, contentView.center.y-20.0, 40.0, 40.0)
button.addTarget(self, action: "handleTap", forControlEvents: UIControlEvents.TouchUpInside)
button.setTitle("Title", forState: UIControlState.Normal)
contentView.addSubview(button)
On the action you can handle the tap
func handleTap() {
//Do whatever you want
print("Button tapped")
}
I tested it using a scrollView and a UIView inside the scrollView

Add button on top of UITableViewController (Swift)

I am trying to add a button ontop of a uitableview controller table view. The view controller has a navigation controller and static cells, which is why it is a uitableviewcontroller and not a uiviewcontroller. Now I am trying to add a button at the bottom of the screen that is attached to the navigation controller so that it doesn't scroll with the table view.
I am trying to make something similar to what is below. It has a navigation controller for the top bar, a table view with static cells and then a button, but how did they do the button?
Image: http://postimg.org/image/ilsmqqrip/
Thanks!
UPDATE: How can I use a uiviewcontroller with a tableview with static cells using Swift?
I find Container Views very useful in this scenario! A clean solution and very easy to implement.
Just create a normal UIViewController, add your button and a ContainerView as subviews of this UIViewController (the middle one in the image below). Finally create Embed Segue from ContainerView to your UITableViewController (the one on the right).
This way you can use static cell prototypes, not being limited only to UITableView at the same time.
Result:
there is a better solution for this. you can do this by disabling the Auto Layout(button.translatesAutoresizingMaskIntoConstraints = false) property of the corresponding Button or any UIView for floating button:
Swift 4
//create a button or any UIView and add to subview
let button=UIButton.init(type: .system)
button.setTitle("NEXT", for: .normal)
button.frame.size = CGSize(width: 100, height: 50)
self.view.addSubview(button)
//set constrains
button.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
button.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
button.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
} else {
button.rightAnchor.constraint(equalTo: tableView.layoutMarginsGuide.rightAnchor, constant: 0).isActive = true
button.bottomAnchor.constraint(equalTo: tableView.layoutMarginsGuide.bottomAnchor, constant: -10).isActive = true
}
I did something similar with UITableViewController and a static datasource. I added the button in the footerview of my tableview.
To make it align to the bottom of the screen i needed this code in my viewcontroller:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Make footerview so it fill up size of the screen
// The button is aligned to bottom of the footerview
// using autolayout constraints
self.tableView.tableFooterView = nil
self.footerView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.tableView.frame.size.height - self.tableView.contentSize.height - self.footerView.frame.size.height)
self.tableView.tableFooterView = self.footerView
}
In short, I resize the footerview to take up all the remaining space after the contentsize of the table view is removed. Since the button is aligned to the bottom of the footerView with autolayout, it will stay in the bottom of the screen.
The Storyboard:
Here is the result:
The UITableViewController will take up the whole space, so you won't be able to add the button. Refactor your UITableViewController based code into UIViewController with UITableView manually added. This way you will be able to set the size of your table view and put the button to the bottom.
Unfortunately UITableViewController has a tableView as its top level view. Of course if you look in the view debugger you can see that the tableview is not the root view. Therefore you can add the buttons to the tableView's window programatically. If you have to do it after the fact, this is probably the easiest way to add a top level element over a UITableViewController. Otherwise if you are doing it in the initial design, you can use container view for your buttons and a UITableViewController for the TableView. The downside of this approach is you end up with two view controllers, one for the container and one for the table and its often necessary to pass information back and for between them. If you are using swift you can simplify this by nesting the tableViewcontroller inside the container view controller class.
If you want to add a button to the window, you can do this lazily once you are sure that the view has a window. Note that the buttons belong to the window and not to the view controller, so its your responsibility to remove them when the view controller disappears.
private weak var button: UIButton!
...
override func didMove(toParentViewController parent: UIViewController?) {
super.didMove(toParentViewController: parent)
guard self.button == nil, let window = tableView.window else {
return
}
let button = UIButton(frame: CGRect(x:0, y:40, width: 200, height: 20))
button.setTitle("This is a red button", for: .normal)
button.backgroundColor = UIColor.red
window.addSubview(button)
self.button = button
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
button?.removeFromSuperview()
}
Step 1 :-
Drag and drop one uiview to UITable View Controller (Static)
Automatically it sticks to the bottom.
If you need to, you can also add two buttons inside UIView... It depends on your requirements.
Step 2 :-
Connect the outlet for uiview (outletView)
Step 3 :-
Add this below code in View Will Appear.
override func viewWillAppear(_ animated: Bool) {
outletViewBottom.backgroundColor = .red
tableView.addSubview(outletViewBottom)
// set position
outletView.translatesAutoresizingMaskIntoConstraints = false
outletView.leftAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.leftAnchor).isActive = true
outletView.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor).isActive = true
outletView.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor).isActive = true
outletView.widthAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.widthAnchor).isActive = true
outletView.heightAnchor.constraint(equalToConstant: 50).isActive = true // specify the height of the view
}
Step 4 :-
Now run the code... Happy coding.
all you need to do is to add your Top view whichever it is to the navigationController.view like so:
self.navigationController?.view.addSubview(YOUR_TOP_VIEW)
so if you need a sticky button/view etc... on top of TableViewController which does not scroll with tableView, use this approach.
Here is a UIViewController, with a UITableView added as a subview. At the top right, you can see a dropdown that says Content: Dynamic Prototypes. Change it to Static Cells.

Resources