I have several buttons defined in a loop in viewDidLoad. They are inside a content view, which is in a scroll view.
for var i:Int = 0; i < colleges.count; i++ {
let collegeButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
collegeButton.frame = CGRectMake(0, 0, self.contentView.frame.size.width, 30)
collegeButton.center = CGPoint(x: self.contentView.center.x, y: 30 * CGFloat(i) + 30)
collegeButton.setTitle(sortedColleges[i], forState: UIControlState.Normal)
collegeButton.setTitleColor(UIColor.darkGrayColor(), forState: UIControlState.Normal)
collegeButton.titleLabel?.font = UIFont(name: "Hiragino Kaku Gothic ProN", size: 15)
collegeButton.addTarget(self, action: "collegeSelected:", forControlEvents: UIControlEvents.TouchUpInside)
self.contentView.addSubview(collegeButton)
}
As you can see, the title of each button is set based on a previously defined array of strings. Whenever a button is selected, a segue is called to move to a table view, which is embedded in a navigation controller.
I need to set the navigation controller title to be the same as the specific button title.
Here are some things I have tried:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var destViewController:videosTableView = segue.destinationViewController as videosTableView
//destViewController.title = collegeButton.titleLabel?.text
//var buttonTitle = sender.titleLabel?.text
//destViewController.title = buttonTitle
}
The commented lines were failed attempts.
I also tried working in the action function called when the button is pressed:
func collegeSelected(sender: UIButton!) {
self.performSegueWithIdentifier("goToTableView", sender: self)
//Set navigation title of next screen to title of button
var buttonTitle = sender.titleLabel?.text
println(buttonTitle)
}
Using the sender to get the button title works, but I don't know how to pass it to the next view controller.
Thanks a lot to anyone who can help.
In your button function, pass the button along as the sender of the segue:
func collegeSelected(sender: UIButton!) {
self.performSegueWithIdentifier("goToTableView", sender: sender)
}
Then in prepareForSegue, get the button title from the sender (i.e. the button):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController = segue.destinationViewController as videosTableView
if let buttonTitle = (sender as? UIButton)?.titleLabel?.text {
destViewController.title = buttonTitle
}
}
Related
I have three buttons that connect to the same IBAction. They all have their own out looks.
I found out how to make the button become highlighted when they are pressed and unhighlighted when the user presses another button. Is their a better way to write the code? Here is what I am using:
#IBAction func tipChanged(_ sender: UIButton) {
zeroPCTButton.isSelected = false
tenPCTButton.isSelected = false
twentyPCTButton.isSelected = false
sender.isSelected = true
}
The reason why I am asking is because I could make an application that has a thousand buttons and I don't want to brute force statements a thousands times
We can unhighlight the non pressed UIButton in the following way,
#IBAction func buttonAction(_ sender: Any) {
let the_tag = (sender as AnyObject).tag;
let button = self.view.viewWithTag(the_tag!) as? UIButton
button?.isSelected = true
button?.backgroundColor = UIColor.white
button?.setTitleColor(UIColor.black, for: .normal)
// Create a list of all tags
let allButtonTags = [1, 2, 3, 4, 5]
let currentButtonTag = (sender as AnyObject).tag
allButtonTags.filter { $0 != currentButtonTag }.forEach { tag in
if let button = self.view.viewWithTag(tag) as? UIButton {
// Deselect/Disable these buttons
button.backgroundColor = #colorLiteral(red: 0.80803, green: 0.803803, blue: 0.805803, alpha: 1)
button.setTitleColor(UIColor.darkGray, for: .normal)
button.isSelected = false
}
}
}
Let's Imagine you have 1000 buttons, You need to Implement some loop to do all the action related Button (Create,Add constraints, click events).Create UIButton Array for store your buttons.
var buttons:[UIButton] = []
Add buttons to this array when you create buttons
for buttonIndex in 1...1000 {
// your other stuff to create, add constraints to button
button.tag = buttonIndex
buttons.append(button)
}
Now you can easily achieve your object.
#IBAction func tipChanged(_ sender: UIButton) {
buttons.forEach({$0.isSelected = $0.tag == sender.tag})
view.layoutIfNeeded()
}
My prepareForSegue method isn't passing data to the destination view controller.
var buttonsDictionary = [Int: UIButton]()
func createButtonArray() {
for item in statTitles {
let statisticButton = StatButton()
statisticButton.layer.cornerRadius = 10
statisticButton.backgroundColor = UIColor.darkGray
statisticButton.setTitle(String(item.value), for: UIControlState.normal)
statisticButton.setTitleColor(UIColor.white, for: UIControlState.normal)
statisticButton.titleLabel?.font = UIFont.systemFont(ofSize: 43)
statisticButton.titleEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0)
statisticButton.contentHorizontalAlignment = .left
statisticButton.addTarget(self, action: #selector(displayStatDetail), for: .touchUpInside)
statisticButton.buttonIndex = item.key
buttonsDictionary[item.key] = (statisticButton) // Assign value at item.key
print(statisticButton.buttonIndex)
}
}
func viewSavedStatistics() {
for button in buttonsDictionary {
statisticsView.addArrangedSubview(button.value)
}
}
#objc func displayStatDetail() {
self.performSegue(withIdentifier: "StatDetailSegue", sender: UIButton())
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "StatDetailSegue" {
if let destinationVC = segue.destination as? StatDetailViewController,
let index = (sender as? StatButton)?.buttonIndex {
destinationVC.statID = index
print("Destination STATID: \(destinationVC.statID)")
}
}
}
All of the above code is written in the ViewController class.
StatButton is a custom UIButton class.
The prepare is meant pass on the buttonIndex of the tapped button, but only passes on 0 and doesn't print so I don't think it's being called.
You sender is a new instance of UIButton which doesn't have any of the information you need. Instead pass the button calling the selector.
#objc func displayStatDetail(_ sender: StatisticButton) {
self.performSegue(withIdentifier: "StatDetailSegue", sender: sender)
}
You would need to change the target selector like this in the loop.
statisticButton.addTarget(self, action: #selector(displayStatDetail(_:)), for: .touchUpInside)
You’re passing a new instance of UIButton as sender here:
self.performSegue(withIdentifier: "StatDetailSegue", sender: UIButton())
Instead you should probably have your statisticButton there. Your button target selector method can have a parameter - the button instance the user clicked on. Use it as sender.
You had a mistake in performSeguefunction you've send always a new object of UIButton, not the one you've clicked on. Here is what you should do.
statisticButton.addTarget(self, action: #selector(displayStatDetail(_ :)), for: .touchUpInside)
#objc func displayStatDetail(_ sender: UIButton) {
self.performSegue(withIdentifier: "StatDetailSegue", sender: sender)
}
I am in a quandary about how to position the popup on the supplied screenshot to point to the word tapped. The word in the text view is the one that is grey. I would show some code but I have none that is relevant other than the code that handles the tap.
Here is some code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if(segue.identifier == "popOverSegue") {
let destinationViewController: PopoverViewController = segue.destination as! PopoverViewController
destinationViewController.modalPresentationStyle = UIModalPresentationStyle.popover
destinationViewController.popoverPresentationController!.delegate = self
destinationViewController.popoverPresentationController?.permittedArrowDirections = .down
destinationViewController.tappedWord = tappedWord
destinationViewController.definitionText = "This is a test description"
let x = meaningText.frame.minX
let y = meaningText.frame.minY
destinationViewController.popupOrigin = CGPoint(x: x + pointOfTap.x,y: y + pointOfTap.y)
destinationViewController.popupSize = CGSize(width: 200, height: 200)
debugPrint(meaningText)
}
}
Not sure if these are applicable:
If you are using a UIButton() for the highlighted text, you could pretty easily get the button's location using something like the following:
let buttonLocation = theButton.frame.origin
print("Buttons location is \(buttonLocation)")
Alternatively, if you're using a UIGestureRecognizer to open the popover, you could use location(in: UIView) to get the tap location (which would be somewhere on/near the highlighted text.
That would go something like this:
override func viewDidLoad() {
let tapView = UITapGestureRecognizer(target: self, action: #selector(TheVC.popover(recognizer:)))
self.view.isUserInteractionEnabled = true
self.view.addGestureRecognizer(tapView)
}
#objc func popover(recognizer: UIGestureRecognizer) {
let tapLocation = recognizer.location(in: self.view)
print("Tap occurred at location \(tapLocation)")
}
Once you have the location of the tap or the UI element that triggers the tap, you could calculate the popover position from there.
I have created 5 buttons dynamically in Swift like this:
for theIndex in 0..<5 {
let aButton = UIButton()
aButton.frame = CGRectMake(self.view.bounds.width / 2 - 120, self.view.bounds.height / 2 - 150, 240, 300)
aButton.setTitle("Button \(theIndex)", forState: .Normal)
aButton.addTarget(self, action: "btnClicked:", forControlEvents:.TouchUpInside)
self.view.addSubview(aButton)
}
But how can I get the BUTTON_ID for each one?
func btnClicked(sender: AnyObject?) {
let vc = storyboard!.instantiateViewControllerWithIdentifier("vc_name") as! DetailVC
vc.selectedId = **WANT_TO_PASS_BUTTON_ID_HERE**
self.presentViewController(vc, animated:true, completion:nil)
}
You can use tag property of your buttons (for example, you can set there a button's index), and retrieve it later in func btnClicked(sender: AnyObject?) method to determine a button with which index was pushed
While cycling through your indexes do:
aButton.tag = theIndex
and in btnClicked method do:
vc.selectedId = sender.tag
See for reference Apple docs on UIView
I have 77 buttons on one view. These 77 buttons are in a collection outlet. The buttons are wired to trigger the same segue. The segue presents a detailViewController with information passed to it from the button. I need to know what button triggered the segue so that I know what data to pass to the detail controller.
I set the tag in the viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
self.containerView.backgroundColor = UIColor.blackColor()
var count = 0
for item in buttonOutlets {
item.layer.cornerRadius = 2.0
item.layer.borderWidth = 2.0
item.tag = count
item.layer.borderColor = UIColor.yellowColor().CGColor
item.addTarget(self, action: Selector("handleButtonPress"), forControlEvents: UIControlEvents.TouchUpInside)
count = count + 1
println(item.tag) // prints correct tag numbers
}
self.fetchAllObjects()
}
This is my prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var upcoming: itemDetail = segue.destinationViewController as! itemDetail
if (segue.identifier == "loadDetailView") {
println(buttonOutlets[1].tag) // prints correct tag number
let objectPlace = sender?.tag
upcoming.parseObject = collectionObjects[objectPlace!] as? PFObject
}
The answer lies in item.addTarget. The action selector calls handleButtonPress. My original button press handler was:
func handleButtonPress(sender: UIButton) {
self.performSegueWithIdentifier("loadDetailView", sender: self)
}
What I was missing was sender: sender:
func handleButtonPress(sender: UIButton) {
self.performSegueWithIdentifier("loadDetailView", sender: sender)
}
Then add a colon to handleButtonPress call:
item.addTarget(self, action: Selector("handleButtonPress:"), forControlEvents: UIControlEvents.TouchUpInside)