UIbutton inside UIViewControllers inside UIScrollView not getting triggered on touch - ios

I'v added two UIViewControllers inside of a UIScrollView, and now I'm trying to add targets to the button inside of the UIViewControllers, I've checked the internet but none of those solutions worked for me, this is what I'm doing
inside of the main ViewController
scrollView.contentSize = CGSize(width: view.frame.width * 2, height:0)
let postsViewController = PostsViewController()
postsViewController.scrollView = scrollView
postsViewController.view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
let chatsViewController = ChatsViewController()
chatsViewController.scrollView = scrollView
chatsViewController.view.frame = CGRect(x: view.frame.width, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(postsViewController.view)
scrollView.addSubview(chatsViewController.view)
postsViewController.didMove(toParent: self)
chatsViewController.didMove(toParent: self)
then inside the postsViewController I'm doing this
let a = UIButton()
a.setImage(currentTheme.chat, for: .normal)
a.imageEdgeInsets = UIEdgeInsets(top: 1.5, left: 0.0, bottom: 1.5, right: 0.0)
view.addSubview(a)
view.addConstraint("V:|-200-[v0(80)]-0-|",a)
view.addConstraint("H:|-200-[v0(80)]-0-|",a)
a.addTarget(self, action: #selector(abc), for: .touchUpInside)
the add "addConstraint" is an extension function just to add constraint to views
the abc function
#objc func abc() {
print("hello")
}
you can see the scrollView setting here
https://ibb.co/ZB1LJsy

Try to initialize your button like this
let a : UIButton = UIButton(type: .custom)
And add this after to the initialize of your UIScrollView
scrollView.delaysContentTouches = false

I tested in an xcode project. I can not execute the function (button) in the other UIViewController.
By cons if you sent the #selector it works.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let scrollView : UIScrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.width))
scrollView.delaysContentTouches = false
view.addSubview(scrollView)
let TestViewController = TestViewController1()
TestViewController.select = #selector(demande(sender:))
TestViewController.view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(TestViewController.view)
print("dd")
}
#objc func demande(sender: UIButton!) {
print("button click", sender.tag)
}
}
class TestViewController1: UIViewController {
var select : Selector!
override func viewDidLoad() {
super.viewDidLoad()
let button : UIButton = UIButton(type: .custom)
button.setImage(#imageLiteral(resourceName: "turn_off_on_power-512"), for: .normal)
button.tag = 2
button.addTarget(self, action: select, for: .touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
view.addSubview(button)
}
}
Hoping that it helps you

okay, I solved my problem, the reason why the button wasn't getting trigger is because I forgot to attach the viewController of the view to the scrollview, so all I had to do is to attach the viewController as well and it worked.
self.addChild(postsViewController)
self.addChild(chatsViewController)
now it is working.

Related

Navigation item in my UIViewController is overlapping child views and labels

I am adding custom navigation item to my application. But every time I navigate the items of navigation item overlaps. My code is
func fixNavBar(){
self.navigationItem.setHidesBackButton(true, animated: true)
let nav = self.navigationController?.navigationBar
let navView = UIView(frame: CGRect(x: 0, y: 0, width: (nav?.frame.width)!, height: (nav?.frame.height)!))
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: navView.frame.height, height: navView.frame.height))
backButton.imageView?.contentMode = .scaleToFill
backButton.setImage(UIImage(systemName: "chevron.left"), for: .normal)
backButton.setTitleColor(UIColor(rgb: 0x23C0FF), for: .normal)
backButton.tintColor = UIColor(rgb: 0x23C0FF)
nav?.addSubview(navView)
backButton.addTarget(self, action: #selector(goBack), for: .touchUpInside)
navView.backgroundColor = .clear
let imageView = UIImageView(frame: CGRect(x: backButton.frame.width+5, y: 0, width: navView.frame.height-2, height: navView.frame.height-2))
let profUrl = URL(string: "\(selectedUser.profilePictuer)")
imageView.kf.setImage(with: profUrl)
let userLbl = UILabel(frame: CGRect(x: backButton.frame.width + 15 + imageView.frame.width, y: 0, width: 150, height: navView.frame.height))
userLbl.font = UIFont(name: UIFont.fontNames(forFamilyName: "Ubuntu")[0], size: 17)
userLbl.text = selectedUser.fullName
userLbl.textAlignment = .left
userLbl.textColor = .black
navView.addSubview(imageView)
navView.addSubview(userLbl)
navView.addSubview(backButton)
imageView.layer.cornerRadius = imageView.frame.height/2
imageView.layer.masksToBounds = true
}
#objc func goBack(sender: UIButton!) {
self.navigationController!.popViewController(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
fixNavBar()
}
This is root view controller when where I select any chat to open
When I select chat for first time I get something like that
And when select second chat it does not remove previous user's name but overlaps it
Your root and child view controller has the same navigationcontroller so when everytime you call fixNavBar , some views appending on the previous .
First option is adding nav?.subviews.forEach({$0.removeFromSuperview()}) on the top of your function like #Raja's comment.
Second is go storyboard and embed a new navigationController to your child viewcontroller(where yout function is)

How to create Onboarding\Walkthrough swift

I'm trying to create a welcome onboarding for the first time users but none of the views are loafing in the simulator, all I'm getting is a red background when the onboardingVC gets presented. Can anyone see the issue as to why the titles, buttons, and images won't appear?
This is the message I'm getting in the console:
Warning: Attempt to present <EMA.WalkthroughVC: 0x7faa2401e5b0> on <EMA.HomeVC: 0x7faa22407e00> whose view is not in the window hierarchy!
FOUND ALL!!
let holderView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = true
view.backgroundColor = .darkGray
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.backgroundColor = UIColor.red
configure()
}
private func configure() {
let scrollView = UIScrollView(frame: holderView.bounds)
holderView.addSubview(scrollView)
let titles = ["Hi","Welcome","real nigga"]
for x in 0..<3 {
let pageView = UIView(frame: CGRect(x: CGFloat(x) * holderView.frame.size.width, y: 0, width: holderView.frame.size.width, height: holderView.frame.size.height))
scrollView.addSubview(pageView)
let label = UILabel(frame: CGRect(x: 10, y: 10, width: pageView.frame.size.width-20, height: 120))
let imageView = UIImageView(frame: CGRect(x: 10, y: 10+120+10, width: pageView.frame.size.width-20, height: pageView.frame.size.height - 60 - 130 - 15))
let button = UIButton(frame: CGRect(x: 10, y: pageView.frame.size.height - 60, width: pageView.frame.size.width-20, height: 50))
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
pageView.addSubview(label)
label.text = titles[x]
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "BankCard\(x)")
pageView.addSubview(imageView)
button.setTitleColor(.red, for: .normal)
button.backgroundColor = .black
button.setTitle("Continue", for: .normal)
if x == 2 {
button.setTitle("Get Started", for: .normal)
}
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
pageView.addSubview(button)
}
}
#objc func didTapButton(_ button: UIButton) {
}
}
"whose view is not in the window hierarchy"
you didn't add the views that you created to the main view try to add the subviews to the main by using this one
self.view.addSubview(holderView)
also don't forget to add the frame for the holder view like that
UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
view.translatesAutoresizingMaskIntoConstraints = true
and inside the view did load
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.view.addSubview(holderView)
}

