UIView Animation just work one time than it doesn't work - swift

I try to do an animation for my view but if just work in first time which is isOpen = true it work but when I call my function again isOpen = false nothing changes?
Perent view is self (UIView). Child is label(UILabel).
private func expansionView(isOpen: Bool) {
if isOpen {
label.backgroundColor = .white
NSLayoutConstraint.activate([
label.centerYAnchor.constraint(equalTo: self.topAnchor),
label.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 15),
])
UIView.animate(withDuration: 1, animations: {
self.layoutIfNeeded()
}) { (_) in
}
} else {
label.backgroundColor = .clear
NSLayoutConstraint.activate([
label.centerYAnchor.constraint(equalTo: self.centerYAnchor),
label.leadingAnchor.constraint(equalTo: self.leadingAnchor , constant: 15),
])
UIView.animate(withDuration: 1, animations: {
self.layoutIfNeeded()
}) { (_) in
print("Animation Completed!!!")
}
}
}

You need to have two constraints to make one of them active.
You can also animate changing label's background color to clear. And you can simplify your function like below.
// define both vertical constraints
var constraintToCenterYAnchor: NSLayoutConstraint!
var constraintToTopAnchor: NSLayoutConstraint!
// where you init your view..
init() {
// init your constraints
constraintToTopAnchor = label.centerYAnchor.constraint(equalTo: topAnchor)
constraintToCenterYAnchor = label.centerYAnchor.constraint(equalTo: centerYAnchor)
// set and activate other constraints once.
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15).isActive = true
// update background color of the label
label.backgroundColor = .clear
label.layer.backgroundColor = UIColor.white.cgColor
}
// simplify your function
private func expansionView(_ isOpen: Bool) {
constraintToTopAnchor.isActive = isOpen
constraintToCenterYAnchor.isActive = !isOpen
UIView.animate(withDuration: 1) {
self.label.layer.opacity = isOpen ? 1.0 : 0.0
self.layoutIfNeeded()
}
}

You need to have two contraints to activate and deactivate ...
lazy var centerXConstraint = label.centerYAnchor.constraint(equalTo: self.centerYAnchor)
lazy var topConstraint = label.leadingAnchor.constraint(equalTo: self.leadingAnchor , constant: 15)
init() {
label.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 15).isActive = true
}
private func expansionView(isOpen: Bool) {
if isOpen {
label.backgroundColor = .white
centerXConstraint.isActive = false
topConstraint.isActive = true
UIView.animate(withDuration: 1, animations: {
self.layoutIfNeeded()
}) { (_) in
}
} else {
label.backgroundColor = .clear
centerXConstraint.isActive = true
topConstraint.isActive = false
UIView.animate(withDuration: 1, animations: {
self.layoutIfNeeded()
}) { (_) in
print("Animation Completed!!!")
}
}
}

Related

Animate UILabel from a location to another location in the save UIViewController

