Use slider to manipulate anchors constrained by a multiplier in swift - swift

I want to use a slider to make pic imageview smaller. Right now its in its max size. The slider should be able to make it smaller. When I use the slider the pic does decrease but I cant increase it, I can only decrease it. This is a pic of what I am looking to do.
My code is in all code no storyboard used.
import UIKit
class ViewController: UIViewController {
var sd = UISlider()
var pic = UIImageView()
var start = [NSLayoutConstraint]()
var change = [NSLayoutConstraint]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
[sd,pic].forEach{
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
pic.topAnchor.constraint(equalTo: view.topAnchor, constant: 12).isActive = true
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
pic.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
start = [
pic.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
pic.heightAnchor.constraint(equalTo: view.layoutMarginsGuide.heightAnchor, multiplier: 1/2),
sd.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :150),
sd.topAnchor.constraint(equalTo: view.centerYAnchor, constant : +250),
sd.widthAnchor.constraint(equalToConstant: 150),
sd.heightAnchor.constraint(equalToConstant: 40)
]
NSLayoutConstraint.activate(start)
sd.addTarget(self, action: #selector(moveRight), for: .allTouchEvents)
}
#objc func moveRight(_ sender: UISlider) {
NSLayoutConstraint.deactivate(start)
let jessicaAlba = 300 + ( 300 * CGFloat(sd.value) )
print(CGFloat(sd.value))
pic.topAnchor.constraint(equalTo: view.topAnchor, constant: -jessicaAlba).isActive = true
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: jessicaAlba).isActive = true
pic.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -jessicaAlba).isActive = true
start = [
pic.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
pic.heightAnchor.constraint(equalTo: view.layoutMarginsGuide.heightAnchor, multiplier: 1/2),
sd.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :150),
sd.topAnchor.constraint(equalTo: view.centerYAnchor, constant : +250),
sd.widthAnchor.constraint(equalToConstant: 100),
sd.heightAnchor.constraint(equalToConstant: 40)
]
NSLayoutConstraint.activate (start)
}
}

Apologies for the very crude code, but this works:
var myView = UIView()
var topConstraint: NSLayoutConstraint!
var bottomConstraint: NSLayoutConstraint!
var leadingConstraint: NSLayoutConstraint!
var trailingConstraint: NSLayoutConstraint!
var jessicaAlba:Float = 50
var slider = UISlider()
override func viewDidLoad() {
super.viewDidLoad()
myView.translatesAutoresizingMaskIntoConstraints = false
myView.backgroundColor = UIColor.orange
view.addSubview(myView)
slider.translatesAutoresizingMaskIntoConstraints = false
slider.minimumValue = 50
slider.maximumValue = 200
slider.setValue(jessicaAlba, animated: false)
slider.addTarget(self, action: #selector(changeSize), for: .valueChanged)
view.addSubview(slider)
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
slider.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
slider.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10).isActive = true
topConstraint = myView.topAnchor.constraint(equalTo: view.topAnchor, constant: CGFloat(jessicaAlba))
topConstraint.isActive = true
bottomConstraint = myView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: CGFloat(-jessicaAlba))
bottomConstraint.isActive = true
leadingConstraint = myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: CGFloat(jessicaAlba))
leadingConstraint.isActive = true
trailingConstraint = myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: CGFloat(-jessicaAlba))
trailingConstraint.isActive = true
}
#objc func changeSize() {
jessicaAlba = slider.value
topConstraint.constant = CGFloat(jessicaAlba)
bottomConstraint.constant = CGFloat(-jessicaAlba)
leadingConstraint.constant = CGFloat(jessicaAlba)
trailingConstraint.constant = CGFloat(-jessicaAlba)
}
The main thing is to:
declare the specific constraints you want to change
set isActive = true in a separate line (I know, stupid but the compiler doesn't recognize the NSLayoutConstraint type and will not build if you do it on a single line
change the constraint as needed

Related

UITextFields keyboard not appearing in UIScrollview

I have 2 textfields as subViews of a contentView and the contentView is a subView of a scrollView. The textfields appear with no issue.But the problem I am having is when I tap or select the textfield to enter text neither a keyboard appears or the blue cursor, the textfields placeholder remains there. Is there something wrong with my constraints? How can I get the keyboard to appear and edit the text?
class SignInViewController: UIViewController {
private let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
private let contentView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private let emailOrPhoneTextField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.placeholder = "Email or Phone Number"
textField.textAlignment = .center
textField.backgroundColor = .red
return textField
}()
private let passwordTextField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.placeholder = "Password"
textField.backgroundColor = .yellow
return textField
}()
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
setupTextFields()
}
}
extension SignInViewController{
private func setupScrollView(){
view.addSubview(scrollView)
scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
scrollView.addSubview(contentView)
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
private func setupTextFields(){
contentView.addSubview(emailOrPhoneTextField)
contentView.addSubview(passwordTextField)
emailOrPhoneTextField.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
emailOrPhoneTextField.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 25).isActive = true
emailOrPhoneTextField.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true
emailOrPhoneTextField.heightAnchor.constraint(equalToConstant: 44).isActive = true
passwordTextField.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
passwordTextField.topAnchor.constraint(equalTo: emailOrPhoneTextField.bottomAnchor, constant: 25).isActive = true
passwordTextField.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true
passwordTextField.heightAnchor.constraint(equalToConstant: 44).isActive = true
}
}
Try this and check if it works:
extension ViewController{
private func setupScrollView(){
view.addSubview(scrollView)
scrollView.addSubview(contentView)
contentView.addSubview(emailOrPhoneTextField)
contentView.addSubview(passwordTextField)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor)
])
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.leftAnchor.constraint(equalTo: scrollView.leftAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor)
])
NSLayoutConstraint.activate([
emailOrPhoneTextField.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 50),
emailOrPhoneTextField.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20),
emailOrPhoneTextField.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20),
])
NSLayoutConstraint.activate([
passwordTextField.topAnchor.constraint(equalTo: emailOrPhoneTextField.bottomAnchor, constant: 25),
passwordTextField.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20),
passwordTextField.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20),
])
}
}