Why is my button not working in Swift Playgrounds?

I am trying to make a playground and I have a button that says "Let's play!" and moves into a new view controller.
I looked at the code from this website and put it into my code:
http://lab.dejaworks.com/ios-swift-3-playground-uibutton-action/
This is all of my code (like, all of it):
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
//Introduction
let view = UIView()
view.backgroundColor = .red
//title
func labelCool() {
let label = UILabel()
label.frame = CGRect(x: 50, y: 300, width: 400, height: 100)
label.text = "Add-Add - A Wonderful Game!"
//label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.numberOfLines = 3
label.font = UIFont(name: "HelveticaNeue-Bold", size: 30)
UILabel.animate (withDuration: 10.0, animations:{
label.textColor = .black
})
UILabel.animate(withDuration: 5.0, animations:{
label.textColor = .blue
})
view.addSubview(label)
}
labelCool()
//subtitle
let subtitle = UILabel()
subtitle.frame = CGRect(x: 50, y: 400, width: 200, height: 50)
subtitle.text = "Curated and Created by Yours Truly, Adit Dayal!"
subtitle.numberOfLines = 4
self.view = view
view.addSubview(subtitle)
}
override func viewDidLoad() {
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
let responder = Responder()
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
view.addSubview(button)
}
}
class gameViewController: UIViewController {
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
For now, I just want the button to display "Yay!" when clicked, but it is doing nothing!
Does anyone know why? (I'm on a bit of a time constraint)
Thank you so much,
Adit Dayal
Your Responder class is inside the viewDidLoad() function put the class outside like so
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
override func viewDidLoad() {
let responder = Responder()
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(responder.action), for: .touchUpInside)
view.addSubview(button)
}
The problem is that you are creating the responder object inside the viewDidLoad, as a local variable; this cause the object to be destroyed when the function ends (but we want that object alive even after). You have to retain that object, so instead of creating a local variable, create an instance variable by simply saving it as a class scope:
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
let responder = Responder() // this is now outside the viewDidLoad, so it's an instance variable
override func viewDidLoad() {
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
view.addSubview(button)
}

Swift Content Tabs?

I am building an app and I am required to have 3 tabs if you click on the first tab, its a tableview, second tab a different tableview, third tab, TextView, here is an image of what I am trying to do:
Every time I google looking for examples of something like this, I get referred to UITabBarController, I don't think a tab bar is what I am looking for.
What you are looking for is called Segmented Control (UISegmentedControl).
You can see it in Action natively e.g. in both the Apple iTunes and Health App.
Instead of performing segues to different views with the UITabBarController, you can, using Interface Builder, connect it to your UIViewController like so
#IBOutlet weak var segmentedControl: UISegmentedControl!
and in
viewDidLoad() {
switch segmentedControl.selectedIndex {
case 0: // Do something on your first picture
someFunction()
case 1: // Do something on your second picture
performSegue(withIdentifier: "your identifier here", sender: nil)
case 2: // Do something on your third picture
image.isHidden = true
button.isEnabled = false
default: break
}
... etc. You could also initiate different View Controllers instead of manipulating just one View, which you can then access via segues.
Please see official Swift doc # https://developer.apple.com/documentation/uikit/uisegmentedcontrol?changes=_3
I would create this layout programmatically. You want a custom look to it so I do not think the standard controls are your best option.
Here is a playground to get you started on one way this could be achieved:
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
let view1 = UIView(frame: CGRect(x: 0, y: 100, width: 768, height: 924))
let view2 = UIView(frame: CGRect(x: 0, y: 100, width: 768, height: 924))
let view3 = UIView(frame: CGRect(x: 0, y: 100, width: 768, height: 924))
override func viewDidLoad() {
super.viewDidLoad()
self.view.frame = CGRect(x: 0, y: 0, width: 768, height: 1024)
self.view.backgroundColor = .black
// View to have a border around the buttons
let box = UIView(frame: CGRect(x: 40, y: 20, width: 300, height: 50))
box.layer.borderColor = UIColor.white.cgColor
box.layer.borderWidth = 2
self.view.addSubview(box)
// Tab buttons
let button1 = UIButton(frame: CGRect(x: 40, y: 20, width: 100, height: 50))
button1.setTitle("Orange", for: .normal)
button1.tag = 1
button1.addTarget(self, action: #selector(tabTouched(sender:)), for: .touchUpInside)
self.view.addSubview(button1)
let button2 = UIButton(frame: CGRect(x: 140, y: 20, width: 100, height: 50))
button2.setTitle("Blue", for: .normal)
button2.tag = 2
button2.addTarget(self, action: #selector(tabTouched(sender:)), for: .touchUpInside)
self.view.addSubview(button2)
let button3 = UIButton(frame: CGRect(x: 240, y: 20, width: 100, height: 50))
button3.setTitle("Green", for: .normal)
button3.tag = 3
button3.addTarget(self, action: #selector(tabTouched(sender:)), for: .touchUpInside)
self.view.addSubview(button3)
// Tab Views
view1.backgroundColor = .orange
self.view.addSubview(view1)
view2.backgroundColor = .blue
view2.alpha = 0
self.view.addSubview(view2)
view3.backgroundColor = .green
view3.alpha = 0
self.view.addSubview(view3)
}
// When each of the buttons are tapped we will hide or show the correct tab's view
#objc func tabTouched(sender: UIButton) {
if sender.tag == 1 {
UIView.animate(withDuration: 0.3) {
self.view1.alpha = 1
self.view2.alpha = 0
self.view3.alpha = 0
}
} else if sender.tag == 2 {
UIView.animate(withDuration: 0.3) {
self.view1.alpha = 0
self.view2.alpha = 1
self.view3.alpha = 0
}
} else if sender.tag == 3 {
UIView.animate(withDuration: 0.3) {
self.view1.alpha = 0
self.view2.alpha = 0
self.view3.alpha = 1
}
}
}
}
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = ViewController()
You can copy and paste this into an empty playground to see it in action. Essentially this is showing or hiding the appropriate views based on which button is selected. You can swap out the views for view controllers if you so desire.

Custom view scrolls inside a scroll view

I have made a custom view called SignView and added to another customView called mainSignView which is inside an scrollview called getFormView but when I sign on the signView it scrolls and I cannot do any sign help me to overcome this please!
Here is what I have
#objc func pressedSignViewAction(_ sender: UILabel) {
self.signViewElement = "signView1"
uniY += 60
mainSignView = UIView(frame: CGRect(x: 20, y: uniY, width: 250, height: 250))
mySignViewName = UILabel(frame: CGRect(x: 20, y: 10, width: 200, height: 30))
let signLabel = UILabel(frame: CGRect(x: 20, y: 50, width: 200, height: 30))
signView = YPDrawSignatureView(frame: CGRect(x: 10, y: 90, width: 230, height: 100))
signView.backgroundColor = .white
signLabel.text = "Signature"
mainSignView.backgroundColor = .green
mySignViewName.text = self.signViewNameFD
self.signViewNameElement = self.signViewNameFD
cancelButton = UIButton(frame : CGRect(x: 20, y: 200, width: 100, height: 25))
cancelButton.addTarget(self, action: #selector(pressedSignClearAction(_:)), for: .touchUpInside)
cancelButton.setTitle("Clear",for: .normal)
cancelButton.setTitleColor(UIColor.red, for: .normal)
uniY += 170
self.view.addSubview(getFormView)
//self.getFormView.addSubview(signLabel)
self.getFormView.addSubview(mainSignView)
self.mainSignView.addSubview(signLabel)
self.mainSignView.addSubview(signView)
self.mainSignView.addSubview(mySignViewName)
self.mainSignView.addSubview(cancelButton)
self.enterSignViewTitle()
self.updateScrollY()
}
#objc func pressedSignClearAction(_ sender: UIButton) {
self.signView.clear()
}
From YPDrawSignatureView Documentation:
// MARK: - Delegate Methods
// The delegate functions gives feedback to the instanciating class. All functions are optional,
// meaning you just implement the one you need.
// didStart() is called right after the first touch is registered in the view.
// For example, this can be used if the view is embedded in a scroll view, temporary
// stopping it from scrolling while signing.
func didStart() {
print("Started Drawing")
yourScroll.isScrollEnabled = false
}
// didFinish() is called rigth after the last touch of a gesture is registered in the view.
// Can be used to enable scrolling in a scroll view if it has previous been disabled.
func didFinish() {
print("Finished Drawing")
yourScroll.isScrollEnabled = true
}

Resources