I want to change the borderColor and titleColor synchronized. but it didn't change the border color.
How can I make setTitleColor func applied to the border Color?
func setColor(button: UIButton) {
button.setTitleColor(UIColor.fromRGB(95, 61, 196), for: .selected)
button.layer.borderColor = UIColor.fromRGB(95, 61, 196).cgColor
}
#objc func handleCleaningKinds(_ sender: UIButton) {
setColor(button: sender)
deselectAllButtons()
sender.isSelected = true
}
func deselectAllButtons() {
for subView in stackView.subviews{
if let button = subView as? UIButton {
button.isSelected = false
//button.layer.borderColor = UIColor.white.cgColor
}
}
}
borderColor doesn't work with UIButton selectedState, So you need to handle that by himself based on your button's current state.
So write function like this to update state:
func updateSelectedState(_ isSelected: Bool) {
button.layer.borderWidth = isSelected ? 1 : 0 // If need to hide border on normal state
button.layer.borderColor = isSelected ? UIColor.fromRGB(95, 61, 196).cgColor : UIColor.white.cgColor // If need another color on normal state
button.isSelected = isSelected
}
Then your two functions should be like this:
#objc func handleCleaningKinds(_ sender: UIButton) {
deselectAllButtons()
updateSelectedState(sender)
}
func deselectAllButtons() {
for subView in stackView.subviews{
if let button = subView as? UIButton {
updateSelectedState(false)
}
}
}
Also setting color func setColor(button: UIButton) should not be called each time when button clicked, so you can call this function at viewDidLoad or any other function, where you create buttons.
You can try to add:
button.layer.borderWidth = 1
This might do the trick.
Have you tried adding these 2 lines?
button.layer.masksToBounds = false
button.clipsToBounds = true
In my project I am using 6 buttons in one screen.I want to change the button color based on user's tap and "day order value". i am getting "day order value" from server.for example user day order value is equal to 1, day1 button background color should be red if user taps on day2 button day2 button should be in blue and remaining all button background colour should be white.
Please see the below screenshot.
if user pressed on one button that particular button should be highlight with some color remaining buttons should be same color. I can able to change button color by checking each condition but I want to write in simple manner.
see the following code which i have i tried for "dayoredrvalue".
func UpdateButtoncolor()
{
let dayOrderStr = UserDefaults.standard.string(forKey: "dayOrderStr")
print("dayOrderStr--",dayOrderStr)
if (dayOrderStr?.isEqual("1"))!{
self.day1Btn.backgroundColor = UIColor.red
self.day2Btn.backgroundColor = UIColor.white
self.day3Btn.backgroundColor = UIColor.white
self.day4Btn.backgroundColor = UIColor.white
self.day5Btn.backgroundColor = UIColor.white
self.day6Btn.backgroundColor = UIColor.white
}else if(dayOrderStr?.isEqual("2"))!
{
self.day1Btn.backgroundColor = UIColor.white
self.day2Btn.backgroundColor = UIColor.red
self.day3Btn.backgroundColor = UIColor.white
self.day4Btn.backgroundColor = UIColor.white
self.day5Btn.backgroundColor = UIColor.white
self.day6Btn.backgroundColor = UIColor.white
}else if(dayOrderStr?.isEqual("3"))!
{
self.day1Btn.backgroundColor = UIColor.white
self.day2Btn.backgroundColor = UIColor.white
self.day3Btn.backgroundColor = UIColor.red
self.day4Btn.backgroundColor = UIColor.white
self.day5Btn.backgroundColor = UIColor.white
self.day6Btn.backgroundColor = UIColor.white
}else if(dayOrderStr?.isEqual("4"))!
{
self.day1Btn.backgroundColor = UIColor.white
self.day2Btn.backgroundColor = UIColor.white
self.day3Btn.backgroundColor = UIColor.white
self.day4Btn.backgroundColor = UIColor.red
self.day5Btn.backgroundColor = UIColor.white
self.day6Btn.backgroundColor = UIColor.white
}else if(dayOrderStr?.isEqual("5"))!
{
self.day1Btn.backgroundColor = UIColor.white
self.day2Btn.backgroundColor = UIColor.white
self.day3Btn.backgroundColor = UIColor.white
self.day4Btn.backgroundColor = UIColor.white
self.day5Btn.backgroundColor = UIColor.red
self.day6Btn.backgroundColor = UIColor.white
}else
{
self.day1Btn.backgroundColor = UIColor.white
self.day2Btn.backgroundColor = UIColor.white
self.day3Btn.backgroundColor = UIColor.white
self.day4Btn.backgroundColor = UIColor.white
self.day5Btn.backgroundColor = UIColor.white
self.day6Btn.backgroundColor = UIColor.red
}
}
As per your query, It's quite simple. Just follow the following -
Step 1: Add an UIButton object in your viewController. Like that -
var selectedButton: UIButton? = nil
Step 2: Add same button Action for all your buttons -
#IBAction func btnActionSelection(_ sender:UIButton){
if(selectedButton == nil){ // No previous button was selected
updateButtonSelection(sender)
}else{ // User have already selected a button
if(selectedButton != sender){ // Not the same button
selectedButton?.backgroundColor = .clear
updateButtonSelection(sender)
}
}
}
Step 3: Now, Update button selection
func updateButtonSelection(_ sender: UIButton){
UserDefaults.standard.set("\(sender.tag)", forKey: "dayOrderStr")
selectedButton = sender
selectedButton?.backgroundColor = .green
}
Step 4: Check User selected day (For that you need to add tag on buttons from 1 to 6 respectively)
override func viewDidLoad() {
super.viewDidLoad()
// Check user's selected day
if let selectedDay = UserDefaults.standard.value(forKey: "dayOrderStr") as? String{
debugPrint("selectedDay: "selectedDay) // Get user's selected day
if let btn = self.view.viewWithTag(Int(selectedDay)!){
updateButtonSelection(btn)
}
}
//Other stuff
}
I have attached a demo for you using my logic:
For this you need to take a Group Outlets of your UIButton and assign a unique tag to each and then rest logic is described in the demo attached below.
like
#IBOutlet var btnAllSelected: [UIButton]!
And then simple logic like this:
#IBAction func btnAllClicked(_ sender: UIButton) {
for button in btnAllSelected {
if sender.tag == button.tag{
button.isSelected = true;
button.backgroundColor = UIColor.green
}else{
button.isSelected = false;
button.backgroundColor = UIColor.red
}
}
if sender.tag == 1{
print("Button 1 selected")
}else if sender.tag == 2{
print("Button 2 selected")
}else if sender.tag == 3{
print("Button 3 selected")
}else if sender.tag == 4{
print("Button 4 selected")
}else if sender.tag == 5{
print("Button 5 selected")
}else if sender.tag == 6{
print("Button 6 selected")
}
}
Link to the Demo
FYI:- Please ignore the pods installed in it. I edited some another demo and made a one for you.
Hope this helps.
You should create New Referencing Outlet Collections for all your UIButtons like this,
#IBOutlet var arrButtons: [UIButton]!
Implement only one Button tap events for all your buttons, Please find belo code.
#IBAction func btnClicked(_ sender: UIButton) {
arrButtons.forEach({$0.backgroundColor = UIColor.red})
sender.backgroundColor = UIColor.darkGray
}
Simplified code, it uses an array of the buttons and an index:
let buttonArray = [day1Btn, day2Btn, day3Btn, day4Btn, day5Btn, day6Btn]
buttonArray.forEach { $0.backgroundColor = .white }
guard let dayOrderStr = UserDefaults.standard.string(forKey: "dayOrderStr"),
let dayOrderIndex = Int(dayOrderStr), 1...buttonArray.count ~= dayOrderIndex {
buttonArray[dayOrderIndex-1].backgroundColor = .red
}
It can be still simpler if you save the value in UserDefaults as Int
Here is one solution among many others.
#IBOutlet var buttons: [UIButton]! // link all the buttons from the storyboard
func changeColorButton(sender: UIButton) {
// default appearance for all buttons
for button in buttons {
button.backgroundColor = UIColor.green
}
// update color only for the button clicked
sender.backgroundColor = .orange
}
#IBAction func buttonTapped(_ sender: UIButton) {
updateFocusPicture(sender: sender)
}
func setupRightNavigationItems()
{
let menuButton = UIButton(type: .system)
menuButton.setImage(#imageLiteral(resourceName: "menu-white").withRenderingMode(.alwaysOriginal),for:.normal)
menuButton.contentMode = .scaleAspectFit
menuButton.frame = CGRect(x:0,y:0,width:25,height:25)
let playButton = UIButton(type: .system)
playButton.setImage(#imageLiteral(resourceName: "nowplaying32").withRenderingMode(.alwaysOriginal), for: .normal)
playButton.contentMode = .scaleAspectFit
playButton.frame = CGRect(x:0,y:0,width:25,height:25)
let nowPlaying = defaults.string(forKey: "NOWPLAYING")
if nowPlaying == "true"
{
playButton.isHidden = false
}
else
{
playButton.isHidden = true
}
menuButton.addTarget(self, action: #selector(menuButtonClicked), for: UIControlEvents.touchUpInside)
playButton.addTarget(self, action: #selector(notificationPlayButtonClicked), for: UIControlEvents.touchUpInside)
navigationItem.rightBarButtonItems = [UIBarButtonItem(customView:menuButton),UIBarButtonItem(customView:playButton)]
}
The button gets hide when i called this function i.e setupRightNavigationItems in viewWillAppear but it does not reflect the changes of button getting hide inside the view, when i call it from another function after checking the condition please help !.
When you want to hide
self.navigationItem.rightBarButtonItem = nil
You can do as below to hide and show a navigation button
Hide:
self.navigationItem.rightBarButtonItem?.tintColor = .clear
self.navigationItem.rightBarButtonItem?.isEnabled = false
Show:
self.navigationItem.rightBarButtonItem?.tintColor = yourbuttonTint color
self.navigationItem.rightBarButtonItem?.isEnabled = true
try to set nil first, then set the buttons to refresh view.
func setupRightNavigationItems() {
// here your rest code
// set nil here >>>
navigationItem.rightBarButtonItems = nil
navigationItem.rightBarButtonItems = [UIBarButtonItem(customView:menuButton),UIBarButtonItem(customView:playButton)]
}
Your code is working good. Just check your condition is correct or not.
class DemoVC: UIViewController {
var flag = "true"
override func viewDidLoad() {
super.viewDidLoad()
setupRightNavigationItems()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
flag = "false"
setupRightNavigationItems()
}
#IBAction func onBtnChange(_ sender : UIButton) {
flag = "true"
setupRightNavigationItems()
}
func setupRightNavigationItems()
{
print("called")
let menuButton = UIButton(type: .system)
menuButton.setImage(#imageLiteral(resourceName: "likesong").withRenderingMode(.alwaysOriginal),for:.normal)
menuButton.contentMode = .scaleAspectFit
menuButton.frame = CGRect(x:0,y:0,width:25,height:25)
let playButton = UIButton(type: .system)
playButton.setImage(#imageLiteral(resourceName: "likesong").withRenderingMode(.alwaysOriginal), for: .normal)
playButton.contentMode = .scaleAspectFit
playButton.frame = CGRect(x:0,y:0,width:25,height:25)
let nowPlaying = "true"//defaults.string(forKey: "NOWPLAYING")
if nowPlaying.lowercased() == flag.lowercased()
{
playButton.isHidden = true
}
else
{
playButton.isHidden = false
}
self.navigationItem.rightBarButtonItems = [UIBarButtonItem(customView:menuButton),UIBarButtonItem(customView:playButton)]
}
}
i'm calling this function from viewDidLoad and working good.i just added static condition for test.
On touchesBegan button get visible and on onBtnChange again get hidden.
Try this, Hope this work.
You are right it won't hide when called from function other than willAppear or didLoad , because both bar button items are already created. You can't simply hide it,
So before calling this function, remove rightBarButtonItem, Now every thing will be OK.
Try this,
#IBAction func hideNavigationBar(_ sender: UIButton) {
navigationItem.rightBarButtonItems = nil
setupRightNavigationItems()
}
Try This too
let nowPlaying = defaults.string(forKey: "NOWPLAYING")
if nowPlaying == "true"
{
navigationItem.rightBarButtonItems = [UIBarButtonItem(customView:menuButton),UIBarButtonItem(customView:playButton)]
}
else
{
navigationItem.rightBarButtonItems = [UIBarButtonItem(customView:menuButton)]
}
Result:
I currently have a UITextfield with an eye icon in it that when pressed is supposed to toggle the secure text entry on and off.
I know you can check mark the "secure text entry" box in the attributes inspector but how to do it so it toggles whenever the icon is pressed?
Use this code,
iconClick is bool variable, or you need other condition check it,
var iconClick = true
eye Action method:
#IBAction func iconAction(sender: AnyObject) {
if iconClick {
passwordTF.secureTextEntry = false
} else {
passwordTF.secureTextEntry = true
}
iconClick = !iconClick
}
hope its helpful
An unintended side-effect of this is that if the user toggles to insecure, and then back to secure, the existing text will be cleared if the user continues typing. The cursor may also end up in the wrong position unless we reset the selected text range.
Below is an implementation that handles these cases (Swift 4)
extension UITextField {
func togglePasswordVisibility() {
isSecureTextEntry = !isSecureTextEntry
if let existingText = text, isSecureTextEntry {
/* When toggling to secure text, all text will be purged if the user
continues typing unless we intervene. This is prevented by first
deleting the existing text and then recovering the original text. */
deleteBackward()
if let textRange = textRange(from: beginningOfDocument, to: endOfDocument) {
replace(textRange, withText: existingText)
}
}
/* Reset the selected text range since the cursor can end up in the wrong
position after a toggle because the text might vary in width */
if let existingSelectedTextRange = selectedTextRange {
selectedTextRange = nil
selectedTextRange = existingSelectedTextRange
}
}
}
This snippet is using the replace(_:withText:) function because it triggers the .editingChanged event, which happens to be useful in my application. Just setting text = existingText should be fine as well.
Why to use an extra var. In the action method of the eye button just do as below
password.secureTextEntry = !password.secureTextEntry
UPDATE
Swift 4.2 (as per #ROC comment)
password.isSecureTextEntry.toggle()
I wrote extension for the same. To provide Password toggle.
In your Assets first add images that you want for toggle.
Add following extension for UITextField.
extension UITextField {
fileprivate func setPasswordToggleImage(_ button: UIButton) {
if(isSecureTextEntry){
button.setImage(UIImage(named: "ic_password_visible"), for: .normal)
}else{
button.setImage(UIImage(named: "ic_password_invisible"), for: .normal)
}
}
func enablePasswordToggle(){
let button = UIButton(type: .custom)
setPasswordToggleImage(button)
button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0)
button.frame = CGRect(x: CGFloat(self.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25))
button.addTarget(self, action: #selector(self.togglePasswordView), for: .touchUpInside)
self.rightView = button
self.rightViewMode = .always
}
#IBAction func togglePasswordView(_ sender: Any) {
self.isSecureTextEntry = !self.isSecureTextEntry
setPasswordToggleImage(sender as! UIButton)
}
}
Call extension on your UITextField Outlet
override func viewDidLoad() {
super.viewDidLoad()
txtPassword.enablePasswordToggle()
txtConfirmPassword.enablePasswordToggle()
}
Swift 4 solution
You don't need extra if statement for simple toggle isSecureTextEntry property
func togglePasswordVisibility() {
password.isSecureTextEntry = !password.isSecureTextEntry
}
But there is a problem when you toggle isSecureTextEntry UITextField doesn't recalculate text width and we have extra space to the right of the text. To avoid this you should replace text this way
func togglePasswordVisibility() {
password.isSecureTextEntry = !password.isSecureTextEntry
if let textRange = password.textRange(from: password.beginningOfDocument, to: password.endOfDocument) {
password.replace(textRange, withText: password.text!)
}
}
UPDATE
Swift 4.2
Instead of
password.isSecureTextEntry = !password.isSecureTextEntry
you can do this
password.isSecureTextEntry.toggle()
Use UITextFiled rightView to show toggle button
var rightButton = UIButton(type: .custom)
rightButton.frame = CGRect(x:0, y:0, width:30, height:30)
yourtextfield.rightViewMode = .always
yourtextfield.rightView = rightButton
If you need TextField with similar feature in multiple places its best to subclass the UITextField like follwing example -
import UIKit
class UIShowHideTextField: UITextField {
let rightButton = UIButton(type: .custom)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
required override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
rightButton.setImage(UIImage(named: "password_show") , for: .normal)
rightButton.addTarget(self, action: #selector(toggleShowHide), for: .touchUpInside)
rightButton.frame = CGRect(x:0, y:0, width:30, height:30)
rightViewMode = .always
rightView = rightButton
isSecureTextEntry = true
}
#objc
func toggleShowHide(button: UIButton) {
toggle()
}
func toggle() {
isSecureTextEntry = !isSecureTextEntry
if isSecureTextEntry {
rightButton.setImage(UIImage(named: "password_show") , for: .normal)
} else {
rightButton.setImage(UIImage(named: "password_hide") , for: .normal)
}
}
}
After which you can use it in any ViewController,
class ViewController: UIViewController {
#IBOutlet var textField: UIShowHideTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.becomeFirstResponder()
}
}
For Objective c
set image for RightButton In viewdidload Method
[RightButton setImage:[UIImage imageNamed:#"iconEyesOpen"] forState:UIControlStateNormal];
[RightButton setImage:[UIImage imageNamed:#"iconEyesClose"] forState:UIControlStateSelected];
and then set action method for that RightButton
-(IBAction)RightButton:(id)sender
{
if (_rightButton.selected)
{
_rightButton.selected = NO;
_passwordText.secureTextEntry = YES;
if (_passwordText.isFirstResponder) {
[_passwordText resignFirstResponder];
[_passwordText becomeFirstResponder];
}
}
else
{
_rightButton.selected = YES;
_passwordText.secureTextEntry = NO;
if (_passwordText.isFirstResponder) {
[_passwordText resignFirstResponder];
[_passwordText becomeFirstResponder];
}
}
}
Swift 3
// MARK: Btn EyeAction
#IBAction func btnEyeAction(_ sender: Any) {
if(iconClick == true) {
txtPassword.isSecureTextEntry = false
iconClick = false
} else {
txtPassword.isSecureTextEntry = true
iconClick = true
}
}
Shortest!
I think this is the shortest solution for secure entry as well as updating the picture of the button.
#IBAction func toggleSecureEntry(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
textfieldPassword.isSecureTextEntry = !sender.isSelected
}
Assign the show/hide picture of the button according to the state selected /default , no need to create any variable or outlet.
This worked for me on Swift 5.0
#IBAction func changePasswordVisibility(_ sender: UIButton) {
passwordField.isSecureTextEntry.toggle()
if passwordField.isSecureTextEntry {
if let image = UIImage(systemName: "eye.fill") {
sender.setImage(image, for: .normal)
}
} else {
if let image = UIImage(systemName: "eye.slash.fill") {
sender.setImage(image, for: .normal)
}
}
}
Button attributes:
Result:
Swift 3
passwordTF.isSecureTextEntry = true
passwordTF.isSecureTextEntry = false
#IBAction func eye_toggle_clicked(sender: AnyObject)
{
if toggleBtn.tag == 0
{
passwordTxt.secureTextEntry=true
toggleBtn.tag=1
}
else
{
passwordTxt.secureTextEntry=false
toggleBtn.tag=0
}
}
As others have noted, the property is secureTextEntry, but you won't find this in the UITextField documentation, as it is actually inherited by a UITextField through the UITextInputTraits protocol- https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/#//apple_ref/occ/intfp/UITextInputTraits/secureTextEntry
You can simply toggle this value each time your button is tapped:
#IBAction func togglePasswordSecurity(sender: UIButton) {
self.passwordField.secureTextEntry = !self.passwordField.secureTextEntry
}
try this line:
#IBAction func btnClick(sender: AnyObject) {
let btn : UIButton = sender as! UIButton
if btn.tag == 0{
btn.tag = 1
textFieldSecure.secureTextEntry = NO
}
else{
btn.tag = 0
textFieldSecure.secureTextEntry = NO;
}
}
Here is your answer no need to take any bool var:
#IBAction func showHideAction(sender: AnyObject) {
if tfPassword.secureTextEntry{
tfPassword.secureTextEntry = false
}else{
tfPassword.secureTextEntry = true;
}
}
First you need to set image(visible or hide) of button of eye for different state (selected or normal)
than connect IBAction and write code like
#IBAction func btnPasswordVisiblityClicked(_ sender: Any) {
(sender as! UIButton).isSelected = !(sender as! UIButton).isSelected
if (sender as! UIButton).isSelected {
txtfPassword.isSecureTextEntry = false
} else {
txtfPassword.isSecureTextEntry = true
}
}
In Swift 4
var iconClick : Bool!
override func viewDidLoad() {
super.viewDidLoad()
iconClick = true
}
#IBAction func showHideAction(_ sender: Any)
{
let userPassword = userPasswordTextFiled.text!;
if(iconClick == true) {
userPasswordTextFiled.isSecureTextEntry = false
iconClick = false
} else {
userPasswordTextFiled.isSecureTextEntry = true
iconClick = true
}
}
Assignment values change from YES/NO to true/false boolean values.
password.secureTextEntry = true //Visible
password.secureTextEntry = false //InVisible
You can try this code..
i think it's helpful.
Use button with eye image
and make buttonHandler method
set Tag for button with value 1
-(IBAction) buttonHandlerSecureText:(UIButton *)sender{
if(sender.tag ==1){
[self.textField setSecureTextEntry:NO];
sender.tag = 2;
}
else{
[self.textField setSecureTextEntry:YES];
sender.tag = 1;
}
}
For Xamarin folks:
passwordField.SecureTextEntry = passwordField.SecureTextEntry ? passwordField.SecureTextEntry = false : passwordField.SecureTextEntry = true;
Try this code in swift 4, tried to make a reusable code within a controller. I have set different image for buttons in storyboard as shown in the link https://stackoverflow.com/a/47669422/8334818
#IBAction func clickedShowPassword(_ sender: UIButton) {
var textField :UITextField? = nil
print("btn ",sender.isSelected.description)
switch sender {
case encryptOldPswdBtn:
encryptOldPswdBtn.isSelected = !encryptOldPswdBtn.isSelected
textField = oldPasswordTextField
default:
break
}
print("text ",textField?.isSecureTextEntry.description)
textField?.isSecureTextEntry = !(textField?.isSecureTextEntry ?? false)
}
#objc func togglePasscode(){
switch textfield.isSecureTextEntry{
case true:
textfield.isSecureTextEntry = false
case false:
textfield.isSecureTextEntry = true
}
}
Here is a easy and more readable solution using Switch statement.
Hope this is simpler solution rather than creating a BOOL object globally.
#IBAction func passwordToggleButton(sender: UIButton) {
let isSecureTextEntry = passwordTextField.isSecureTextEntry
passwordTextField.isSecureTextEntry = isSecureTextEntry ? false : true
if isSecureTextEntry {
visibilityButton.setImage(UIImage(named: "visibility"), for: .normal)
} else {
visibilityButton.setImage(UIImage(named: "visibility_off"), for: .normal)
}
}
only add this line into your code replace you TextField name with "textfield" Done:
you need to change the isSecureTextEntry propertity to change true for password type textFiled like ......
textField.isSecureTextEntry = true
sender.isSelected = !sender.isSelected
if(sender.isSelected == true) {
RegPasswordField.isSecureTextEntry = false
sender.setBackgroundImage(UIImage(systemName: "eye.fill"), for: .normal)
} else {
RegPasswordField.isSecureTextEntry = true
sender.setBackgroundImage(UIImage(systemName: "eye"), for: .normal)
}
Swift 5 Please use this
var btnClick = true
if(btnClick == true) {
passwordTextField.isSecureTextEntry = false
} else {
passwordTextField.isSecureTextEntry = true
}
btnClick = !btnClick
}
var viewingPassword = true
#IBAction func btnEyeAction(_ sender: Any) {
passwordTF.isSecureTextEntry = viewingPassword ? false : true
viewingPassword.toggle()
}