I have 2 UILabels: usernameLabel located in left top corner and fadingWelcomeMessageLabel where I show a welcome message to user.
I want to implement a simple animation with a custom duration of few seconds which will minimise the size and fade (disolve) my fadingWelcomeMessageLabel from is original position to usernameLabel position.
How will be this possible ?
Below is a screenshot with what I want to do and also my current source code.
Thanks in advance.
import UIKit
class ViewController: UIViewController {
var fadingWelcomeMessageLabel: UILabel!
var usernameLabel : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setupUsernameLabel()
setupWelcomeMessageLabel()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UILabel.transition(with: usernameLabel, duration: 0.5, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
}, completion: { (fininshed: Bool) -> () in
self.fadeWelcomeMessage(message: "Hello, Mr User !", color: .orange, finalAlpha: 0.0)
})
}
func setupUsernameLabel() {
usernameLabel = UILabel()
usernameLabel.text = "Mr User"
usernameLabel.numberOfLines = 0
view.addSubview(usernameLabel)
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
usernameLabel.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 10).isActive = true
usernameLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
usernameLabel.widthAnchor.constraint (equalToConstant: 200).isActive = true
usernameLabel.heightAnchor.constraint (equalToConstant: 50).isActive = true
}
func setupWelcomeMessageLabel() {
// Fading Welcome Message Label
fadingWelcomeMessageLabel = UILabel()
fadingWelcomeMessageLabel.text = String()
fadingWelcomeMessageLabel.numberOfLines = 0
view.addSubview(fadingWelcomeMessageLabel)
fadingWelcomeMessageLabel.isHidden = true
fadingWelcomeMessageLabel.translatesAutoresizingMaskIntoConstraints = false
fadingWelcomeMessageLabel.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
fadingWelcomeMessageLabel.topAnchor.constraint (equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
fadingWelcomeMessageLabel.widthAnchor.constraint (equalTo: view.safeAreaLayoutGuide.widthAnchor).isActive = true
fadingWelcomeMessageLabel.heightAnchor.constraint (equalToConstant: 200).isActive = true
}
func fadeWelcomeMessage(message: String, color: UIColor, finalAlpha: CGFloat) {
fadingWelcomeMessageLabel.text = message
fadingWelcomeMessageLabel.alpha = 1.0
fadingWelcomeMessageLabel.isHidden = false
fadingWelcomeMessageLabel.textAlignment = .center
fadingWelcomeMessageLabel.backgroundColor = color
fadingWelcomeMessageLabel.layer.cornerRadius = 5
fadingWelcomeMessageLabel.layer.masksToBounds = true
fadingWelcomeMessageLabel.font = UIFont.systemFont(ofSize: 24.0)
UIView.animate(withDuration: 6.0, animations: { () -> Void in
self.fadingWelcomeMessageLabel.alpha = finalAlpha
})
}
}
CGAffineTransform can help you. You can run my code and change value according to your needs. I have showed only for fadingWelcomeMessageLabel. Hope you will get the idea.
class ViewController: UIViewController {
let fadingWelcomeMessageLabel = UILabel()
let usernameLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .gray
viewSetup()
}
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.asyncAfter(deadline: .now()+3, execute: {
UIView.animate(withDuration: 1.5) {
self.fadingWelcomeMessageLabel.transform = CGAffineTransform(translationX: -300, y: -2200).concatenating(CGAffineTransform(scaleX: 0.4, y: 0.2))
}
})
}
func viewSetup() {
fadingWelcomeMessageLabel.frame = CGRect(x: 10, y: view.frame.height/2 - 50, width: view.frame.width - 20, height: 300)
fadingWelcomeMessageLabel.text = "Welcome Mr. David"
fadingWelcomeMessageLabel.textColor = .green
fadingWelcomeMessageLabel.textAlignment = .center
fadingWelcomeMessageLabel.backgroundColor = .red
view.addSubview(fadingWelcomeMessageLabel)
}
}
Solution for my issue was resolved with 1 line of code inside animation closure:
func fadeWelcomeMessage(message: String, color: UIColor, finalAlpha: CGFloat) {
fadingWelcomeMessageLabel.text = message
fadingWelcomeMessageLabel.alpha = 1.0
fadingWelcomeMessageLabel.isHidden = false
fadingWelcomeMessageLabel.textAlignment = .center
fadingWelcomeMessageLabel.backgroundColor = color
fadingWelcomeMessageLabel.layer.cornerRadius = 5
fadingWelcomeMessageLabel.layer.masksToBounds = true
fadingWelcomeMessageLabel.font = UIFont.systemFont(ofSize: 24.0)
UIView.animate(withDuration: 6.0, delay: 4.0, animations: { () -> Void in
self.fadingWelcomeMessageLabel.transform = CGAffineTransform(translationX: -180, y: -80).scaledBy(x: 0.20, y: 0.20)
self.fadingWelcomeMessageLabel.alpha = finalAlpha
}) { finish in
self.setupWelcomeMessageLabel()
}
}
Output:

