UITextView with border and floating placeholder using MDCMultilineTextField - ios

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/

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.

I want to change bottom layer of text field color when i start typing to blue

func designTextField()
{
//Set the horizontal line in bottom of text field
nameLayer.frame = CGRect(x: 0, y: self.tfName.bounds.size.height-1, width: self.tfName.bounds.size.width, height: 1)
nameLayer.backgroundColor = UIColor.lightGray.cgColor
tfName.layer.addSublayer(nameLayer)
//Set the horizontal line in bottom of text field
phoneLayer.frame = CGRect(x: 0, y: self.tfPhone.bounds.size.height-1, width: self.tfPhone.bounds.size.width, height: 1)
phoneLayer.backgroundColor = UIColor.lightGray.cgColor
tfPhone.layer.addSublayer(phoneLayer)
//Set the horizontal line in bottom of text field
emailLayer.frame = CGRect(x: 0, y: self.tfEmail.bounds.size.height-1, width: self.tfEmail.bounds.size.width, height: 1)
emailLayer.backgroundColor = UIColor.lightGray.cgColor
tfEmail.layer.addSublayer(emailLayer)
}
When to use this function to show in the View :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//Text Field Design
self.designTextField()
self.view.layoutIfNeeded()
}
Output :
Bottom layer background color will change to blue, when to hit the "Name" text field. But when i type some characters in the text field, then the text field bottom color will change to lightgray(but when i typing then the bottom layer will be same to blue.)
Output :
func textFieldDidBeginEditing(_ textField: UITextField)
{
if textField == self.tfName
{
nameLayer.backgroundColor = UIColor(red: 11/255, green: 174/255, blue: 250/255, alpha: 1).cgColor
imgName = UIImage(named: "user2")!
imgVwName.image = imgName
tfName.leftView = imgVwName
}
else if textField == self.tfPhone
{
phoneLayer.backgroundColor = UIColor(red: 11/255, green: 174/255, blue: 250/255, alpha: 1).cgColor
imgPhone = UIImage(named: "phone2")!
imgVwPhone.image = imgPhone
tfPhone.leftView = imgVwPhone
}
else if textField == self.tfEmail
{
emailLayer.backgroundColor = UIColor(red: 11/255, green: 174/255, blue: 250/255, alpha: 1).cgColor
imgEmail = UIImage(named: "mail2")!
imgVwEmail.image = imgEmail
tfEmail.leftView = imgVwEmail
}
}
func textFieldDidEndEditing(_ textField: UITextField)
{
if textField == self.tfName
{
nameLayer.backgroundColor = UIColor.lightGray.cgColor
imgName = UIImage(named: "user1")!
imgVwName.image = imgName
tfName.leftView = imgVwName
}
else if textField == self.tfPhone
{
phoneLayer.backgroundColor = UIColor.lightGray.cgColor
imgPhone = UIImage(named: "phone1")!
imgVwPhone.image = imgPhone
tfPhone.leftView = imgVwPhone
}
else if textField == self.tfEmail
{
emailLayer.backgroundColor = UIColor.lightGray.cgColor
imgEmail = UIImage(named: "mail1")!
imgVwEmail.image = imgEmail
tfEmail.leftView = imgVwEmail
}
}
Can somebody plzz help ???
When you write in textfield viewDidLayoutSubviews is called every time and call designTextField (designTextField add a new sublayer with grayColor). You can check if is the first time with a flag, or call designTextField in viewWillAppear or viewDidAppear, or check if the layer was added.
I suggest you to use SkyFloatingField as it is lightweight library which fulfil your requirement.

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.

Stackview doesn't append second view

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)

How can I properly group and minimize style code for UITextfields?

