Stackview doesn't append second view - ios

I've created a stack view programmatically and I added a view which I've created programmatically too to it. But when I try to add a second view it doesn't work.
Here's my code:
#IBOutlet weak var codingScrollView: UIView!
let codeStackView = UIStackView()
var codeViews = [CodeView]()
let codeView1 = CodeView(name: "Lennart", date: "13/05/2002", code: "Just some code")
let codeView2 = CodeView(name: "Nina", date: "01/07/1999", code: "Also some code")
The codingScrollView is the contentview I've added to a UIScrollView.
The codeStackView is the one I've described before
The codeViews array is being used to add the views to the stackview.
Here's the viewDidLoad method:
codeViews.append(codeView1)
codeViews.append(codeView2)
codingScrollView.addSubview(codeStackView)
codingScrollView.backgroundColor = UIColor(red: 226/255, green: 226/255, blue: 226/255, alpha: 1)
codeStackView.centerXAnchor.constraint(equalTo: codingScrollView.centerXAnchor)
codeStackView.centerYAnchor.constraint(equalTo: codingScrollView.centerYAnchor)
codeStackView.translatesAutoresizingMaskIntoConstraints = false
codeStackView.spacing = 10
codeStackView.axis = .horizontal
codeStackView.alignment = .center
for i in 0...codeViews.count - 1 {
codeStackView.addSubview(codeViews[i])
codeStackView.addArrangedSubview(codeViews[i])
}
But if I run the app it won't show the second view, it only shows one of them.
Thank you very much, I really appreciate any kind of help

Try adding the codeView{1,2} to the stack view first then add the codeStackView to the codingScrollView.
Also, be sure to set codeStackView.translatesAutoresizingMaskIntoConstraints = false before doing any constraints.
codeViews.append(codeView1)
codeViews.append(codeView2)
for i in 0...codeViews.count - 1 {
codeStackView.addSubview(codeViews[i])
codeStackView.addArrangedSubview(codeViews[i])
}
codeStackView.translatesAutoresizingMaskIntoConstraints = false
codeStackView.centerXAnchor.constraint(equalTo: codingScrollView.centerXAnchor)
codeStackView.centerYAnchor.constraint(equalTo: codingScrollView.centerYAnchor)
codeStackView.spacing = 10
codeStackView.axis = .horizontal
codeStackView.alignment = .center
codingScrollView.addSubview(codeStackView)
codingScrollView.backgroundColor = UIColor(red: 226/255, green: 226/255, blue: 226/255, alpha: 1)

Related

Is there a way to change all of my IOS App page's Bg Color by using User Defaults?

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.

UITextView with border and floating placeholder using MDCMultilineTextField

Im trying to achieve as in these images below
On User edit
here is my code
#IBOutlet weak var commentTxtField: MDCMultilineTextField! // Connected to storyboard
commentTxtField.textView?.delegate = self
commentTxtField.textView?.frame = CGRect(x: (commentTxtField.textView?.frame.origin.x)!, y: (commentTxtField.textView?.frame.origin.y)!, width: (commentTxtField.textView?.frame.width)!, height: CGFloat(GenUtils.shared.getHeightForPercent(percent: 11.99)))
commentTxtField.expandsOnOverflow = false
commentTextFieldController = MDCTextInputControllerOutlinedTextArea(textInput: commentTxtField)
commentTextFieldController?.placeholderText = "Comment"
commentTextFieldController?.isFloatingEnabled = true
commentTextFieldController!.characterCountMax = UInt(maxCharactersCount)
commentTextFieldController?.characterCountViewMode = UITextField.ViewMode.never
commentTextFieldController?.activeColor = UIColor.white.withAlphaComponent(0.6)
commentTextFieldController?.normalColor = UIColor.white.withAlphaComponent(0.2)
// emailTextFieldController?.borderFillColor = UIColor.white
commentTextFieldController?.floatingPlaceholderActiveColor = UIColor(red: 249/255, green: 249/255, blue: 249/255, alpha: 0.54)
commentTextFieldController?.inlinePlaceholderColor = UIColor.white
commentTextFieldController?.floatingPlaceholderNormalColor = UIColor(red: 249/255, green: 249/255, blue: 249/255, alpha: 0.54)
commentTxtField.textColor = UIColor.white
commentTextFieldController?.inlinePlaceholderFont = UIFont(name:"Avenir-Medium",size:16)
tried to set the textviewframe, but not reflecting on screen. And also not able to get floating placeholder on border line align. What am i missing?
use **MDCTextField** as below:
class SomeVC: UIViewController, UITextFieldDelegate {
var textFieldControllerFloating = MDCTextInputControllerUnderline()
override func viewDidLoad() {
let textFieldFloating = MDCTextField()
self.view.addSubview(textFieldFloating)
//place textfield where you want
textFieldFloating.placeholder = "Some cool animating placeholder"
textFieldFloating.delegate = self
// This will animate the textfield's place holder
textFieldControllerFloating = MDCTextInputControllerUnderline(textInput: textFieldFloating)
}
}
also if you want an outlined textfield you to use "Outlined" text field
https://material.io/develop/ios/components/textfields/

