UITextField.textColor not called until UITextField gets focus - swift3

Could anybody explain please how/when .textColor is called for the UITextField?
XCode9, Swift 4
Consider the following code:
import UIKit
class TestViewController: UIViewController {
#IBOutlet weak var txt1: UITextField!
#IBOutlet weak var txt2: UITextField!
#IBAction func btnaction(_ sender: UIButton) {
txt1.textColor=UIColor.red
txt1.backgroundColor=UIColor.green.withAlphaComponent(0.5)
txt2.textColor=UIColor.red
txt2.backgroundColor=UIColor.green.withAlphaComponent(0.5)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Everything is connected. When you run it and click on the button, only the backgroundColor gets set immediately. The .textColor remains the same. Only when the text field gets a focus, only then the .textColor changes.
Is this correct behaviour or a bug?
Thank you for comments.
I tried the same code in XCode 8, Swift 3 and it worked fine, so I believe it is probably a bug.

Related

Found nil while unwrapping an optional value while setting textColor of label

I am new in ios and I am making an app using XCode 9.2 with swift 3.2.I am facing a problem which is i am setting textColor of label but it show an error which is: Found nil while unwrapping an optional value in line titleBar.textColor = UIColor.white
this happens for all IBOutlet in viewController of this class but in same project other view controller work fine Please help me.
My code is :
#IBOutlet weak var titleBar: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
titleBar.textColor = UIColor.white
}
The cause of the app crash or found nil is the #IBOutlet is not connected with the storyboard.. somehow the #IBOutlet connection is broken... please check and connect it and then try the code.
*After the connection is done you can use this code -
#IBOutlet weak var titleBar: UILabel! {
didSet {
titleBar.textColor = UIColor.white
}
}
Add self.titleBar.textColor = UIColor.white and also make sure that you have properly bind the IBOutlet in to your class file

Show different Views based on conditions on button click in Swift 3?

I have a ViewControllertheir is a button at top right side. When i click that button i want to Show/Hide a UIView at bottom with size half of ViewControlleron same ViewController . Anyone help me. Thanks in advance.
If only Show/Hide a UIView is your requirement, below code will work:
class ViewController: UIViewController
{
#IBOutlet weak var viewHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var customView: UIView!
override func viewDidLoad()
{
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.viewHeightConstraint.constant = self.view.bounds.height / 2
}
#IBAction func onShowHideButtonPress(_ sender: UIButton)
{
self.customView.isHidden = !self.customView.isHidden
}
}
Storyboard:

Which lifecycle do I activate and deactivate constraints for Swift

