In my case, I am trying to create multiple buttons using storyboard. Here, each buttons having on and off background and title color change. In this process as of now I am doing same logic repeated in each button action. Now, instead of that I have to create a common function within one time logics for all button action have to call and work like a on and off individually.
How to make this below logic in a common function and call it from multiple button actions.
Code Base
#IBAction func firstbuttonClick(_ sender: Any) {
if button_isActive {
self.tasktypeButton.backgroundColor = #colorLiteral(red: 0.1843137255, green: 0.6823529412, blue: 0.9764705882, alpha: 1)
self.tasktypeButton.setTitleColor(UIColor.white, for: .normal)
} else {
self.tasktypeButton.backgroundColor = #colorLiteral(red: 0.80803, green: 0.803803, blue: 0.805803, alpha: 1)
self.tasktypeButton.setTitleColor(UIColor.darkGray, for: .normal)
}
button_isActive = !button_isActive
}
You can connect all UIButton action in one like below code.
#IBAction func btnTapped(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
sender.setTitleColor(UIColor.white, for: .normal)
sender.backgroundColor = UIColor.red
}
else {
sender.setTitleColor(UIColor.black, for: .normal)
sender.backgroundColor = UIColor.white
}
//For identifing which button is tapped
if sender.tag == 1 {
// Do your task
}
else if sender.tag == 2 {
// Do your task
}
}
If you want to detect which button is tapped, you can set tag to UIButton from UIStoryBoard.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var btn1: UIButton!
#IBOutlet weak var btn2: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func btnactn(btnTag:Int)
{
print(btnTag)
switch btnTag {
case 0:
self.btn1.backgroundColor = #colorLiteral(red: 0.1843137255, green: 0.6823529412, blue: 0.9764705882, alpha: 1)
self.btn1.setTitleColor(UIColor.white, for: .normal)
case 1:
self.btn2.backgroundColor = #colorLiteral(red: 0.80803, green: 0.803803, blue: 0.805803, alpha: 1)
self.btn2.setTitleColor(UIColor.white, for: .normal)
default:
break
}
}
#IBAction func btnActn1(_ sender: UIButton)
{
self.btnactn(btnTag: sender.tag)
}
#IBAction func btnActn2(_ sender: UIButton)
{
self.btnactn(btnTag: sender.tag)
}}
its working i have tried this. you just need to connect button outlets and its functions.you can try this.
First of all connect all the UIButtons in the storyboard to the same #IBAction. Also, don't forget to select the UIButton as parameter type when creating the #IBAction.
Next, in the method sender is the UIButton that is clicked. So you can use that for further configuration.
#IBAction func buttonClicked(_ sender: UIButton) {
sender.backgroundColor = sender.isSelected ? #colorLiteral(red: 0.1843137255, green: 0.6823529412, blue: 0.9764705882, alpha: 1) : #colorLiteral(red: 0.80803, green: 0.803803, blue: 0.805803, alpha: 1)
sender.setTitleColor(sender.isSelected ? .white : .darkGray, for: .normal)
//User sender to get the button that is clicked...
let title = sender.titleLabel?.text
print(title)
sender.isSelected = !sender.isSelected
}
One more thing, use isSelected to manage the backgroundColor and titleColor of the button instead of a separate button_isActive property.
You can create only one function as below and connect all the button actions in storyboard to this function so that any button will update its state.
#IBAction private func buttonAction(_ sender: UIButton) {
if button_isActive {
sender.backgroundColor = #colorLiteral(red: 0.1843137255, green: 0.6823529412, blue: 0.9764705882, alpha: 1)
sender.setTitleColor(UIColor.white, for: .normal)
} else {
sender.backgroundColor = #colorLiteral(red: 0.80803, green: 0.803803, blue: 0.805803, alpha: 1)
sender.setTitleColor(UIColor.darkGray, for: .normal)
}
button_isActive = !button_isActive
// To differentiate different buttons
switch (sender.tag) {
case 0:
print(sender.title(for: .normal))
case 1:
print(sender.title(for: .normal))
default:
print(sender.title(for: .normal))
}
}
You can also set tag for each in the storyboard and differentiate in above method to know what button click is this.
Related
I am following this tutorial provided on Youtube for: How to Save Data with UserDefaults - Swift
https://www.youtube.com/watch?v=sUhq1vIrRbo
And I have this code that works for one page only and would like to know how to do the same exact thing (changing background color) but for my entire app pages based on the user's choice.
I have tried keeping the checkForStylePreference() in the viewDidLoad()of another page but it did not recognize it. I copy pasted the whole checkForStylePreference() but still other pieces of code were missing. Is the only way to do it is by copy pasting all of the methods of the viewController in all App pages? Or there is a much simpler way as a believe to reduce amount of code? Currently I can change BgColor from white to grey perfectly enter image description here but I don't know how to apply it for all.
This is the code of my NameViewController.swift (the one I've created for the page in the screenshot). Please note that I have 2 more swift files which are SAButton.swift and ConstantStyles.swift (for the colors)
class NameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
nameLbl.text = myString
checkForStylePreference()
}
#IBAction func didChangeStyleSeg(_ sender: UISegmentedControl) {
isDarkMode = sender.selectedSegmentIndex == 1
saveStylePreference()
updateStyle()
}
var myString = String()
#IBOutlet weak var styleSegment: UISegmentedControl!
#IBOutlet weak var nameLbl: UILabel!
var isDarkMode = false
let defaults = UserDefaults.standard
struct Keys {
static let preferDarkMode = "preferDarkMode"
}
func updateStyle(){
UIView.animate(withDuration: 0.4){
// self.view.backgroundColor = self.isDarkMode ? Colors.darkGrey : .white
// UIColor(hue: 287/360, saturation: 15/100, brightness: 85/100, alpha: 1.0)
self.view.backgroundColor = self.isDarkMode ? Colors.lightGrey : .white
//recent correct one
// self.view.backgroundColor = self.isDarkMode ? Colors.darkGrey : .white
//self.view.UIBackgroundFetchResult = self.isDarkMode? UIColor.grey : .white
}
}
func saveStylePreference(){
defaults.set(isDarkMode, forKey: Keys.preferDarkMode)
}
func checkForStylePreference(){
let preferDarkMode = defaults.bool(forKey: Keys.preferDarkMode)
if preferDarkMode{
isDarkMode = true
updateStyle()
styleSegment.selectedSegmentIndex = 1
}
}
// Do any additional setup after loading the view.
}
Code of the SAButton.swift
class SAButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
setupButton()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupButton()
}
private func setupButton() {
setTitleColor(.white, for: .normal)
backgroundColor = Colors.lightBlue
titleLabel?.font = .boldSystemFont(ofSize: 20)
layer.cornerRadius = frame.size.height / 2
}
}
Code of the ConstantStyles.swift
import UIKit
struct Colors {
static let darkGrey = UIColor(red: 40/255, green: 40/255, blue: 40/255, alpha: 1)
// static let purple = UIColor(red: 212/255, green: 186/255, blue: 86/255, alpha: 1)
static let lightBlue = UIColor(red: 89/255, green: 205/255, blue: 242/255, alpha: 1)
static let darkPurple = UIColor(red: 242/255, green: 232/255, blue: 255/255, alpha: 1.0)
// UIColor(hue: 287/360, saturation: 15/100, brightness: 85/100, alpha: 1.0)
static let lightPurple = UIColor(red: 240/255, green: 229/255, blue: 255/255, alpha: 1.0)
static let lightGrey = UIColor(red: 237/255, green: 237/255, blue: 237/255, alpha: 1.0)
//UIColor(red: 249/255, green: 244/255, blue: 255/255, alpha: 1.0)
}
I believe it could be simple but I am new to Swift, I would like to know what part of code to keep exactly and where. Much appreciated.
Ps: Original project Source Code is provided below the Youtube Video.
You can create a main class and inherit from it
class GeneralVC : UIViewController {
override func viewDidLoad() {
self.view.backgroundColor = .red // read color from userdefaults and set it here
}
}
class ViewController: GeneralVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Same applies to any UIKit component that you need to affect globally
Another interesting way to do it is to use Appearance:
Perhaps you can use UIViewControllerWrapperView as a parent.
UIView.appearance(whenContainedInInstancesOf: [UIViewControllerWrapperView]) // UIViewControllerWrapperView might be private. In that case it might take some wizardry to get it to work
Another way to do it is to set it when the UITabBarController or UINavigationController presents a new UIViewController. You can do this by subclassing them.
The reason why I don't like subclassing is that you force a subclass for just one simple thing. If you only do it in a few navigation based ones it's much easier and also easier to override with extensions instead of everything through subclassing.
How can I save the state of my toggle button using userdefaults? Here is the code, please help me.
import UIKit
class LawFigure: UIViewController {
//Outlets:
#IBOutlet weak var likeButton: UIButton!
//Variables:
var isButtonOn = false
override func viewDidLoad() {
super.viewDidLoad()
customiseUI()
}
func customiseUI() {
likeButton.layer.borderWidth = 3.0
likeButton.layer.borderColor = UIColor(red: 0/255, green: 166/255, blue: 221/255, alpha: 1.0).cgColor
likeButton.layer.cornerRadius = 20.0
likeButton.clipsToBounds = true
}
#IBAction func followActionPressed(_ sender: Any) {
self.activateButton(bool: !isButtonOn)
}
func activateButton(bool: Bool) {
isButtonOn = bool
likeButton.backgroundColor = bool ? UIColor(red: 0/255, green: 166/255, blue: 221/255, alpha: 1.0) : .clear
likeButton.setTitle(bool ? "unlike": "like", for: .normal)
likeButton.setTitleColor(bool ? .white : UIColor(red: 0/255, green: 166/255, blue: 221/255, alpha: 1.0), for: .normal)
}
}
You can try every open of the app
likeButton.isEnabled = !(UserDefaults.standard.bool(forKey:"IsBtnEnabled"))
whenever button is clicked save it
UserDefaults.standard.set(state, forKey: "IsBtnEnabled")
var isButtonOn = UserDefaults.standard.bool(forKey: "isButtonOn")
override func viewDidLoad() {
super.viewDidLoad()
activateButton(bool: isButtonOn)
customiseUI()
}
func activateButton(bool: Bool) {
isButtonOn = bool
UserDefaults.standard.set(isButtonOn, forKey: "isButtonOn")
UserDefaults.standard.synchronize()
likeButton.backgroundColor = bool ? UIColor(red: 0/255, green: 166/255, blue: 221/255, alpha: 1.0) : .clear
likeButton.setTitle(bool ? "unlike": "like", for: .normal)
likeButton.setTitleColor(bool ? .white : UIColor(red: 0/255, green: 166/255, blue: 221/255, alpha: 1.0), for: .normal)
}
I've got a MainViewController where I'm loading a slideout-menu. The MainViewController contains a static TopView and a ContentView where different child controllers or views are loaded, depending on which menu entry was selected.
There is a button inside one of the children is loaded, but it is not working.
When I start the app with the ViewController including the button, set to "is initial View Controller", everything works properly.
When starting the app with the MainViewController as initial View Controller with a loaded child, the button is not working (it is loaded in the view, but not reacting).
Any suggestions how I can make this work?
MainViewController loading of Child View
class MainViewController: UIViewController, SideBarDelegate {
var contentView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
....
contentView.backgroundColor = UIColor(red: 70/255, green: 174/255, blue: 253/255, alpha: 1)
contentView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(contentView)
contentView.topAnchor.constraint(equalTo: statusBarView.bottomAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
contentView.layoutIfNeeded()
}
func sideBarDidSelectButtonAtIndex(_ index: Int) {
...
if index == 0{
statusBarLabel.text = "First"
let controller:FirstViewController = storyboard!.instantiateViewController(withIdentifier: "First") as! FirstViewController
controller.view.frame = ContentView.bounds
controller.willMove(toParentViewController: self)
contentView.addSubview(controller.view)
controller.didMove(toParentViewController: self)
print("touched index 0")
} else if index == 1{
// index is 1
}
}
FirstViewController
class FirstViewController: UIViewController, UIScrollViewDelegate {
let addButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1)
addButton.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 60)
addButton.clipsToBounds = true
addButton.setTitleColor(UIColor.white, for: .normal)
addButton.backgroundColor = UIColor(red: 102/255, green: 204/255, blue: 255/255, alpha: 1)
addButton.setTitle("add feed", for: .normal)
addButton.titleLabel?.font = UIFont.systemFont(ofSize: 20, weight: UIFontWeightRegular)
self.view.addSubview(AddButton)
addButton.layoutIfNeeded()
addButton.addTarget(self, action: #selector(touchUpAddButton), for: UIControlEvents.touchUpInside)
addButton.addTarget(self, action: #selector(touchDownAddButton), for: UIControlEvents.touchDown)
func touchUpAddButton() {
addButton.backgroundColor = UIColor(red: 102/255, green: 204/255, blue: 255/255, alpha: 1)
}
func touchDownAddButton() {
addButton.backgroundColor = UIColor(red: 70/255, green: 174/255, blue: 253/255, alpha: 1)
}
}
While adding the view in the container you don't have to use addSubview function, that the FirstViewController functionality is not working.
Use below code:
let newViewController:FirstViewController = storyboard!.instantiateViewController(withIdentifier: "First") as! FirstViewController
let oldViewController = childViewControllers.last! as UIViewController
oldViewController.willMove(toParentViewController: nil)
addChildViewController(newViewController)
transition(from: oldViewController, to: newViewController, duration: 0.25, options: .transitionCrossDissolve, animations:{ () -> Void in
// nothing needed here
}, completion: { (finished) -> Void in
oldViewController.removeFromParentViewController()
newViewController.didMove(toParentViewController: self)
})
You can change the duration, it used for animation
Update your functions to these
func TouchUpAddButton(sender: UIButton){
addButton.backgroundColor = UIColor(red: 102/255, green: 204/255, blue: 255/255, alpha: 1)
}
func TouchDownAddButton(sender: UIButton) {
addButton.backgroundColor = UIColor(red: 70/255, green: 174/255, blue: 253/255, alpha: 1)
}
And change your code of adding the target to
addButton.addTarget(self, action: #selector(FirstViewController.touchUpAddButton(_:)), for: .touchDown)
addButton.addTarget(self, action: #selector(FirstViewController.touchDownAddButton(_:)), for: .touchDown)
First solution:
Remove an autolayout constrains
Second solution:
Button is not performing an action because a child view controller view should be added directly to a container controller view (in your case: MainViewController view) and not via an intermediate view (in your case: contentView)
I want to go to another view controller when pressing button my btnSignUp, If I write code like this I have error "sigabrt". What I should do?
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 15/255, green: 52/255, blue: 100/255, alpha: 1)
createTop()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func createTop() {
let topView = UIView()
self.view.addSubview(topView)
topView.backgroundColor = UIColor(red: 15/255, green: 52/255, blue: 100/255, alpha: 1)
topView.snp_makeConstraints { (make) -> Void in
make.width.equalTo((self.view.frame.width/10)*8)
make.height.equalTo(self.view.frame.height/5)
make.centerX.equalTo(self.view)
make.top.equalTo(self.view).offset(self.view.frame.height/15)
}
let btnSignUp = UIButton()
self.view.addSubview(btnSignUp)
btnSignUp.backgroundColor = UIColor(red: 15/255, green: 52/255, blue: 100/255, alpha: 1)
btnSignUp.layer.borderColor = UIColor.whiteColor().CGColor
btnSignUp.layer.borderWidth = 1
btnSignUp.layer.cornerRadius = 6
btnSignUp.setTitle("Sign Up", forState: UIControlState.Normal)
btnSignUp.titleLabel?.font = UIFont(name: "AvenirNext-Regular", size: 17)
btnSignUp.snp_makeConstraints { (make) -> Void in
make.width.equalTo(((self.view.frame.width/10)*7)+40)
make.height.equalTo(self.view.frame.height/13)
make.top.equalTo(ORView.snp_bottom).offset(20)
make.centerX.equalTo(self.view)
}
btnSignUp.addTarget(self, action: "buttonAction", forControlEvents: UIControlEvents.TouchUpInside)
func buttonAction(sender:UIButton!)
{
let signUpVC = SignUpViewController()
self.presentViewController(signUpVC, animated: true, completion: nil)
}
}
}
Your action selector buttonAction doesn't match your function declaration - It takes an argument, so the selector will be buttonAction:
btnSignUp.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
Additionally, check your parentheses. It appears that your buttonAction function is declared inside func createTop()
func createTop() {
let topView = UIView()
self.view.addSubview(topView)
topView.backgroundColor = UIColor(red: 15/255, green: 52/255, blue: 100/255, alpha: 1)
topView.snp_makeConstraints { (make) -> Void in
make.width.equalTo((self.view.frame.width/10)*8)
make.height.equalTo(self.view.frame.height/5)
make.centerX.equalTo(self.view)
make.top.equalTo(self.view).offset(self.view.frame.height/15)
}
let btnSignUp = UIButton()
self.view.addSubview(btnSignUp)
btnSignUp.backgroundColor = UIColor(red: 15/255, green: 52/255, blue: 100/255, alpha: 1)
btnSignUp.layer.borderColor = UIColor.whiteColor().CGColor
btnSignUp.layer.borderWidth = 1
btnSignUp.layer.cornerRadius = 6
btnSignUp.setTitle("Sign Up", forState: UIControlState.Normal)
btnSignUp.titleLabel?.font = UIFont(name: "AvenirNext-Regular", size: 17)
btnSignUp.snp_makeConstraints { (make) -> Void in
make.width.equalTo(((self.view.frame.width/10)*7)+40)
make.height.equalTo(self.view.frame.height/13)
make.top.equalTo(ORView.snp_bottom).offset(20)
make.centerX.equalTo(self.view)
}
btnSignUp.addTarget(self, action: "buttonAction", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonAction(sender:UIButton!) {
let signUpVC = SignUpViewController()
self.presentViewController(signUpVC, animated: true, completion: nil)
}
Finally, I doubt that you want to get your new view controller by SignUpViewController() - if you are using a storyboard you want to call instantiateViewControllerWithIdentifier
I am trying to add button to the programatically created view that I add to main view. I can't make action to work on a button. This is what I tried so far:
itemView = UIImageView(frame:CGRect(x:0, y:0, width:240, height:375))
itemView.backgroundColor = UIColor(red: 255.0/0.0, green: 255.0/0.0, blue: 255.0/0.0, alpha: 0.05)
itemView.contentMode = .Center
buttonConnect = UIButton(frame: CGRect(x:0, y:335, width:120, height:40))
buttonConnect.backgroundColor = UIColor(red: 0.8, green: 0.6, blue: 0.2, alpha: 1.0)
buttonConnect.setTitle("Connect", forState: .Normal)
buttonConnect.tag = 3
buttonConnect.addTarget(itemView, action: "btnConnectTouched:", forControlEvents:.TouchDown)
itemView.addSubview(buttonConnect)
self.addSubview(itemView)
Method on button click looks like this:
func btnConnectTouched(sender:UIButton!)
{
print("button connect touched")
}
Can someone advice what is the problem? Thanks!
I don't understand why you are adding a button inside a UIImageView. Even this is what you need, take a UIView and then put all other controls inside it. The reason your button is not clicking is that you have put it inside a UIImageView and for UIImageView , default value for userInteractionEnabled is false. so you need to enable it i.e.
itemView.userInteractionEnabled = true;
Also set button target to 'self' rather than itemView.
Try change the tarjet and the event
buttonConnect.addTarget(itemView, action: "btnConnectTouched:", forControlEvents:.TouchDown)
into
buttonConnect.addTarget(self, action: "btnConnectTouched:", forControlEvents:. TouchUpInside)
You are wrong at the target:
// buttonConnect.addTarget(itemView, action: "btnConnectTouched:", forControlEvents:.TouchDown)
// using
buttonConnect.addTarget(self, action: "btnConnectTouched:", forControlEvents:.TouchDown)
// or buttonConnect.addTarget(self, action: "btnConnectTouched:", forControlEvents:.TouchUpInside)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let buttonConnect = UIButton()
buttonConnect = UIButton(frame: CGRect(x:0, y:335, width:120, height:40))
buttonConnect.backgroundColor = UIColor(red: 0.8, green: 0.6, blue: 0.2, alpha: 1.0)
buttonConnect.setTitle("Connect", forState: .Normal)
buttonConnect.tag = 3
buttonConnect.addTarget(self, action: "btnConnectTouched:", forControlEvents: .TouchUpInside)
self.view.addSubview(buttonConnect)
}
func btnConnectTouched(sender: UIButton!) {
print("button connect touched");
}
try buttonConnect.addTarget(itemView, action: "btnConnectTouched", forControlEvents:.TouchUpInside) without the : after "btnConnectTouched"
If you can make following two changes in your code, it will work.
Replace UIImageView with UIView for itemView type and
Replace self.addSubview(itemView) with self.view.addSubview(itemView)
Your final code should look like....
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var itemView = UIView(frame:CGRect(x:0, y:0, width:240, height:375))
itemView.backgroundColor = UIColor(red: 255.0/0.0, green: 255.0/0.0, blue: 255.0/0.0, alpha: 0.05)
itemView.contentMode = .Center
var buttonConnect = UIButton(frame: CGRect(x:0, y:335, width:120, height:40))
buttonConnect.backgroundColor = UIColor(red: 0.8, green: 0.6, blue: 0.2, alpha: 1.0)
buttonConnect.setTitle("Connect", forState: .Normal)
buttonConnect.tag = 3
buttonConnect.addTarget(self, action: "btnConnectTouched:", forControlEvents:.TouchDown)
itemView.addSubview(buttonConnect)
self.view.addSubview(itemView)
}
func btnConnectTouched(sender:UIButton!)
{
print("button connect touched")
}
Try this one.... It's working for me....