Setting label's text causes stack view layout issues

If I use the code sample below in a playground everything looks good until I try to set the text property for one of the labels. I've pinned it down to being able to change the value before adding the stack view to the UIView. But if I change the label's text value after adding the stack view to the parent view then the two labels end up overlapping (see images at bottom).
This is a basic test harness highlighting the problem, the real code will set the value at run time, potentially after the view has loaded, and the actual control is more complex than this. I know it's something to do with auto-layout / constraints but I'm pretty sure I've followed the example code I was looking at properly but I can't see the difference between their example and mine.
import UIKit
import PlaygroundSupport
#IBDesignable
public final class TestHarness : UIView {
fileprivate let nameLabel: UILabel = {
let label = UILabel()
//label.font = UIFont.systemFont( ofSize: 20, weight: UIFont.Weight.medium)
label.textAlignment = .center
label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
label.text = "Person's Name"
label.adjustsFontSizeToFitWidth = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate let jobTitleLabel: UILabel = {
let label = UILabel()
//label.font = UIFont.systemFont( ofSize: 20, weight: UIFont.Weight.medium)
label.textAlignment = .center
label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
label.text = "Job Title"
label.adjustsFontSizeToFitWidth = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
fileprivate lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
//stackView.distribution = .fill
stackView.alignment = .center
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(self.nameLabel)
stackView.addArrangedSubview(self.jobTitleLabel)
return stackView
}()
public required init?(coder: NSCoder) {
super.init(coder: coder)
initPhase2()
}
public override init(frame: CGRect) {
super.init(frame: frame)
initPhase2()
}
private func initPhase2() {
layer.cornerRadius = 10
layer.borderWidth = 2
self.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
jobTitleLabel.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
// self.jobTitleLabel.text = "Developer" // <<-- Can set here no problem
self.addSubview(stackView)
// self.jobTitleLabel.text = "Developer" // << -- If I set this here, job title and name overlap
NSLayoutConstraint.activate([
{
let constraint = stackView.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor, constant: 8)
constraint.priority = UILayoutPriority(750)
return constraint
}(),
stackView.leftAnchor.constraint(equalTo: layoutMarginsGuide.leftAnchor, constant: 8),
stackView.rightAnchor.constraint(equalTo: layoutMarginsGuide.rightAnchor, constant: -8),
{
let constraint = stackView.bottomAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.bottomAnchor, constant: -8)
constraint.priority = UILayoutPriority(750)
return constraint
}(),
stackView.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor)
])
}
#IBInspectable
public var Name: String? {
get{
return self.nameLabel.text
}
set{
self.nameLabel.text = newValue
}
}
#IBInspectable
public var JobTitle: String? {
get{
return self.jobTitleLabel.text
}
set{
self.jobTitleLabel.text = newValue
}
}
}
let dimensions = (width: 200, height: 300)
let control = TestHarness(frame: CGRect(x: dimensions.width / 2, y: dimensions.height / 2, width: dimensions.width, height: dimensions.height))
// control.JobTitle = "Developer" // << -- If I set this here, job title and name overlap
let view = UIView(frame: control.frame.insetBy(dx: -100, dy: -100))
view.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
view.addSubview(control)
PlaygroundPage.current.liveView = view
This is how it should look, and does look if I change the label's text before adding the stack view as a child of the parent view.
This is how it looks if I change the label's text after adding the stack view to the parent view. The job title overlaps with the name label.
Your code looks good, maybe there is a problem with Playground's render loop,
I created an Xcode project and used your code and it worked great in the simulator with no overlap:
import UIKit
override func viewDidLoad() {
super.viewDidLoad()
let dimensions = (width: 200, height: 300)
let control = TestHarness(frame: CGRect(x: dimensions.width / 2, y: dimensions.height / 2, width: dimensions.width, height: dimensions.height))
control.JobTitle = "Developer b2.0" // << -- No overlap in simulator
let contentView = UIView(frame: control.frame.insetBy(dx: -100, dy: -100))
contentView.backgroundColor = #colorLiteral(red: 0.3098039329, green: 0.01568627544, blue: 0.1294117719, alpha: 1)
contentView.addSubview(control)
view.addSubview(contentView)
}