UIScrollView animate offset change when removing nested view

I have a UIScrollView that contains a stack view - I'm basically replicating a tabs feature.
One tab has a taller view than the other, so when I hide the view in the stack view it resizes.
This causes the scroll view to jump to the offset that fits the shorter view, in the event the user has scrolled to the top.
Is it possible to instead animate this change? Instead of the jump, the view scrolls to the correct offset? I am unsure how to achieve this.
final class ScrollViewController: UIViewController {
private var visibleTab: TabState = .overview {
didSet {
guard oldValue != visibleTab else { return }
switch visibleTab {
case .overview:
self.spacesTab.isHidden = true
self.overviewTab.isHidden = false
case .spaces:
self.spacesTab.isHidden = false
self.overviewTab.isHidden = true
}
}
}
enum TabState {
case overview
case spaces
}
private lazy var scrollView: UIScrollView = {
let view = UIScrollView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
view.delegate = self
view.alwaysBounceVertical = true
return view
}()
private let contentStackView: UIStackView = {
let view = UIStackView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.axis = .vertical
view.alignment = .fill
view.spacing = 8
view.distribution = .fill
return view
}()
private let tabSelectorView: UIStackView = {
let view = UIStackView(frame: .zero)
view.axis = .horizontal
view.distribution = .fillEqually
return view
}()
private let overviewTab: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .darkGray
view.heightAnchor.constraint(equalToConstant: 100).isActive = true
view.isHidden = false
return view
}()
private let spacesTab: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .lightGray
view.heightAnchor.constraint(equalToConstant: 780).isActive = true
view.isHidden = true
return view
}()
private let profileHeader = ScrollViewProfileHeaderView(frame: .zero)
private lazy var overviewTabButton = makeButton(title: "Overview")
private lazy var spacesTabButton = makeButton(title: "Spaces")
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
}
}
extension ScrollViewController: UIScrollViewDelegate { }
private extension ScrollViewController {
func configureUI() {
overviewTabButton.addTarget(self, action: #selector(showOverviewTab), for: .touchUpInside)
spacesTabButton.addTarget(self, action: #selector(showSpacesTab), for: .touchUpInside)
[overviewTabButton, spacesTabButton].forEach(tabSelectorView.addArrangedSubview)
profileHeader.translatesAutoresizingMaskIntoConstraints = false
tabSelectorView.translatesAutoresizingMaskIntoConstraints = false
[overviewTab, spacesTab].forEach(contentStackView.addArrangedSubview)
[profileHeader, tabSelectorView, contentStackView].forEach(scrollView.addSubview(_:))
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
profileHeader.topAnchor.constraint(equalTo: scrollView.topAnchor),
profileHeader.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
profileHeader.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
tabSelectorView.topAnchor.constraint(equalTo: profileHeader.bottomAnchor),
tabSelectorView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
tabSelectorView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
contentStackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
contentStackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
contentStackView.topAnchor.constraint(equalTo: tabSelectorView.bottomAnchor, constant: 8),
contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentStackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
}
func makeButton(title: String) -> UIButton {
let button = UIButton(type: .system)
button.setTitle(title, for: .normal)
button.backgroundColor = .lightGray
return button
}
#objc func showOverviewTab() {
visibleTab = .overview
}
#objc func showSpacesTab() {
visibleTab = .spaces
}
}
final class ScrollViewProfileHeaderView: UIView {
private let headerImage: UIImageView = {
let view = UIImageView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.contentMode = .scaleAspectFill
view.clipsToBounds = true
view.backgroundColor = .systemTeal
return view
}()
private let profileCard: ProfileCardView = {
let view = ProfileCardView(frame: .zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .purple
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
[headerImage, profileCard].forEach(addSubview(_:))
NSLayoutConstraint.activate([
headerImage.topAnchor.constraint(equalTo: topAnchor),
headerImage.leadingAnchor.constraint(equalTo: leadingAnchor),
headerImage.trailingAnchor.constraint(equalTo: trailingAnchor),
headerImage.heightAnchor.constraint(equalToConstant: 180),
profileCard.topAnchor.constraint(equalTo: headerImage.centerYAnchor),
profileCard.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 48),
profileCard.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -32),
profileCard.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -48),
profileCard.heightAnchor.constraint(equalToConstant: 270),
])
}
required init?(coder: NSCoder) {
return nil
}
}
You will probably want to make some additional changes, but this might get you on your way.
In your visibleTab / didSet block, use UIView.animate() when you hide the spacesTab:
private var visibleTab: TabState = .overview {
didSet {
guard oldValue != visibleTab else { return }
switch self.visibleTab {
case .overview:
// set duration longer, such as 1.0, to clearly see the animation...
UIView.animate(withDuration: 0.3) {
self.spacesTab.isHidden = true
self.overviewTab.isHidden = false
}
case .spaces:
self.spacesTab.isHidden = false
self.overviewTab.isHidden = true
}
}
}

