How do I disable all buttons when one gets pressed in XCode? - ios

How do I make it so that when I press one button in XCode, the rest of the buttons (including the one that was pressed) become disabled? Of course I still want the function to be carried out by the button that gets pressed. I just don't want the users to be able to press any button more than once, nor do I want them to be able to press another button after they've already pressed a first one. Below are my IBActions for my two buttons in this case:
#IBAction func addVote1(sender: AnyObject) {
var query = PFQuery(className: "VoteCount")
query.getObjectInBackgroundWithId("BiEM17uUYT") {
(voteCount1: PFObject!, error: NSError!) ->Void in
if error != nil {
NSLog("%#", error)
} else {
voteCount1.incrementKey("votes")
voteCount1.saveInBackgroundWithTarget(nil, selector: nil)
}
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
self.pollResults1.text = "\(votes) votes \(votes2) votes"
}
}
#IBAction func addVote2(sender: AnyObject) {
var query = PFQuery(className: "VoteCount")
query.getObjectInBackgroundWithId("BiEM17uUYT") {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
voteCount1.incrementKey("votes2")
voteCount1.saveInBackgroundWithTarget(nil, selector: nil)
}
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
self.pollResults2.text = "\(votes) votes \(votes2) votes"
}
}
}

Set up #IBOutlet properties for the buttons if you haven't already, then add a lazy var array of the buttons. In the button handler, set each button's enabled property to false.
class ViewController {
#IBOutlet var button1: UIButton!
#IBOutlet var button2: UIButton!
lazy var buttons: [UIButton] = [self.button1, self.button2]
// ...
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
// ...
}
}

You can loop through all subview in UIView and find if is a UIButton, if is you can disable the button.
func disableButtons() {
for views in view.subviews {
if let button = views as? UIButton {
button.enabled = false
}
}
}

Do one thing, give unique Tag to all buttons. After that create the method which creates button and disable them by using button tags
func disableButton()
{
for tagvalue in 101...102
{
var btnTemp = self.view.viewWithTag(tagvalue) as UIButton;
btnTemp.enabled = false;
}
}
Add above method in your button, as shown in below code
#IBAction func addVote1(sender: AnyObject)
{
//Your code
disableButton()
}
#IBAction func addVote2(sender: AnyObject)
{
//Your code
disableButton()
}

The easiest way is to add a UIView with a background color of UIColor.clearColor() on top. It's invisible and captures all taps.
class ViewController {
private var uiBlocker = UIView()
override func viewDidLoad() {
uiBlocker.backgroundColor = UIColor.clearColor()
}
#IBAction func buttonAction() {
view.addSubView(uiBlocker)
[stuff you want to do]
uiBlocker.removeFromSuperView()
}
}

let subviews : NSArray = headerView.subviews as NSArray
for button in subviews {
if let button = button as? UIButton {
//let btn = button as! UIButton
button.isSelected = false
}
}
sender.isSelected = true

Related

Only want Copy and Share from UIMenuController, but code still being wonky

Here's what my textView looks like right now. It is a textview inside a scrollview.
I am trying to replace the usual UIMenuController menu items with Save and Delete but not getting there. Can someone help me out?
Here's my code:
import UIKit
class DetailViewController: UIViewController, UIGestureRecognizerDelegate, {
var selectedStory : URL!
#IBOutlet weak var textView: UITextView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var textSlider: UISlider! {
didSet {
configureSlider()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let storyText = try? String(contentsOf: selectedStory)
textView.text = storyText
textView.isUserInteractionEnabled = true
let longPressGR = UILongPressGestureRecognizer(target: self, action: #selector(longPressHandler))
longPressGR.minimumPressDuration = 0.3 //
textView.addGestureRecognizer(longPressGR)
}
// MARK: - UIGestureRecognizer
#objc func longPressHandler(sender: UILongPressGestureRecognizer) {
guard sender.state == .began,
let senderView = sender.view,
let superView = sender.view?.superview
else { return }
senderView.becomeFirstResponder()
UIMenuController.shared.setTargetRect(senderView.frame, in: superView)
UIMenuController.shared.setMenuVisible(true, animated: true)
}
override var canBecomeFirstResponder: Bool {
return true
}
}
extension UITextView{
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == Selector(("_copy:")) || action == Selector(("_share:"))
{
return true
} else {
return false
}
}
}
extension UIScrollView{
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == Selector(("_copy:")) || action == Selector(("_share:"))
{
return true
} else {
return false
}
}
}
I'm getting 2 issues:
When I tap the screen, only the Share is showing up and the Copy is not.
The Share button shows up randomly near the center, not on the text that is selected, like so.
First of all, remove UITextView that is inside UIScrollView because UIScrollView itself is the parent class of UITextView. It will place the UIMenuController at appropriate frame.
Remove longPressGR and longPressHandler methods.
Replace this method,
extension UITextView{
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action.description == "copy:" || action.description == "_share:" {
return true
} else {
return false
}
}
}
You will get following output.