How to apply multiplier to a var bottom constraint

My code below produces the image below.
What I want is the height of the UIView to be exactly half of the view controller user something like:
constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, multiplier: 1/2)
I dont know where to put it since I am creating a var for every side.
import UIKit
class ViewController: UIViewController {
var myView = UIView()
var topConstraint: NSLayoutConstraint!
var bottomConstraint: NSLayoutConstraint!
var leadingConstraint: NSLayoutConstraint!
var trailingConstraint: NSLayoutConstraint!
var jessicaAlba:Float = 50
override func viewDidLoad() {
super.viewDidLoad()
myView.translatesAutoresizingMaskIntoConstraints = false
myView.backgroundColor = UIColor.orange
view.addSubview(myView)
topConstraint = myView.topAnchor.constraint(equalTo: view.topAnchor, constant: CGFloat(jessicaAlba))
topConstraint.isActive = true
bottomConstraint = myView.bottomAnchor.constraint(equalTo: view.bottomAnchor , constant: CGFloat(-jessicaAlba))
bottomConstraint.isActive = true
leadingConstraint = myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: CGFloat(jessicaAlba))
leadingConstraint.isActive = true
trailingConstraint = myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: CGFloat(-jessicaAlba))
trailingConstraint.isActive = true
}
}
You should use heightConstraint instead of bottomConstraint to get that done. Try the snippet below.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
var myView = UIView()
var topConstraint: NSLayoutConstraint!
var heightConstraint: NSLayoutConstraint!
var leadingConstraint: NSLayoutConstraint!
var trailingConstraint: NSLayoutConstraint!
var jessicaAlba:Float = 50
override func viewDidLoad() {
super.viewDidLoad()
myView.translatesAutoresizingMaskIntoConstraints = false
myView.backgroundColor = UIColor.orange
view.addSubview(myView)
topConstraint = myView.topAnchor.constraint(equalTo: view.topAnchor, constant: CGFloat(jessicaAlba))
topConstraint.isActive = true
heightConstraint = myView.heightAnchor.constraint(equalTo: view.heightAnchor , multiplier: 0.5, constant: CGFloat(-jessicaAlba))
heightConstraint.isActive = true
leadingConstraint = myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: CGFloat(jessicaAlba))
leadingConstraint.isActive = true
trailingConstraint = myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: CGFloat(-jessicaAlba))
trailingConstraint.isActive = true
}
}