I'm struggling with when is the correct time to activate or deactivate constraints in the storyboard.
I've made an extremely simplified view controller showing this issue I'm having.
Basically, there is UIView (the red box) and inside of that is the UIScrollView, and finally inside of that is the label containing the text. The UIScrollView is 15 away from all edges of the red UIView it is inside of. And the UILabel is 0 on all sides from the UIScrollView it is inside of. By default, I have a constraint from the bottom (called bottomConst) of the red UIView to the bottom of the super view. Meaning its always the same distance. And if nothing is changed it will look the following way on both a 4 inch and 4.7 inch screen. This is initiated as isActive = true.
.
As you can see, there is a large amount of blank white space on the 4.7 inch screen.
To fix this I've added a second constraint that controls the height of the red UIView (called heightConst) and this is initiated as isActive = false.
I use the code to check after layoutIfNeeded() if the bounds height of the UIScrollView is taller than the contentSize height of the UIScrollView. And if it is, then it deactivates the bottomConst and activates the heightConst. The problem is, instead of that happening. I end up getting a zero height UIScrollView and a UIView that 30 tall because of the 15 on top and bottom edge constraints.
But if I manually go in and switch them before running them, everything looks correct.
Here is the code I'm using. (see below)
I've tried placing the code in various places such as viewDidLoad, viewDidAppear, viewWillLayoutSubviews, viewDidLayoutSubviews. But none of them seem to work. I'm starting to wonder if I should be calling the LayoutIfNeeded() in a separate lifecycle but there are so many possibilities of how to do that I figured I'd come the people who always seem to know best. Any help would be much appreciated.
import UIKit
class ViewController: UIViewController {
#IBOutlet var bottomConst: NSLayoutConstraint!
#IBOutlet var heightConst: NSLayoutConstraint!
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
scrollView.setNeedsLayout()
scrollView.layoutIfNeeded()
let scrollHeight = scrollView.contentSize.height
if (scrollHeight <= scrollView.bounds.height) {
bottomConst.isActive = false
heightConst.constant = scrollHeight + 30
heightConst.isActive = true
view.layoutIfNeeded()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Well, I was able to find the answer to my problem. But its slightly complicated, and also may depend on how the view controller is setup.
For the case I show above the following code worked.
import UIKit
class ViewController: UIViewController {
#IBOutlet var bottomConst: NSLayoutConstraint!
#IBOutlet var heightConst: NSLayoutConstraint!
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view.setNeedsLayout()
view.layoutIfNeeded()
let scrollHeight = scrollView.contentSize.height
if (scrollHeight <= scrollView.bounds.height) {
bottomConst.isActive = false
heightConst.constant = scrollHeight + 30
heightConst.isActive = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Turns out putting that code in viewWillAppear was where it needed to go, and marking the view as setNeedsLayout instead of the scrollView. But I also had another case that was very similar to the one I described above except the bottom constraint wasn't to the super view, it was to another UIView. In that case even with using the new code I still got a 0 height scrollView.
After doing some testing, I found that heightConst would remain true after I set it in the above code. But then it would go through the viewWillLayoutSubviews and viewDidLayoutSubviews one final time and in those it would become false again. My work around for that was to modify my code to the following.
import UIKit
class ViewController: UIViewController {
var changeSize: Bool = false //Additional Code
#IBOutlet var bottomConst: NSLayoutConstraint!
#IBOutlet var heightConst: NSLayoutConstraint!
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view.setNeedsLayout()
view.layoutIfNeeded()
let scrollHeight = scrollView.contentSize.height
if (scrollHeight <= scrollView.bounds.height) {
changeSize = true //Addition Code
bottomConst.isActive = false
heightConst.constant = scrollHeight + 30
heightConst.isActive = true
}
}
//Addition Code
override function viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if (changeSize == true && heightConst.isActive == false) {
heightConst.isActive = true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
But ultimately, the way I found the work around was to put a print() function in each lifecycle and see what it was reporting that constraint was. That way, I could see when it was going wrong. Hopefully this helps someone else in the future!

Swift - changing container from viewController

In the main viewController, I placed Container View and 2 buttons below it. I want to change only the container part by these buttons. Default is showing container1 and when the button2 is pressed, container part switches to container2. How should I do this? Thanks,
Based on this article, I made my version and it works.
In his article, he sets alpha value of container2 as 0 in interface builder. However, this didn't work for me. So, I set alpha values in interface builder 1 for both containers as below screen shots.
and here is the code for main viewController.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var containerViewA: UIView!
#IBOutlet weak var containerViewB: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// below sets the container1 as default
self.containerViewA.alpha = 1
self.containerViewB.alpha = 0
}
#IBAction func button1(_ sender: Any) {
self.containerViewA.alpha = 1
self.containerViewB.alpha = 0
}
#IBAction func button2(_ sender: Any) {
self.containerViewA.alpha = 0
self.containerViewB.alpha = 1
}
}

Can't click button inside UITableViewCell?

I'm using storyboard to create a UITableView, loading up some data to recommend users to follow, and including a follow button inside the cell.
Only problem is, I'm not able to click the follow button inside the cell.
Here's the code for the TableView in my ViewController class (It isn't a TableViewController, it's a UIViewController that includes UITableViewDelegate and UITableViewDataSource):
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return followRecommendations.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let followCell = tableView.dequeueReusableCell(withIdentifier: "followCell", for: indexPath) as! FollowRecommendationTableViewCell
followCell.followButton.tag = indexPath.row
followCell.followButton.addTarget(self, action: #selector(self.buttonTapped), for: UIControlEvents.touchUpInside)
followCell.followRecommendationName.text = followRecommendations[indexPath.row].suggestedUserName
followCell.followRecommendationInterests.text = followRecommendations[indexPath.row].suggestedUserTasteString
let imageUrl = followRecommendations[indexPath.row].suggestedUserImage
followCell.followRecomendationImage.downloadedFrom(link: imageUrl)
return followCell
}
func buttonTapped() {
print("Tapped")
}
and here's the code for the TableViewCell class.
class FollowRecommendationTableViewCell: UITableViewCell {
#IBOutlet weak var followRecomendationImage: UIImageView!
#IBOutlet weak var followRecommendationName: UILabel!
#IBOutlet weak var followRecommendationInterests: UILabel!
#IBOutlet weak var followButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
I've seen this question on StackOverflow before, but I wasn't able to fix the problem. Here are some things I've tried:
Numerous variations of enabling/disabling user interaction for the tableView, cell, content view, and button.
Moving the button to the front of the content view using this code: followCell.bringSubview(toFront: followCell.followButton)
I've tried the delegate/protocol method shown in this tutorial: http://candycode.io/how-to-properly-do-buttons-in-table-view-cells/
I just can't seem to get it to work.
Has anyone else had this issue and figured out a solution?
Thanks in advance!
I checked - your code works fine. You probably don't have IBOutlet set for your button on the cell, either in Storyboard, (or in separate .xib file if you use it). Open your storyboard and match the outlet from the cell to button, like this: