Remove a nested subview inside custom UITextField when user interaction did end? - swift

This is my first post on StackOverflow! Seems to be an amazing community.
I have created a custom UITextfield with a bottom line (bottomLine) programmatically and also a shadowed line (shadowLine) that I wish should be removed when the user moves away from the textfield. How do I do that?
lazy var textField: UITextField = {
let textField = UITextField()
textField.anchor(width: 150, height: 22)
textField.backgroundColor = UIColor(white: 100, alpha: 1)
var bottomLine = CALayer()
bottomLine.frame = CGRect(x: 0, y: 22, width: 150, height: 1)
bottomLine.backgroundColor = UIColor.black.cgColor
textField.borderStyle = UITextField.BorderStyle.none
textField.layer.addSublayer(bottomLine)
let shadowLine = UIView()
shadowLine.frame = CGRect(x: 0, y: 22, width: 150, height: 3)
shadowLine.backgroundColor = UIColor.black
shadowLine.layer.shadowColor = UIColor.darkGray.cgColor
shadowLine.layer.shadowOffset = CGSize(width: 3, height: 3)
shadowLine.layer.shadowRadius = 3
shadowLine.layer.shadowOpacity = 1
shadowLine.tag = 1
textField.addSubview(shadowLine)
return textField
}()
Then I implemented the UITextFieldDelegate protocol and one of its optional functions in order to remove shadowLine subview but it doesn't get removed as I want to:
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == textField {
textField.viewWithTag(1)?.removeFromSuperview()
}
}
Can you help a rookie out? :)

It looks like you forgot to set the delegate:
textField.delagate = self

Related

How to connect UILabel text to UISlider meaning?

I'm new in Swift and trying to create Temperature Converter from ºC to ºF programmatically. But I have no idea how to change meaning of my label when l drag the slider.
I tried to change addTarget, but it didn't help. I really have no idea what's wrong and why my label still being "0ºC".
enter image description here
Here is my code:
class ListVC: UIViewController {
var cLabel : UILabel = UILabel()
var slider : UISlider = UISlider()
override func viewDidLoad() {
super.viewDidLoad()
**// creating label**
let cLabel = UILabel()
cLabel.frame = CGRect(x: 150, y: 250, width: 100, height: 200)
cLabel.textAlignment = .center
cLabel.text = "0ºC"
cLabel.textColor = .black
cLabel.font = UIFont(name: "Apple SD Gothic Neo", size: 25)
self.view.addSubview(cLabel)
self.view = view
**// creating slider**
let slider = UISlider()
slider.frame = CGRect(x: 110, y: 300, width: self.view.frame.width, height: 250)
slider.center = self.view.center
slider.translatesAutoresizingMaskIntoConstraints = false
slider.minimumValue = 0
slider.maximumValue = 100
slider.value = 0
slider.isContinuous = true
slider.isUserInteractionEnabled = true
slider.addTarget(self, action:#selector(sliderValue(sender:)), for: .valueChanged)
self.view.addSubview(slider)
}
**// creating function that had to change label value but something went wrong**
#objc func sliderValue(sender: UISlider) {
cLabel.text = String(sender.value)
}
Thank you!

Add drop shadow to xib view in Swift

I have added a card view from a Xib file which when tapped it slides from bottom-up to display the view.
I have am trying to customised the view and a drop shadow to the view which is not working.
The cornerRadius works fine otherwise.
func setupCard() {
menuCardVC = MenuCardVC(nibName:"MenuCardVC", bundle:nil)
menuCardVC.view.layer.shadowOpacity = 0.50
menuCardVC.view.layer.shadowRadius = 12
menuCardVC.view.layer.shadowColor = UIColor.black.cgColor
menuCardVC.view.layer.shadowOffset = CGSize.zero
menuCardVC.view.layer.cornerRadius = 25
self.addChild(menuCardVC)
self.view.addSubview(menuCardVC.view)
menuCardVC.view.frame = CGRect(x: 0, y: self.view.frame.height - cardHandleAreaHeight, width: self.view.bounds.width, height: cardHeight)
menuCardVC.view.clipsToBounds = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(VenueDetailsVC.handleCardTap(recognzier:)))
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(VenueDetailsVC.handleCardPan(recognizer:)))
menuCardVC.handleArea.addGestureRecognizer(tapGestureRecognizer)
menuCardVC.handleArea.addGestureRecognizer(panGestureRecognizer)
}//end setupCard
Remove the below line of code,
menuCardVC.view.clipsToBounds = true
Since your view hierarchy is simple you could use the following technique. Also, you don't need to use clipsToBounds.
let superview = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
superview.backgroundColor = .white
let subview = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
subview.backgroundColor = .red
// First provide the corner radius.
subview.layer.cornerRadius = 8
// Then provide the shadow parameters.
subview.layer.shadowOpacity = 1
// ...
// Do not clip to bounds since it will clip the shadow.
// ...
superview.addSubview(subview)

How to show all TextField in a view that stored in a array / Swift 5