ViewControlling full of textEdits not scrolling down with scrollview

I have a view controller with 8 to 9 textEdits where user has to fill them out to save to a database but it is taking a lot of my screen and some TE is not being shown because of the size of the iphones screen.I then decide to add a UIScrollView like this :
lazy var myScrollView : UIScrollView = {
let scrol = UIScrollView()
scrol.contentSize.height = 10000
scrol.backgroundColor = appBackgroundColor
scrol.translatesAutoresizingMaskIntoConstraints = false
return scrol
}()
...
view.addSubview(myScrollView)
myScrollView.addSubview(labelYear)
myScrollView.addSubview(labelAppTitle)
// then I added the constraints
NSLayoutConstraint.activate([
myScrollView.topAnchor.constraint(equalTo: view.topAnchor),
myScrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
myScrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
//enter code here
myScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
labelAppTitle.leftAnchor.constraint(equalTo: myScrollView.leftAnchor,constant: 40),
labelAppTitle.topAnchor.constraint(equalTo: myScrollView.safeAreaLayoutGuide.topAnchor, constant: 10),
labelAppTitle.rightAnchor.constraint(equalTo:myScrollView.rightAnchor, constant: -40),
labelAppTitle.heightAnchor.constraint(equalToConstant: 90)
])
I have a lot more textEdits but I am not posting for sake of saving space.The problem is that it is not scrolling down like I wanted . How do I do this?
thank you
import UIKit
class TestController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
initUI()
}
func initUI() {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.isUserInteractionEnabled = true
view.addSubview(scrollView)
let contentView = UIView()
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.isUserInteractionEnabled = true
contentView.isMultipleTouchEnabled = true
scrollView.addSubview(contentView)
let titleText = UITextField(frame: CGRect.zero)
titleText.translatesAutoresizingMaskIntoConstraints = false
titleText.borderStyle = .roundedRect
titleText.isEnabled = true
titleText.isUserInteractionEnabled = true
titleText.placeholder = "Constants.Messages.titlePlaceholder"
titleText.isUserInteractionEnabled = true
titleText.delegate = self
contentView.addSubview(titleText)
// scroll view
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0)
])
// content view
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
// title text field
NSLayoutConstraint.activate([
titleText.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20.0),
titleText.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
titleText.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0),
titleText.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0)
])
}
}
This is an exmaple of using scrollView. When you create a scrollView, apple recommends to put a contentView in it and put it inside in scrollView and don't forget to use bottomAnchor. If you forgot to use that then it'll not scroll.

UIImage Aspect Fill and clipsToBounds