How to arrange views in the `UIStackView`?

I want to set four views in the UIStackView with the horizontal direction. The four views next to each without space.
My code:
let arrangeStackView = UIStackView()
let followUpActionView = UIView()
let developCurriculumView = UIView()
let moreMoreView = UIView()
let takeCareSalonView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(arrangeStackView)
developCurriculumView.translatesAutoresizingMaskIntoConstraints = false;
followUpActionView.translatesAutoresizingMaskIntoConstraints = false;
takeCareSalonView.translatesAutoresizingMaskIntoConstraints = false;
moreMoreView.translatesAutoresizingMaskIntoConstraints = false;
developCurriculumView.backgroundColor = UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: 1)
followUpActionView.backgroundColor = UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: 1)
takeCareSalonView.backgroundColor = UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: 1)
moreMoreView.backgroundColor = UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: 1)
arrangeStackView.axis = .horizontal
arrangeStackView.distribution = .fillEqually
arrangeStackView.spacing = 10
arrangeStackView.alignment = .fill
arrangeStackView.translatesAutoresizingMaskIntoConstraints = false
arrangeStackView.addSubview(followUpActionView)
arrangeStackView.addSubview(developCurriculumView)
arrangeStackView.addSubview(moreMoreView)
arrangeStackView.addSubview(takeCareSalonView)
arrangeStackView.snp.makeConstraints { (make) in
make.center.equalToSuperview()
make.height.equalTo(95)
make.width.equalToSuperview()
}
let yaIconWith = self.view.frame.width * 0.25
followUpActionView.snp.makeConstraints{(make) -> Void in
make.height.equalToSuperview()
make.width.equalTo(yaIconWith)
}
takeCareSalonView.snp.makeConstraints{(make) -> Void in
make.height.equalToSuperview()
make.width.equalTo(yaIconWith)
}
moreMoreView.snp.makeConstraints{(make) -> Void in
make.height.equalToSuperview()
make.width.equalTo(yaIconWith)
}
developCurriculumView.snp.makeConstraints{(make) -> Void in
make.height.equalToSuperview()
make.width.equalTo(yaIconWith)
}
Now, I look the result as below.
Why the four views locate the top-left on the screen?
You added each of the views as a subview to the stack view, instead of adding each view as an arranged subview. While they sound similar, only the arranged subviews are laid out according to the stack view's properties.
So you will change these lines:
arrangeStackView.addSubview(followUpActionView)
arrangeStackView.addSubview(developCurriculumView)
arrangeStackView.addSubview(moreMoreView)
arrangeStackView.addSubview(takeCareSalonView)
To this:
arrangeStackView.addArrangedSubview(followUpActionView)
arrangeStackView.addArrangedSubview(developCurriculumView)
arrangeStackView.addArrangedSubview(moreMoreView)
arrangeStackView.addArrangedSubview(takeCareSalonView)
And if you need special arrangement or if you need to add the views at different times in certain places, insertArrangedSubview(_:at:) is an alternative to addArrangedSubview(_:)
A UIStackView only distributes its arrangedSubViews not its regular subViews. Use addArrangedSubview instead of addSubView.

Function to style TextField borders in swift not working

so I am new to Swift and mobile development, I want to make function that Change TextField style so i don't have to write long code for each TextField i have.
This is what I am trying to do :
func borderstyle(TextField : UITextField){
self.TextField.layer.borderColor = UIColor(red: 46/225, green: 204/225, blue: 113/225, alpha: 1).CGColor;
self.TextField.layer.borderWidth = CGFloat(Float(1.0));
self.TextField.layer.cornerRadius = CGFloat(Float(0.0));
}
I think you can get what i am trying to make form the code , the problem is that TextField in the func is read as #IBOutlet while its not.
I want to style any TextField I have with something like this :
borderstyle(UserNameTextField) // UserNameTextField is #IBOutlet
I know that I am doing some kind of mistake there but I want to know whats the best way to solve that.
Thanks.
Why you pass a textField to the function and then you use self.textField inside of it?
Use:
TextField.layer.borderColor = UIColor(red: 46/225, green: 204/225, blue: 113/225, alpha: 1).CGColor;
TextField.layer.borderWidth = CGFloat(Float(1.0));
TextField.layer.cornerRadius = CGFloat(Float(0.0));
Remove the self pointer from the code.
func borderstyle(textField : UITextField){
textField.layer.borderColor = UIColor(red: 46/225, green: 204/225, blue: 113/225, alpha: 1).CGColor;
textField.layer.borderWidth = CGFloat(Float(1.0));
textField.layer.cornerRadius = CGFloat(Float(0.0));
}
NB: As a good naming concept follow camelCase as shown

Resources