I'm trying to implement a standard universal styling of my text fields based strictly on the login/sign up fields.
So, I designed them all to be identical, but I think that I'm reusing a lot of code that can be condensed and maybe used in a variable? I'm not sure how to do so.
The way it is works, but i'm sure it can be done better than this. I'm almost certain there's a way to minimize this code for better practice.
I'm still learning, so I really want to learn better practice in dev.
Here's an example of my sign up view & the styling of the fields:
class JoinVC: UIViewController, UITextFieldDelegate {`
#IBOutlet weak var enterEmailTextField: UITextField!
#IBOutlet weak var enterPasswordTextField: UITextField!
#IBOutlet weak var enterNameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Field Border Corner + Width
self.enterEmailTextField.layer.cornerRadius = 24.0
self.enterEmailTextField.layer.borderWidth = 1.5
self.enterPasswordTextField.layer.cornerRadius = 24.0
self.enterPasswordTextField.layer.borderWidth = 1.5
self.enterNameTextField.layer.cornerRadius = 24.0
self.enterNameTextField.layer.borderWidth = 1.5
// ...
// Field Placeholder ColorEnter
var placeholderEnterEmail = NSAttributedString(string: "Enter Email", attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
var placeholderEnterPass = NSAttributedString(string: "Choose Password", attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
var placeholderEnterName = NSAttributedString(string: "Choose Username", attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
enterEmailTextField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
enterPasswordTextField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
enterNameTextField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
// ...
// Text Field Border color
var borderColor : UIColor = UIColor( red: 255, green: 255, blue:255, alpha: 0.8 )
self.enterPasswordTextField.layer.borderColor = borderColor.CGColor; enterEmailTextField.attributedPlaceholder = placeholderEnterEmail;
self.enterEmailTextField.layer.borderColor = borderColor.CGColor; enterPasswordTextField.attributedPlaceholder = placeholderEnterPass;
self.enterNameTextField.layer.borderColor = borderColor.CGColor; enterNameTextField.attributedPlaceholder = placeholderEnterName;
// ...
}
}
The way I have solved this before, especially if all text fields in the project are:
Always going to have identical attributes,
Always going to be created from the storyboard
is to subclass UITextField and apply the attributes in -awakeFromNib:
class KBTextField: UITextField {
let myAttributes = [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)]
let mySublayerTransform = CATransform3DMakeTranslation(20, 0, 0)
let myBorderColor = UIColor( red: 255, green: 255, blue:255, alpha: 0.8 )
override func awakeFromNib () {
self.layer.sublayerTransform = mySublayerTransform
self.layer.borderColor = myBorderColor.CGColor
self.layer.cornerRadius = 24.0
self.layer.borderWidth = 1.5
self.attributedPlaceholder = NSAttributedString(string: self.placeholder!, attributes: myAttributes)
}
}
Then you can just set the class right on the storyboard (to KBTextField, in this case) and it will take care of all your attributes automatically.
This way, you can ensure that all KBTextFields in your app look identical, as long as you create them through the storyboard.
easy solution for reusable code is a handler
func setupTextField(textField : UITextField, placeHolderString: String)
{
let borderColor = UIColor( red: 1.0, green: 1.0, blue:1.0, alpha: 0.8 )
textField.layer.cornerRadius = 24.0
textField.layer.borderWidth = 1.5
textField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
textField.layer.borderColor = borderColor.CGColor;
textField.attributedPlaceholder = NSAttributedString(string: placeHolderString, attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
}
override func viewDidLoad() {
super.viewDidLoad()
setupTextField(enterEmailTextField, placeHolderString: "Enter Email")
setupTextField(enterPasswordTextField, placeHolderString: "Choose Password")
setupTextField(enterNameTextField, placeHolderString: "Choose Username")
}
Note: UIColor values must be in the range of 0.0 to 1.0
You can use the Extension functionality.
Just create an Extension of UITextField an place your code into that Extension
(easy tutorial here)
Ex:
extension UITextField
{
func setPlaceholderColorAndString(pholder: String, color: UIColor)
{
self.attributedPlaceholder = NSAttributedString(string:pholder,
attributes:[NSForegroundColorAttributeName: color])
}
func setupField()
{
self.layer.cornerRadius = 24.0
self.layer.borderWidth = 1.5
}
}
Then in your code you can use it like:
self.enterEmailTextField.setPlaceholderColorAndString(pholder: "Enter Email", color: UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)
self.enterEmailTextField.setupField()
self.enterPasswordTextField.setPlaceholderColorAndString(pholder: "Enter Password", color: UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)
self.enterPasswordTextField.setupField()
And so on. Of course the above snippet it's only to give you an idea how using it, you can improve it a lot to fit your needs.

Resources