I have a tapGesture, that every time when you click on it a new TextField displays and will saved in a array.
I can create multiple TextField and can store them in a Array, but I have no idea, how I can display them on a view.
At the Moment only the first one will be shown in the view.
I want to build something similar like snapchat with the text.
var myTextField: UITextField = UITextField(frame: CGRect(x: 0,y: 0, width: 300.0, height:30.0))
func addTapGestureToTextImageView() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTextImage))
textImageView.isUserInteractionEnabled = true
textImageView.addGestureRecognizer(tapGesture)
}
#objc func handleTextImage() {
textFields.append(myTextField)
let myTextField = UITextField(frame: CGRect(x: 0,y: 0, width: 300.0, height:30.0))
for i in 0..<textFields.count {
myTextField.tag = i
view.addSubview(textFields[i])
print(textFields[i])
}
print(textFields.count)
}
If you want to pile them vertically you have to increment the y with the height for each textField and hence change it's frame.
for i in 0..<textFields.count {
var field = textFields[i]
field.frame = CGRect(x: 0, y: 30*i, width: 300, height: 30)
view.addSubview(field)
print(textFields[i])
}
It will look something like this. But you will need to tweak it to properly align it.
My suggestion would be to put a UIStackView in the baseView and then use it's addArrangedSubview() and it will do the stacking for you.
Use stackView for this:
lazy var textFieldsView: UIStackView = {
let stackView = UIStackView()
stackView.spacing = 4
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.frame.size.width = 300
view.addSubview(stackView)
return stackView
}()
#objc func handleTextImage() {
let myTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 300.0, height: 30.0))
for pair in textFields.enumerated() {
pair.element.tag = pair.offset
textFieldsView.addArrangedSubview(pair.element)
}
// Update stackView frame if needed
}

Swift: SegmentedControl in NavBar with Small TitleView

I am attempting to include a segmentedControl on my navBar that looks like this:
The idea here is that the text "fetching..." is a small titleView. However, my current implementation would result in the text "fetching..." on the lower side like so:
I implement large titles so that I can get two "rows" on the navBar, else the word "fetching..." will be hidden behind the segmentedControl.
Code:
let segmentedControl: UISegmentedControl = {
let items = ["Now","In 15 mins", "In 1 hour"]
let sc = UISegmentedControl(items: items)
sc.selectedSegmentIndex = 0
return sc
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.backBarButtonItem?.title = "Back"
navigationItem.largeTitleDisplayMode = .automatic
navigationItem.titleView = segmentedControl
}
Does anyone have any advice?
You can create a customView that holds all the views you want to show in the navigation bar and set that view as titleView like below,
let segmentedControl: UISegmentedControl = {
let items = ["Now","In 15 mins", "In 1 hour"]
let sc = UISegmentedControl(items: items)
sc.selectedSegmentIndex = 0
return sc
}()
let fetchingLabel: UILabel = {
let label = UILabel(frame: .zero)
label.text = "Fetching..."
return label
}()
In viewDidLoad
let customView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 250))
customView.addSubview(segmentedControl)
customView.addSubview(fetchingLabel)
fetchingLabel.frame = CGRect(x: 150, y: 0, width: self.view.frame.width, height: 60)
segmentedControl.frame = CGRect(x: 60, y: 50, width: self.view.frame.width * 0.75, height: 30)
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .automatic
navigationItem.titleView = customView
This should give you below result. You can play with the values to do what you want.

Set insets of programmatically created UITextView

I've created a UITextView programmatically, but unfortunately it doesn't behave the way a textview does when you drag it from the attributes inspector to the Main.storyboard.
For example: the text in my programmatically created textview doesn't "break line" at the right side of the textview frame.
Although the documentation mentions textContainerInsets, I can't seem to get it to work. (Xcode doesn't recognise the attribute)
class ViewController: UIViewController, UIScrollViewDelegate {
let scrollView = UIScrollView(frame: UIScreen.mainScreen().bounds)
var textView:UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.view = self.scrollView
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width;
let screenHeight = screenSize.height;
//Create textview
let textView : UITextField = UITextField(frame : CGRect(x:10, y:(screenHeight/2), width: (screenWidth-20), height: (screenHeight/3) ))
textView.backgroundColor = UIColor( red: 0.9, green: 0.9, blue:0.9, alpha: 1.0 )
textView.placeholder = NSLocalizedString("Start typing...", comment: "")
textView.borderStyle = UITextBorderStyle.Line;
// textView.autocorrectionType = .Yes
self.view.addSubview( textView )
}
Is there any way to make the text inside my textview act like normal? multi line instead of one line?
You're creating a UITextField in your code, not a UITextView.
This:
let textView : UITextField = UITextField(frame : CGRect(x:10, y:(screenHeight/2), width:(screenWidth-20), height: (screenHeight/3) ))
Should be:
let textView : UITextView = UITextView(frame : CGRect(x:10, y:(screenHeight/2), width: (screenWidth-20), height: (screenHeight/3) ))
You also seem to have declared textView as a property in your class, so your probably don't want the let in there:
textView = UITextView(frame : CGRect(x:10, y:(screenHeight/2), width: (screenWidth-20), height: (screenHeight/3) ))
Here's how I would implement your UITextView programatically -
override func viewDidLoad() {
super.viewDidLoad();
self.view.translatesAutoresizingMaskIntoConstraints = false;
let screenSize: CGRect = UIScreen.mainScreen().bounds;
let screenWidth = screenSize.width;
let screenHeight = screenSize.height;
//Create textview
let textView : UITextView = UITextView(frame : CGRect(x: 10,
y: (screenHeight/2),
width: (screenWidth-20),
height: (screenHeight/3)));
textView.backgroundColor = UIColor( red: 0.9, green: 0.9, blue:0.9, alpha: 1.0 );
textView.text = NSLocalizedString("Start typing... maybe...", comment: "");
//textView.borderStyle: border's are not supported by the UITextView
self.view.addSubview(textView);
return;
}