make 3 random elements in the array invisible

I have 5 buttons in an array I want to make random three of these invisible when pressed on button. so the last two buttons will be visible
I tried like this:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
let buttons:[UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
let randomNumber = Int(arc4random_uniform(UInt32(3)))
buttons[randomNumber].isHidden = !buttons[randomNumber].isHidden
}
but it takes first elements [0,1,2] and only 1 button is invisible at each press
You are currently only selecting one button. Change that to a loop to select 3. Remove the selected button from the array and make it invisible. Finally, make the remaining buttons visible:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
var buttons:[UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
// Select 3 buttons randomly and hide them
for _ in 1...3 {
let randomNumber = Int(arc4random_uniform(UInt32(buttons.count)))
let button = buttons.remove(at: randomNumber)
button.isHidden = true
}
// Make the remaining buttons visible
for button in buttons {
button.isHidden = false
}
}
I've just written a neat extension to get a random elements from an array:
extension Array {
func randomItems(count: Int) -> [Element] {
guard count <= self.count else { fatalError() }
var notUsedElements: [Element] = self
var randomElements: [Element] = []
while randomElements.count != count {
randomElements.append(notUsedElements.remove(at: Int(arc4random_uniform(UInt32(notUsedElements.count)))))
}
return randomElements
}
}
Using this you can achieve what you want this way:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
let buttons:[UIButton] = [buttonA, buttonB, buttonC, buttonD, buttonE]
// make sure all are visible at the beginning
buttons.forEach { (button) in
button.isHidden = false
}
// hide random 3:
buttons.randomItems(count: 3).forEach { (button) in
button.isHidden = true
}
}

How to pass data back to ViewController holding Container View and TableViewController that is embedded in the Container? Swift 3

How can I call func checkField when nextButton is tapped?
If no field is empty in ManagedTableEleventhViewController, I'd like to segue to TwelvethViewController.
I have a UIViewController ElevethViewController which holds a container view. The container view has an embed segue to a UITableViewController ManagedTableEleventhViewController. From ElevethViewController there is a Show segue to a UIViewController TwelevethViewController
The View hierarchy looks like this:
ElevethViewController
Container View
ManagedTableEleventhViewController embedded in Container View with Embed segue
Show segue "eleventhToTwelveth" to "Tweleveth View Controller"
Embed segue "myEmbeddedSegue" to "Managed Table"
ManagedTableEleventhViewController contains 4 static cells containing 1 textField each and one empty static cell.
import UIKit
import Foundation
protocol DelegateEleventh {
func checkField(sender:EleventhViewController)
}
class EleventhViewController: UIViewController {
var delegate:DelegateEleventh?
#IBAction func nextButton(_ sender: Any) {
//if delegate is not nil, call func checkField
if let delegateVC = delegate {
delegateVC.checkField(sender:self)
} else{
print("delegateVC value \(delegate)") //prints nil
}
}
} //end of class
import Foundation
import UIKit
class ManagedTableEleventhViewController:
UITableViewController,UITextFieldDelegate,DelegateEleventh {
#IBOutlet weak var fullName: UITextField!
#IBOutlet weak var flatNumber: UITextField!
#IBOutlet weak var streetAddress: UITextField!
#IBOutlet weak var phoneNumber: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
//When nextButton is touched in EleventhViewController, call this method
func checkField(sender:EleventhViewController){
for cell in self.tableView.visibleCells {
for sub in cell.contentView.subviews{
if sub is UITextField{
let textF = sub as? UITextField
//if textField is empty, make its border red,else clear
if textF?.text == "" {
self.hasText = false
textF?.layer.cornerRadius = 8.0
textF?.layer.masksToBounds = true
textF?.layer.borderColor = UIColor.red.cgColor
textF?.layer.borderWidth = 1.0
} else {
self.hasText = true
//segue to nextViewcontroller
sender.performSegue(withIdentifier: "elevethToTwelveth", sender: sender)
}
}// end of if sub is UITextField
}//end of for sub in cell.contentView
} //end of for cell in tableView
}
//KEYBOARD DOES NOT RESIGN....
// When tapping outside of the keyboard, close the keyboard down
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
// used to check textField has a string value
var hasText:Bool!
//called by ManagedTableEleventhViewController (namely the delegate) when
editing has begun
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField.text == "" {
print("false value in textFieldDidBeginEditing")
self.hasText = false
textField.layer.cornerRadius = 8.0
textField.layer.masksToBounds = true
textField.layer.borderColor = UIColor.red.cgColor
textField.layer.borderWidth = 1.0
} else {
print("true value in textFieldDidBeginEditing")
textField.layer.borderWidth = 1
textField.layer.borderColor = UIColor.white.cgColor
print("call in else")
self.hasText = true
}
}
//called by ManagedTableEleventhViewController (namely the delegate) when
// editing stopped
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
//if textField is empty make the border red
if textField.text == "" {
self.hasText = false
textField.layer.cornerRadius = 8.0
textField.layer.masksToBounds = true
textField.layer.borderColor = UIColor.red.cgColor
textField.layer.borderWidth = 1.0
print("false value in textFieldDidEndEditing")
} else {
textField.layer.borderWidth = 1
textField.layer.borderColor = UIColor.white.cgColor
print("true value in textFieldDidEndEditing")
self.hasText = true
}
}
// Stop Editing on Return Key Tap.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}//end of class
Thanks to this answer I have obtained the desired result.
class EleventhViewController: UIViewController {
#IBAction func nextButton(_ sender: Any) {
var managed: ManagedTable? {
return self.childViewControllers.last as! ManagedTable?
//if there is no empty field after checkField(sender:_) is called,
// segue to TwelvethViewController
managed?.checkField(sender: self)
}
}
}
class ManagedTableEleventhViewController {
// holds a true value if textField contains a value
var hasText:Bool!
//holds a true/false value for each textField after iterating through them
//with a for loop
var textValues = [Bool]()
//When nextButton is touched in EleventhViewController, call this method
func checkField(sender:EleventhViewController) {
for cell in self.tableView.visibleCells{
for sub in cell.contentView.subviews{
if sub is UITextField{
let textF = sub as? UITextField
//if textField is empty, make its border red,else clear
if textF?.text == "" {
self.hasText = false
self.textValues.append(self.hasText)
textF?.layer.cornerRadius = 8.0
textF?.layer.masksToBounds = true
textF?.layer.borderColor = UIColor.red.cgColor
textF?.layer.borderWidth = 1.0
} else {
self.hasText = true
self.textValues.append(self.hasText)
}
}// end of if sub is UITextField
}//end of for sub in cell.contentView
} //end of for cell in tableView
//if no field is empty perform segue to TwelvethViewController,
//otherwise reset textValues array
if !self.textValues.contains(false){
sender.performSegue(withIdentifier: "eleventhToTwelveth", sender: sender)
}
self.textValues.removeAll()
} //end of checkField(sender:_)
}//end of class