why NSLayoutConstraint animation works only one time?

in my project I have a someView(of type UIView), that inside holderView(of type UIView).
someView have 2 state.
in state 1 the someView become large and in the step 2 the someView become small.
when some condition where right, someView show in state 1 and when it's not someView show in state 2.
I want to do this with animation and I use NSLayoutConstraint in my project. I'm using this codes(someViewHeight and someViewWidth are of type NSLayoutConstraint):
func minimizeSomeView() {
someViewHeight.constant = holderView.frame.width
someViewWidth.constant = holderView.frame.height
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded()
}
}
func maximizeSomeView() {
someViewHeight.constant = holderView.frame.width/4
someViewWidth.constant = holderView.frame.height/4
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded()
}
}
if someTextField.text != nil {
minimizeSomeView()
} else. {
maximizeSomeView()
}
I define someViewHeight and someViewWidth inside viewDidLayoutSubviews(), this is my codes:
class ViewController: UIViewController {
private var holderView, someView: UIView!
private var someViewHeight,someViewWidth: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
view.backgroundColor = .white
// Holder View
holderView = UIView()
holderView.backgroundColor = .red
holderView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(holderView)
NSLayoutConstraint.activate([
holderView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
holderView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
holderView.topAnchor.constraint(equalTo: view.topAnchor, constant: 120),
holderView.heightAnchor.constraint(equalToConstant: view.frame.height * 40 / 100)
])
// Some View
someView = UIView()
someView.backgroundColor = .blue
someView.translatesAutoresizingMaskIntoConstraints = false
holderView.addSubview(someView)
someView.topAnchor.constraint(equalTo: holderView.topAnchor).isActive = true
someView.trailingAnchor.constraint(equalTo: holderView.trailingAnchor).isActive = true
// Some TextField
let someTextField = UITextField()
someTextField.backgroundColor = .yellow
someTextField.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(someTextField)
NSLayoutConstraint.activate([
someTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
someTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
someTextField.topAnchor.constraint(equalTo: view.bottomAnchor, constant: -100),
someTextField.heightAnchor.constraint(equalToConstant: 50)
])
someTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
}
override func viewDidLayoutSubviews() {
someViewHeight = someView.heightAnchor.constraint(equalToConstant: holderView.frame.width)
someViewHeight.isActive = true
someViewWidth = someView.widthAnchor.constraint(equalToConstant: holderView.frame.width)
someViewWidth.isActive = true
}
func minimizeSomeView() {
someViewHeight.constant = holderView.frame.width/4
someViewWidth.constant = holderView.frame.height/4
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded()
}
}
func maximizeSomeView() {
someViewHeight.constant = holderView.frame.width
someViewWidth.constant = holderView.frame.height
UIView.animate(withDuration: 1.0) {
self.view.layoutIfNeeded()
}
}
#objc func textFieldDidChange(_ textfield: UITextField) {
if textfield.text!.count > 0 {
self.minimizeSomeView()
} else {
self.maximizeSomeView()
}
}
}
You should not update the constraints in viewDidLayoutSubviews, specifically when you are using auto layout. You don't need this block
When you add constraint you can initialize and make them active.
Here we can specify the constraint in proportion. i.e Height of someView is 0.4 of the holderView. Similarly, Width of someView is 0.4 of the holderView.
To fix the issue , you can perform below changes
// Your some View Constraints
someView.topAnchor.constraint(equalTo: holderView.topAnchor).isActive = true
someView.trailingAnchor.constraint(equalTo: holderView.trailingAnchor).isActive = true
maximizeSomeView()
Remove the viewDidLayouSubView Code
Update your maximize and minimize events. Here I have to remove the existing constraints as .multiplier is a readonly property.
func minimizeSomeView() {
removeExistingConstriant()
UIView.animate(withDuration: 1.0) { [unowned self] in
self.someViewWidth = self.someView.widthAnchor.constraint(equalTo: self.holderView.widthAnchor, multiplier: 1.0)
self.someViewWidth.isActive = true
self.someViewHeight = self.someView.heightAnchor.constraint(equalTo:
self.holderView.heightAnchor, multiplier: 1.0)
self.someViewHeight.isActive = true
self.view.layoutIfNeeded()
}
}
func maximizeSomeView() {
removeExistingConstriant()
UIView.animate(withDuration: 1.0) { [unowned self] in
self.someViewWidth = self.someView.widthAnchor.constraint(equalTo: self.holderView.widthAnchor, multiplier: 0.4)
self.someViewWidth.isActive = true
self.someViewHeight = self.someView.heightAnchor.constraint(equalTo:
self.holderView.heightAnchor, multiplier: 0.4)
self.someViewHeight.isActive = true
self.view.layoutIfNeeded()
}
}
func removeExistingConstriant(){
if self.someViewHeight != nil {
self.someViewHeight.isActive = false
}
if self.someViewWidth != nil {
self.someViewWidth.isActive = false
}
}