I want to set an image to a UIImage, but as soon as I set it it the UIImageView gets bigger and goes over other elements.
There is a solution provided here:
Crop UIImage to fit a frame image
But I can not get it to work, I set the properties like in the solution provided.
Maybe somebody can have a look and help me:
Without setting the image:
After setting the image:
class Cell: UICollectionViewCell, CollectionViewCellConfigurable {
var image = UIImageView()
var dateDay = UILabel()
var dateMonth = UILabel()
var title = UILabel()
lazy private var dateContainer: UIView = {
let v = UIView()
v.sv(dateDay, dateMonth)
dateDay.heightAnchor.constraint(equalTo: self.dateMonth.heightAnchor, multiplier: 1).isActive = true
dateDay.leadingAnchor.constraint(equalTo: v.leadingAnchor, constant: 5).isActive = true
dateDay.trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -5).isActive = true
dateDay.topAnchor.constraint(equalTo: v.topAnchor, constant: 15).isActive = true
dateDay.bottomAnchor.constraint(equalTo: dateMonth.topAnchor, constant: -5).isActive = true
dateMonth.heightAnchor.constraint(equalTo: self.dateDay.heightAnchor, multiplier: 1).isActive = true
dateMonth.leadingAnchor.constraint(equalTo: v.leadingAnchor, constant: 5).isActive = true
dateMonth.trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -5).isActive = true
dateMonth.topAnchor.constraint(equalTo: dateDay.bottomAnchor, constant: 5).isActive = true
// dateMonth.bottomAnchor.constraint(greaterThanOrEqualTo: v.bottomAnchor, constant: -5).isActive = true
return v
}()
lazy private var container: UIView = {
return UIView()
}()
func configureCellAtIndexPath(item: Journaling) {
self.image.image = UIImage.baliBeach
self.image.backgroundColor = .green
self.dateDay.text = "16"
self.dateMonth.text = "May"
self.title.text = "Text visible"
}
override init(frame: CGRect) {
super.init(frame:frame)
setUpLayout()
additionalSetUp()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func additionalSetUp() {
backgroundColor = .clear
let colorText: UIColor = .grau
dateDay.textColor = colorText
dateMonth.textColor = colorText
title.textColor = colorText
dateDay.textAlignment = .center
dateMonth.textAlignment = .center
title.textAlignment = .center
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.autoresizesSubviews = true
}
func setUpLayout() {
sv(dateContainer, container)
container.sv(image,title)
dateContainer.widthAnchor.constraint(equalToConstant: 45).isActive = true
// dateContainer.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.15).isActive = true
dateContainer.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
dateContainer.trailingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
dateContainer.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
dateContainer.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
// container.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.5).isActive = true
container.leadingAnchor.constraint(equalTo: dateContainer.trailingAnchor, constant: 0).isActive = true
container.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
container.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
container.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
image.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 5).isActive = true
image.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -5).isActive = true
image.topAnchor.constraint(equalTo: self.topAnchor, constant: 15).isActive = true
image.bottomAnchor.constraint(equalTo: title.topAnchor, constant: -5).isActive = true
title.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0).isActive = true
title.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: 0).isActive = true
title.topAnchor.constraint(equalTo: image.bottomAnchor, constant: 5).isActive = true
title.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 0).isActive = true
}
}
You need to higher vertical compression priority of the title label as the imageView is equal it = 750 , so it occupies the space
title.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 751), for: .vertical)

heightAnchor.constraint not change height of view

I use this code:
func show(){
view.translatesAutoresizingMaskIntoConstraints = false
view.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
view.heightAnchor.constraint(equalToConstant: view.frame.height - 300).isActive = true
view.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
}
func hide(){
view.translatesAutoresizingMaskIntoConstraints = false
view.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
view.heightAnchor.constraint(equalToConstant: view.frame.height + 300).isActive = true
view.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
}
show function works fine, but hide function does not work and heightAnchor does not work.
First declare constraints
var heightArchonWhenShow = view.heightAnchor.constraint(equalToConstant: view.frame.height - 300)
var heightArchonWhenHide = view.heightAnchor.constraint(equalToConstant: view.frame.height + 300)
After init your constraints on ViewDidLoad
func setConstraints(){
view.translatesAutoresizingMaskIntoConstraints = false
view.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
view.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
heightArchonWhenShow.isActive = true
}
And simple active them , don't overwrite. Like this:
func show(){
heightArchonWhenShow.isActive = true
heightArchonWhenHide.isActive = false
}
func hide(){
heightArchonWhenShow.isActive = false
heightArchonWhenHide.isActive = true
}
If u want u can also animate changes, like that :
func hide(){
heightArchonWhenShow.isActive = false
heightArchonWhenHide.isActive = true
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
I recommend you to setup your constraint in a different function like maybe setup() and store them in some variable that you can modify after, I'll show you an example
var constraint: NSLayoutConstraint?
func setup() {
constraint = view.heightAnchor.constraint(equalToConstant: view.frame.height)
}
func show() {
if constraint != nil {
constraint!.constant = constraint!.constant + 300
}
}
func hide() {
if constraint != nil {
constraint!.constant = constraint!.constant - 300
}
}
You need only 1 var
var heightCon = view.heightAnchor.constraint(equalToConstant: view.frame.height - 300)
heightCon.isActive = true
Then manage it's constant value
func showOrHide(_ te:Bool){
heightCon.constant = te ? view.frame.height - 300 : view.frame.height + 300
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}