Swift/UISwitch: how to implement a delegate/listener

In my UITableViewController I have a custom cell which contains a switcher which is the following:
import Foundation
import UIKit
class SwitchCell: UITableViewCell {
#IBOutlet weak var label : UILabel!
#IBOutlet weak var switchEmail : UISwitch!
func setEditable(canEdit:Bool) {
if (canEdit) {
self.switchEmail.enabled = true
self.label.highlighted = false
}
else {
self.switchEmail.enabled = false
self.label.highlighted = true
}
}
func configureCellWithSwitch(labelText:String, switchValue:Bool, enabled:Bool) {
var labelFrame:CGRect = self.label.frame
labelFrame.size.height = Settings.labelHeight
self.label.frame = labelFrame
self.label.text = labelText
if (switchValue) {
self.switchEmail.setOn(true, animated: true)
}
else {
self.switchEmail.setOn(false, animated: true)
}
self.setEditable(enabled)
}
}
I would like to know how to implement a listener/delegate to the switcher in order to get its value from the UITableViewController. I was able to write delegate/listeners for a cell with UITextField and UITextView implementing the methods
func controller(controller: UITableViewCell, textViewDidEndEditing: String, atIndex: Int)
and
func controller(controller: UITableViewCell, textFieldDidEndEditingWithText: String, atIndex: Int)
but I don't know what I should implement the switcher.
UISwitch has no delegate protocol. You can listen to the status as follows:
ObjC:
// somewhere in your setup:
[self.mySwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
- (void)switchChanged:(UISwitch *)sender {
// Do something
BOOL value = sender.on;
}
Swift:
mySwitch.addTarget(self, action: "switchChanged:", forControlEvents: UIControlEvents.ValueChanged)
func switchChanged(mySwitch: UISwitch) {
let value = mySwitch.on
// Do something
}
Swift3 :
mySwitch.addTarget(self, action: #selector(switchChanged), for: UIControlEvents.valueChanged)
func switchChanged(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
}
Swift4:
mySwitch.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged)
#objc func switchChanged(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
}
In Swift4.0
mySwitch.addTarget(self, action: #selector(valueChange), for:UIControlEvents.valueChanged)
#objc func valueChange(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
print("switch value changed \(value)")
}
Another (Swift 3 or 4) method is to use didSet observer and drastically reduce code, like so-
In the class declaration declare a variable like below:
var switchFlag: Bool = false {
didSet{ //This will fire everytime the value for switchFlag is set
print(switchFlag) //do something with the switchFlag variable
}
}
Then you can have an IBAction on the UISwitch like so
#IBAction func switchChanged(_ sender: Any) {
if self.mySwitch.isOn{
switchFlag = true
}else{
switchFlag = false
}
}
Swift 3:
Using Storyboard Autolayout:
Add Reference:
#IBOutlet weak var sampleSwitch: UISwitch!
Associate method:
#IBAction func sampleSwitchValueChanged(_ sender: Any) {
if sampleSwitch.isOn {
print("ON")
}
else {
print ("OFF")
}
}
Programatic way:
Adding Target:
sampleSwitch.addTarget(self, action: #selector(ViewController.sampleSwitchValueChanged(sender:)), for: UIControlEvents.valueChanged)
The method associated with the switch:
func sampleSwitchValueChanged(sender: UISwitch!)
{
if sender.isOn {
print("switch on")
} else {
}
}
In Swift 5
switchDemo.addTarget(self, action: #selector(didTapAdvertise), for:UIControl.Event.valueChanged)
#objc func didTapAdvertise(mySwitch: UISwitch) {
let value = mySwitch.isOn
// Do something
print("switch value changed \(value)")
}
Swift 3:
#IBOutlet weak var mySwitch: UISwitch!
mySwitch.addTarget(self, action: #selector(MyClass.switchChanged(_:)), for: UIControlEvents.valueChanged)
func switchChanged(_ mySwitch: UISwitch) {
if mySwitch.isOn {
// handle on
} else {
// handle off
}
}
I have the solution in objective-c, it is the method that I use regularly:
-The Action of the switch must be in tableviewcontroller and not on the cell
-When You tap on the switch inside the action can do this to find the correct cell, then you can easily find the index or any other value that you need ...
- (IBAction)switchValueChanged:(UISwitch *)sender
{
YourCellClass *cell = (YourCellClass *)[sender findSuperViewWithClass:[YourCellClass class]];
etc....
}
the method findSuperviewWithClass is a category on UIView
- (UIView *)findSuperViewWithClass:(Class)superViewClass
{
UIView *superView = self.superview;
UIView *foundSuperView = nil;
while (nil != superView && nil == foundSuperView)
{
if ([superView isKindOfClass:superViewClass])
{
foundSuperView = superView;
} else
{
superView = superView.superview;
}
}
return foundSuperView;
}

Button with constraints inside PersonCell hides half of the button Swift

Created a button inside a personCell which either shows Follow / Unfollow.
I've added the following constraints to the button:
Align Center Y to: Superview
Height = 43
Trailing space to: Superview
With or without the constraints it still cuts of a side of the button.
If the button was supposed to display "follow" it would only show "ow"
Code for PersonCell
class PersonCell: UITableViewCell {
#IBOutlet weak var followButton: UIButton!
var isFollowing: Bool?
var user: PFUser?
{
didSet
{
self.configure()
}
}
override func awakeFromNib()
{
super.awakeFromNib()
self.isFollowing = false
self.followButton?.hidden = true
}
override func prepareForReuse()
{
super.prepareForReuse()
self.isFollowing = false
self.followButton?.hidden = true
self.textLabel?.text = ""
self.user = nil
}
func configure()
{
if let constUser = user
{
self.textLabel?.text = constUser.username
// are we following this person?
NetworkManager.sharedInstance.isFollowing(constUser, completionHandler: {
(isFollowing, error) -> () in
if let _ = error
{
// Alert the user, or otherwise modify the UI
}
else
{
self.isFollowing = isFollowing
if isFollowing == true
{
let image = UIImage(named: "UnfollowButton")
self.followButton?.setImage(image, forState: .Normal)
}
else
{
let image = UIImage(named: "FollowButton")
self.followButton?.setImage(image, forState: .Normal)
}
self.followButton?.hidden = false
}
})
}
}
#IBAction func didTapFollow(sender: UIButton)
{
self.followButton?.enabled = false
let newValue = !(self.isFollowing == true)
NetworkManager.sharedInstance.updateFollowValue(newValue, user: self.user!) { (error) -> () in
self.followButton?.enabled = true
let image = (newValue == true) ? UIImage(named: "UnfollowButton") : UIImage(named: "FollowButton")
self.followButton?.setImage(image, forState: .Normal)
self.isFollowing = newValue
}
}
}
Im not yet allowed to post images but see this if you need to view how it looks:
http://postimg.org/image/jnf47mnr1/
Thankx in advance!

Resources