.tag on slider not changing the alpha of imagview

My swift code below has 2 different buttons which should effect the slider baised on the .tagnumber they initialize. B1 should effect the alhpa or transpency of the imageivew and b2 should decrease / increase the size. What b2 does works. What B1 does not work.My code does not use any storyboards. Also the uislider should only do one task it cannont resize the imageview and change the alpha at the same time. Only 1 task.
import UIKit
class ViewController: UIViewController {
var pzc = UIImageView()
var s = UISlider()
var b1 = UIButton()
var b2 = UIButton()
var jessicaAlba:Float = 50
var topConstraint: NSLayoutConstraint!
var heightConstraint: NSLayoutConstraint!
var leadingConstraint: NSLayoutConstraint!
var trailingConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
[pzc,s,b1,b2].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
}
[b1,b2].forEach {
$0.backgroundColor = .systemRed
}
pzc.backgroundColor = .systemGray
b1.frame = CGRect(x: view.center.x-115, y: view.center.y+200, width: 30, height: 30)
b2.frame = CGRect(x: view.center.x-115, y: view.center.y+250, width: 30, height: 30)
s.addTarget(self, action: #selector(moveRight), for: .touchUpInside)
b1.addTarget(self, action: #selector(mr1), for: .touchUpInside)
b2.addTarget(self, action: #selector(mr2), for: .touchUpInside)
NSLayoutConstraint.activate ([
b1.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :37.5),
b1.topAnchor.constraint(equalTo: view.centerYAnchor, constant : 225),
b1.widthAnchor.constraint(equalToConstant: 75),
b1.heightAnchor.constraint(equalToConstant: 50),
b2.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :130),
b2.topAnchor.constraint(equalTo: view.centerYAnchor, constant : 225),
b2.widthAnchor.constraint(equalToConstant: 75),
b2.heightAnchor.constraint(equalToConstant: 50),
])
s.minimumValue = 50
s.maximumValue = 200
s.setValue(jessicaAlba, animated: false)
view.addSubview(s)
s.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
s.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
s.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10).isActive = true
pzc.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pzc)
topConstraint = pzc.topAnchor.constraint(equalTo: view.topAnchor, constant: CGFloat(jessicaAlba))
topConstraint.isActive = true
heightConstraint = pzc.heightAnchor.constraint(equalTo: view.heightAnchor , multiplier: 0.5, constant: CGFloat(-jessicaAlba))
heightConstraint.isActive = true
leadingConstraint = pzc.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: CGFloat(jessicaAlba))
leadingConstraint.isActive = true
trailingConstraint = pzc.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: CGFloat(-jessicaAlba))
trailingConstraint.isActive = true
}
#objc func moveRight() {
if s.tag == 1 {
pzc.alpha = CGFloat(s.value)
}
if s.tag == 2 {
changeSize()
}
}
#objc func changeSize() {
UIView.animate(withDuration: 0.5, animations: {
self.jessicaAlba = self.s.value
self.topConstraint.constant = CGFloat(self.jessicaAlba)
self.heightConstraint.constant = CGFloat(-self.jessicaAlba)
self.leadingConstraint.constant = CGFloat(self.jessicaAlba)
self.trailingConstraint.constant = CGFloat(-self.jessicaAlba)
self.view.layoutIfNeeded()
}) { (finished) in
}
}
#objc func mr1() {
b1.backgroundColor = .brown
b2.backgroundColor = .systemPink
s.tag = 1
}
#objc func mr2() {
b2.backgroundColor = .brown
b1.backgroundColor = .systemPink
s.tag = 2
}
}
Here multiple target are added on your UISlider. Just modify your function.
#objc func moveRight() {
if s.tag == 1 {
let diff = s.maximumValue-s.minimumValue
pzc.alpha = CGFloat(s.value/diff)
}
if s.tag == 2 {
changeSize()
}
}
You can also modify your changeSize() function for animation.
#objc func changeSize() {
UIView.animate(withDuration: 0.5, animations: {
self.jessicaAlba = self.s.value
self.topConstraint.constant = CGFloat(self.jessicaAlba)
self.heightConstraint.constant = CGFloat(-self.jessicaAlba)
self.leadingConstraint.constant = CGFloat(self.jessicaAlba)
self.trailingConstraint.constant = CGFloat(-self.jessicaAlba)
self.view.layoutIfNeeded()
}) { (finished) in
}
}

Can the transition from the selection UITextField press to another UITextField cause the UIView to reload in Swift?

I have the following view as soon as my app loads:
As soon as I click on the Full name text field, the keyboard shows and shifts the elements a little bit to allow the register button stays appearing.
The problem appears when I move to the second text field. It causes the view to reload entirely and place all the elements in the view to their original place which makes the key board to hide the lowest elements. which is shown in the next figure
I have searched and checked if the problem comes from the fact that the keyboard loads keyboardwillshow() and keyboardwillhide do not get called at all when this problem happens as I have verified.
Can the transition from the selection UITextField press to another UITextField cause the UIView to reload Xcode? Please not that the UIText fields are in a
import UIKit
import SendBirdSDK
class LoginController: UIViewController {
var keyboardShowing = false
let inputsContainerView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.white
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 5
view.layer.masksToBounds = true
return view
}()
lazy var loginRegisterButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor(r: 88, g: 101, b: 161)
button.setTitle("Register", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.addTarget(self, action: #selector(handleLoginRegister), for: .touchUpInside)
return button
}()
func handleLoginRegister() {
if loginRegisterSegmentedControl.selectedSegmentIndex == 0 {
handleLogin()
} else {
handleRegister()
}
}
func handleLogin(){
guard let userid = fullNameTextField.text, (passwordTextField.text != nil) else {
print ("Form is not valid")
return
}
SBDMain.connect(withUserId: userid, completionHandler: { (user, error) in
if error != nil {
print (error)
return
}
//successfully loggedin user
self.dismiss(animated: true, completion: nil)
})
}
let nameTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Full Name"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let nameSeperatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let fullNameTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Username"
tf.translatesAutoresizingMaskIntoConstraints = false
return tf
}()
let fullNameSeperatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let passwordTextField: UITextField = {
let tf = UITextField()
tf.placeholder = "Password"
tf.translatesAutoresizingMaskIntoConstraints = false
tf.isSecureTextEntry = true
return tf
}()
lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "gameofthrones_splash")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView)))
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var loginRegisterSegmentedControl: UISegmentedControl = {
let sc = UISegmentedControl(items: ["Login", "Register"])
sc.translatesAutoresizingMaskIntoConstraints = false
sc.tintColor = UIColor.white
sc.selectedSegmentIndex = 1
sc.addTarget(self, action: #selector(handleLoginRegisterChange), for: .valueChanged)
return sc
}()
func handleLoginRegisterChange() {
if keyboardShowing == true {
view.endEditing(true)
}
/*else {
view.endEditing(false)
}*/
let title = loginRegisterSegmentedControl.titleForSegment(at: loginRegisterSegmentedControl.selectedSegmentIndex)
loginRegisterButton.setTitle(title, for: UIControlState())
// change height of inputContainerView, but how???
inputsContainerViewHeightAnchor?.constant = loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 100 : 150
// change height of nameTextField
nameTextFieldHeightAnchor?.isActive = false
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 0 : 1/3)
nameTextFieldHeightAnchor?.isActive = true
nameTextField.isHidden = loginRegisterSegmentedControl.selectedSegmentIndex == 0
fullNameTextFieldHeightAnchor?.isActive = false
fullNameTextFieldHeightAnchor = fullNameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
fullNameTextFieldHeightAnchor?.isActive = true
passwordTextFieldHeightAnchor?.isActive = false
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: loginRegisterSegmentedControl.selectedSegmentIndex == 0 ? 1/2 : 1/3)
passwordTextFieldHeightAnchor?.isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(r: 61, g: 91, b: 151)
view.addSubview(inputsContainerView)
view.addSubview(loginRegisterButton)
view.addSubview(profileImageView)
view.addSubview(loginRegisterSegmentedControl)
setupInputsContainerView()
setupLoginRegisterButton()
setupProfileImageView()
setupLoginRegisterSegmentedControl()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
//connecting to the application
SBDMain.initWithApplicationId("1662A8E8-F45F-454B-9E5E-02362342ECC5")
}
func keyboardWillShow(notification: NSNotification) {
print ("keyboardwillshow was called")
if self.keyboardShowing {
return
}
if self.keyboardShowing == false {
self.inputsContainerView.frame.origin.y -= 58
self.loginRegisterButton.frame.origin.y -= 58
self.loginRegisterSegmentedControl.frame.origin.y -= 58
self.profileImageView.frame.origin.y -= 58
}
self.keyboardShowing = true
}
func keyboardWillHide(notification: NSNotification) {
print ("keyboardwillhide was called")
if !self.keyboardShowing {
return
}
if self.keyboardShowing == true {
self.inputsContainerView.frame.origin.y += 58
self.loginRegisterButton.frame.origin.y += 58
self.loginRegisterSegmentedControl.frame.origin.y += 58
self.profileImageView.frame.origin.y += 58
}
self.keyboardShowing = false
}
func setupLoginRegisterSegmentedControl() {
//need x, y, width, height constraints
loginRegisterSegmentedControl.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginRegisterSegmentedControl.bottomAnchor.constraint(equalTo: inputsContainerView.topAnchor, constant: -12).isActive = true
loginRegisterSegmentedControl.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor, multiplier: 1).isActive = true
loginRegisterSegmentedControl.heightAnchor.constraint(equalToConstant: 36).isActive = true
}
func setupProfileImageView(){
//need x, y, width, height constraints
profileImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
profileImageView.bottomAnchor.constraint(equalTo: loginRegisterSegmentedControl.topAnchor, constant: -12).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 150).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
}
var inputsContainerViewHeightAnchor: NSLayoutConstraint?
var nameTextFieldHeightAnchor: NSLayoutConstraint?
var fullNameTextFieldHeightAnchor: NSLayoutConstraint?
var passwordTextFieldHeightAnchor: NSLayoutConstraint?
func setupInputsContainerView(){
//need x, y, width, height constraints
inputsContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
inputsContainerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
print(self.inputsContainerView.frame.origin.y)
inputsContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -24).isActive = true
inputsContainerViewHeightAnchor = inputsContainerView.heightAnchor.constraint(equalToConstant: 150)
inputsContainerViewHeightAnchor?.isActive = true
inputsContainerView.addSubview(nameTextField)
inputsContainerView.addSubview(nameSeperatorView)
inputsContainerView.addSubview(fullNameTextField)
inputsContainerView.addSubview(fullNameSeperatorView)
inputsContainerView.addSubview(passwordTextField)
//need x, y, width, height constraints
nameTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
nameTextField.topAnchor.constraint(equalTo: inputsContainerView.topAnchor).isActive = true
nameTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
nameTextFieldHeightAnchor = nameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
nameTextFieldHeightAnchor?.isActive = true
//need x, y, width, height constraints
nameSeperatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
nameSeperatorView.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true
nameSeperatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
nameSeperatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
//need x, y, width, height constraints
fullNameTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
fullNameTextField.topAnchor.constraint(equalTo: nameTextField.bottomAnchor).isActive = true
fullNameTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
fullNameTextFieldHeightAnchor = fullNameTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
fullNameTextFieldHeightAnchor?.isActive = true
//need x, y, width, height constraints
fullNameSeperatorView.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor).isActive = true
fullNameSeperatorView.topAnchor.constraint(equalTo: fullNameTextField.bottomAnchor).isActive = true
fullNameSeperatorView.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
fullNameSeperatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
//need x, y, width, height constraints
passwordTextField.leftAnchor.constraint(equalTo: inputsContainerView.leftAnchor, constant: 12).isActive = true
passwordTextField.topAnchor.constraint(equalTo: fullNameTextField.bottomAnchor).isActive = true
passwordTextField.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
passwordTextFieldHeightAnchor = passwordTextField.heightAnchor.constraint(equalTo: inputsContainerView.heightAnchor, multiplier: 1/3)
passwordTextFieldHeightAnchor?.isActive = true
}
func setupLoginRegisterButton(){
//need x, y, width, height constraints
loginRegisterButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
loginRegisterButton.topAnchor.constraint(equalTo: inputsContainerView.bottomAnchor, constant: 12).isActive = true
loginRegisterButton.widthAnchor.constraint(equalTo: inputsContainerView.widthAnchor).isActive = true
loginRegisterButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat ) {
self.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
}
}
Instead of moving the elements of the UIView move the whole view frame like this:
func keyboardWillShow(notification: NSNotification) {
print ("keyboardwillshow was called")
if self.keyboardShowing {
return
}
if self.keyboardShowing == false {
/*self.inputsContainerView.frame.origin.y -= 58
self.loginRegisterButton.frame.origin.y -= 58
self.loginRegisterSegmentedControl.frame.origin.y -= 58
self.profileImageView.frame.origin.y -= 58*/
self.view.frame.origin.y -= 58
}
self.keyboardShowing = true
}
func keyboardWillHide(notification: NSNotification) {
print ("keyboardwillhide was called")
if !self.keyboardShowing {
return
}
if self.keyboardShowing == true {
/* self.inputsContainerView.frame.origin.y += 58
self.loginRegisterButton.frame.origin.y += 58
self.loginRegisterSegmentedControl.frame.origin.y += 58
self.profileImageView.frame.origin.y += 58*/
self.view.frame.origin.y += 58
}
self.keyboardShowing = false
}