UIDatePicker and Two Buttons from different time - ios

Start app.
Choice of hour and secondButton. I want different hour.
I have two buttons and one DatePicker. set datePickerMode = .time.
I need to set two different hours on different buttons.
Unfortunately, I could not find solutions for this.
This is my code:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(firstButton)
firstButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100).isActive = true
firstButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30).isActive = true
firstButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -30).isActive = true
firstButton.heightAnchor.constraint(equalToConstant: 100).isActive = true
view.addSubview(secondButton)
secondButton.topAnchor.constraint(equalTo: firstButton.bottomAnchor, constant: 10).isActive = true
secondButton.leftAnchor.constraint(equalTo: firstButton.leftAnchor).isActive = true
secondButton.rightAnchor.constraint(equalTo: firstButton.rightAnchor).isActive = true
view.addSubview(myDatePicker)
myDatePicker.topAnchor.constraint(equalTo: secondButton.bottomAnchor, constant: 10).isActive = true
myDatePicker.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 10).isActive = true
myDatePicker.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -10).isActive = true
}
// MyFirstButton
let firstButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("First", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.tintColor = .white
button.tag = 0
button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
return button
}()
// MySecondButton
let secondButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Second", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.tintColor = .white
button.tag = 1
button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
return button
}()
// Target First and Second Button
#objc func handleButton() {
view.layoutIfNeeded()
UIView.animate(withDuration: 0.25, animations: {
self.view.layoutIfNeeded()
}) { (completed) in
UIView.animate(withDuration: 0.25, animations: {
self.myDatePicker.alpha = 1
self.view.layoutIfNeeded()
})
}
}
// DataPicker
let myDatePicker: UIDatePicker = {
let pv = UIDatePicker()
pv.timeZone = .current
pv.datePickerMode = .time
pv.backgroundColor = .white
pv.translatesAutoresizingMaskIntoConstraints = false
pv.addTarget(self, action: #selector(handleMyDatePicker), for: .valueChanged)
return pv
}()
// Target
#objc func handleMyDatePicker(sender: UIDatePicker) {
let formatter = DateFormatter()
formatter.timeStyle = .short
let selectedTime = formatter.string(from: sender.date)
firstButton.setTitle(selectedTime, for: .normal)
// here is the problem
secondButton.setTitle(selectedTime, for: .normal)
myDatePicker.alpha = 0
}
How to achieve this effect?

Set your myDatePicker tag to same with button, that you touched
#objc func handleButton(button: UIButton) {
view.layoutIfNeeded()
UIView.animate(withDuration: 0.25, animations: {
self.view.layoutIfNeeded()
}) { (completed) in
UIView.animate(withDuration: 0.25, animations: {
self.myDatePicker.alpha = 1
self.myDatePicker.tag = button.tag
self.view.layoutIfNeeded()
})
}
}
#objc func handleMyDatePicker(sender: UIDatePicker) {
let formatter = DateFormatter()
formatter.timeStyle = .short
let selectedTime = formatter.string(from: sender.date)
let button = self.view.viewWithTag(sender.tag) as? UIButton
button?.setTitle(selectedTime, for: .normal)
myDatePicker.alpha = 0
}
and small change in your addTarget code
button.addTarget(self, action: #selector(handleButton(button:)), for: .touchUpInside)

Related

Changing color of uibutton

I am trying to create a UIbutton that changes color to green when tapped and blue when deselected. My logic works however when I exit the screen it still shows blue when selected because it's the default color shown before the button is tapped. What can I do to resolve this ?
func setUpSelectDealerButton(){
selectDealerButton.layer.cornerRadius = 5
view.addSubview(selectDealerButton)
selectDealerButton.setTitle( "Select Dealer" , for: .normal)
selectDealerButton.backgroundColor = .systemBlue
selectDealerButton.snp.makeConstraints{ (make) in
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-16)
make.top.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(16)
make.leading.equalTo(view.safeAreaLayoutGuide.snp.leading).offset(3)
make.trailing.equalTo(view.safeAreaLayoutGuide.snp.trailing).offset(-3)
make.height.equalTo(50)
make.width.equalTo(50)
}
selectDealerButton.addTarget(self, action: #selector(addToSelectedAccounts), for: .touchUpInside)
}
#objc func addToSelectedAccounts() {
if let selectedAccounts = delegate?.selectedAccounts, !selectedAccounts.contains(viewModel.account) {
delegate?.didSelect(account: viewModel.account)
}
if selectDealerButton.isSelected{
selectDealerButton.isSelected = false
selectDealerButton.setTitle( "Select Dealer" , for: .normal)
selectDealerButton.backgroundColor = .systemBlue
}
else{
selectDealerButton.isSelected = true
selectDealerButton.setTitle( "Dealer Selected" , for: .normal)
selectDealerButton.backgroundColor = .systemGreen
GlobalMBProgressHud.sharedInstance.showGlobalHud(withSuccess: true, text: "Selected!")
}
}
This is the screenshot: https://postimg.cc/xJt8ngy9
If I understand well this is an example of how to control button state, declare your objects:
let myButton: UIButton = {
let button = UIButton(type: .system)
button.layer.cornerRadius = 5
button.clipsToBounds = true
button.setTitleColor(.white, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let myLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.textAlignment = .center
label.font = .systemFont(ofSize: 20, weight: .semibold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var buttonState = Int() // set to integer
in viewDidLoad add target to your button set constraints (how you prefer) and call handleChangeButton function:
view.backgroundColor = .red
let control = UserDefaults.standard.integer(forKey: "buttonState")
if control == 0 {
buttonState = 0
} else {
buttonState = control
}
myButton.addTarget(self, action: #selector(handleChangeButton), for: .touchUpInside)
view.addSubview(myButton)
myButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
myButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10).isActive = true
myButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10).isActive = true
myButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
view.addSubview(myLabel)
myLabel.leadingAnchor.constraint(equalTo: myButton.leadingAnchor).isActive = true
myLabel.trailingAnchor.constraint(equalTo: myButton.trailingAnchor).isActive = true
myLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
myLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
handleChangeButton()
set variable to control button state and write the function:
#objc fileprivate func handleChangeButton() {
if buttonState == 0 {
myButton.setTitle( "Select Dealer" , for: .normal)
myButton.backgroundColor = .systemBlue
myLabel.text = myButton.currentTitle
buttonState = 1
} else {
myButton.setTitle( "Dealer Selected" , for: .normal)
myButton.backgroundColor = .systemGreen
myLabel.text = myButton.currentTitle
buttonState = 0
}
UserDefaults.standard.set(buttonState, forKey: "buttonState")
}
This is the result:

How can I change screens layout for landscape and portrait in iOS

I have totally different layouts for landscape and portrait.
In portrait the screen does not have the menu view of full height and half width on left and in landscape the screen contains the menu view on left side.
How to do that in iOS?
If you only want to show menu on landscape.
Check the device orientation by:
UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight
Then show the menu by using menu.isHidden = false to show the menu.
You can set the menu constraints either using storyboard or programmatically.
You can do it programmatically, declare your menuContainer view under your class controller like that:
let menuContainer: UIView = {
let v = UIView()
v.backgroundColor = .lightGray
v.alpha = 0
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
Now in viewDidLoad set constraints:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .darkGray
view.addSubview(menuContainer)
menuContainer.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
menuContainer.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
menuContainer.trailingAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
menuContainer.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
after that write the detect func (I add animation but you can't do it):
fileprivate func detectRotation() {
if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft {
print("landscape left")
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
self.menuContainer.alpha = 1
self.view.layoutIfNeeded()
}, completion: nil)
} else if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight {
print("landscape right")
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
self.menuContainer.alpha = 1
self.view.layoutIfNeeded()
}, completion: nil)
} else {
print("porrait")
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
self.menuContainer.alpha = 0
self.view.layoutIfNeeded()
}, completion: nil)
}
}
override viewWillTransition func and call detectRotation func:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
detectRotation()
}
This is the result:
portrait
Landscape
To show in landscape and portrait:
let myButton: UIButton = {
let b = UIButton()
b.backgroundColor = .white
b.setTitle("Section 1", for: .normal)
b.setTitleColor(.black, for: .normal)
b.titleLabel?.font = .systemFont(ofSize: 17, weight: .regular)
b.titleLabel?.adjustsFontSizeToFitWidth = true
b.titleLabel?.minimumScaleFactor = 0.5
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
let myButton2: UIButton = {
let b = UIButton()
b.backgroundColor = .white
b.setTitle("Section 2", for: .normal)
b.setTitleColor(.black, for: .normal)
b.titleLabel?.font = .systemFont(ofSize: 17, weight: .regular)
b.titleLabel?.adjustsFontSizeToFitWidth = true
b.titleLabel?.minimumScaleFactor = 0.5
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
let myButton3: UIButton = {
let b = UIButton()
b.backgroundColor = .white
b.setTitle("Section 3", for: .normal)
b.setTitleColor(.black, for: .normal)
b.titleLabel?.font = .systemFont(ofSize: 17, weight: .regular)
b.titleLabel?.adjustsFontSizeToFitWidth = true
b.titleLabel?.minimumScaleFactor = 0.5
b.titleLabel?.textAlignment = .left
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
let myButton4: UIButton = {
let b = UIButton()
b.backgroundColor = .white
b.setTitle("Section 4", for: .normal)
b.setTitleColor(.black, for: .normal)
b.titleLabel?.font = .systemFont(ofSize: 17, weight: .regular)
b.titleLabel?.adjustsFontSizeToFitWidth = true
b.titleLabel?.minimumScaleFactor = 0.5
b.titleLabel?.textAlignment = .left
b.translatesAutoresizingMaskIntoConstraints = false
return b
}()
let menuContainer: UIView = {
let v = UIView()
v.backgroundColor = .lightGray
v.alpha = 1
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .darkGray
view.addSubview(menuContainer)
menuContainer.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
menuContainer.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
menuContainer.trailingAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
menuContainer.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
let stackViewMenu = UIStackView(arrangedSubviews: [myButton, myButton2, myButton3, myButton4])
stackViewMenu.axis = .vertical
stackViewMenu.distribution = .fillEqually
stackViewMenu.spacing = 2
stackViewMenu.translatesAutoresizingMaskIntoConstraints = false
menuContainer.addSubview(stackViewMenu)
stackViewMenu.topAnchor.constraint(equalTo: menuContainer.safeAreaLayoutGuide.topAnchor).isActive = true
stackViewMenu.leadingAnchor.constraint(equalTo: menuContainer.leadingAnchor).isActive = true
stackViewMenu.trailingAnchor.constraint(equalTo: menuContainer.trailingAnchor).isActive = true
stackViewMenu.heightAnchor.constraint(equalTo: menuContainer.heightAnchor, multiplier: 0.5).isActive = true
}
The result:

Opening UIDatePicker under UITextView

I am writing an app, where when clicking on a UITexView an UIDatePicker opens. I want the UIDatePicker to pop up underneath the UITextView and not to come up as the keyboard from the bottom.
I am just starting with IOS app development and I hope someone can help me.
datePicker = UIDatePicker
and
inputTextfield = UITextField
myCode:
//Function to create the datepicker
func createDatePicker(){
//create instance of the datepicker
datePicker = UIDatePicker()
//sets format, so only day month and year can be selected
//datePicker?.datePickerMode = .date
datePicker?.backgroundColor = .white
datePicker?.addTarget(self, action: #selector(ViewController.dateChanged(datePicker:)), for: .valueChanged)
//to limit the datepicker, you can not pick a date older than yesterday
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())
datePicker?.minimumDate = yesterday
datePicker?.minuteInterval = 30
let loc = Locale(identifier: "de")
datePicker?.locale = loc
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.viewTapped(gesturRecognizer:)))
view.addGestureRecognizer(tapGesture)
inputTextfield.inputView = datePicker
//create a toolbar
let toolbar = UIToolbar()
toolbar.sizeToFit()
//add done button to the toolbar
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(doneClicked))
toolbar.setItems([doneButton], animated: true)
inputTextfield.inputAccessoryView = toolbar
}
//function to select a date
#objc func dateChanged(datePicker: UIDatePicker){
//selected date by the user
let dateFormate = DateFormatter()
//Jonas das ist vllt für dich relevant, man kann es so verändern wie man will
dateFormate.dateFormat = "MM/dd/yyyy"
inputTextfield.text = dateFormate.string(from: datePicker.date)
}
//function to close the datepicker, when tapping on the inputText again -handler method
#objc func viewTapped(gesturRecognizer: UITapGestureRecognizer){
view.endEditing(true)
}
//function to close the datepicker when clicking on the done button
#objc func doneClicked(){
self.view.endEditing(true)
}
No need to use any third party library. This can be achieved very easily. What I understand is that you want the picker to be displayed below the textfield and not as the input view instead of keyboard. Follow the following code to achieve what you want.
Here, name of my ViewController is TextFieldWithDatePickerVC. Don't get confused with name. With following code you would be able to do this very easily without using any third part library. I am attaching a output video also along with the code.
class TextFieldWithDatePickerVC: UIViewController {
lazy var inputTextfield: UITextField = {
let txtField = UITextField()
txtField.backgroundColor = .white
txtField.borderStyle = .roundedRect
txtField.translatesAutoresizingMaskIntoConstraints = false
txtField.placeholder = "Click me to open date picker"
return txtField
}()
lazy var datePicker: UIDatePicker = {
let picker = UIDatePicker()
picker.backgroundColor = .white
picker.addTarget(self, action: #selector(TextFieldWithDatePickerVC.dateChanged(_:)), for: .valueChanged)
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())
picker.minimumDate = yesterday
picker.minuteInterval = 30
let loc = Locale(identifier: "de")
picker.locale = loc
picker.translatesAutoresizingMaskIntoConstraints = false
return picker
}()
lazy var doneToolBar: UIToolbar = {
let toolbar = UIToolbar()
toolbar.sizeToFit()
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(doneClicked))
toolbar.setItems([doneButton], animated: true)
toolbar.translatesAutoresizingMaskIntoConstraints = false
return toolbar
}()
lazy var pickerContainer: UIView = {
let view = UIView()
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
setupAutoLayout()
pickerContainer.isHidden = true
inputTextfield.delegate = self
hideDatePicker()
}
func showDatePickerView() {
DispatchQueue.main.async {
self.pickerContainer.isHidden = false
}
}
func hideDatePicker() {
DispatchQueue.main.async {
self.pickerContainer.isHidden = true
}
}
func setupAutoLayout() {
self.view.addSubview(inputTextfield)
self.view.addSubview(pickerContainer)
self.view.bringSubview(toFront: pickerContainer)
pickerContainer.addSubview(doneToolBar)
pickerContainer.addSubview(datePicker)
NSLayoutConstraint.activate([
inputTextfield.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30),
inputTextfield.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -30),
inputTextfield.topAnchor.constraint(equalTo: view.topAnchor, constant: 60),
pickerContainer.topAnchor.constraint(equalTo: inputTextfield.bottomAnchor, constant: 5),
pickerContainer.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30),
pickerContainer.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -30),
pickerContainer.heightAnchor.constraint(equalToConstant: datePicker.intrinsicContentSize.height + doneToolBar.intrinsicContentSize.height),
doneToolBar.topAnchor.constraint(equalTo: pickerContainer.topAnchor, constant: 0),
doneToolBar.leftAnchor.constraint(equalTo: pickerContainer.leftAnchor, constant: 0),
doneToolBar.rightAnchor.constraint(equalTo: pickerContainer.rightAnchor, constant: 0),
datePicker.bottomAnchor.constraint(equalTo: pickerContainer.bottomAnchor, constant: 0),
datePicker.leftAnchor.constraint(equalTo: pickerContainer.leftAnchor, constant: 0),
datePicker.rightAnchor.constraint(equalTo: pickerContainer.rightAnchor, constant: 0)
])
}
#objc func dateChanged(_ sender: UIDatePicker) {
print(sender.date)
inputTextfield.text = sender.date.description
}
#objc func doneClicked() {
hideDatePicker()
}
}
extension TextFieldWithDatePickerVC: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.resignFirstResponder()
showDatePickerView()
}
}
Here is a third party library which I guess will meet your expectation :
https://github.com/angelopino/APJTextPickerView
This subclasses the UITextField and very useful. Refer the example for more details.
See this: This would be helpfull for you.
https://blog.apoorvmote.com/change-textfield-input-to-datepicker/
let dateFormatter = DateFormatter()
let locale = NSLocale.current
var datePicker : UIDatePicker!
let toolBar = UIToolbar()
func doDatePicker() {
// DatePicker
self.datePicker = UIDatePicker(frame:CGRect(x: 0, y: UIScreen.main.bounds.height - 200.0, width: UIScreen.main.bounds.width, height: 200))
self.datePicker?.backgroundColor = UIColor.white
self.datePicker?.datePickerMode = UIDatePickerMode.dateAndTime
datePicker.center = view.center
view.addSubview(self.datePicker)
// ToolBar
toolBar.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 240.0, width: UIScreen.main.bounds.width, height: 44.0)
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.tintColor = UIColor(red: 92/255, green: 216/255, blue: 255/255, alpha: 1)
toolBar.sizeToFit()
// Adding Button ToolBar
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneClick))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelClick))
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: true)
self.view.addSubview(toolBar)
self.toolBar.isHidden = false
}
#objc func doneClick() {
let dateFormatter1 = DateFormatter()
dateFormatter1.dateStyle = .medium
dateFormatter1.timeStyle = .none
//self.datePicker.resignFirstResponder()
datePicker.isHidden = true
self.toolBar.isHidden = true
}
#objc func cancelClick() {
datePicker.isHidden = true
self.toolBar.isHidden = true
}

Swift iOS -Constraint isn't animating even though view.layoutIfNeeded() is called

I have a rounded likeButton that is behind a rounded moreButton. The likeButton is pinned to the centerX and centerY of the moreButton. When I press the moreButton I want to animate the likeButton 200 points above the moreButton.
I use a NSLayoutConstraint to keep track of the likeButton's centerY and to make changes to it. When I call UIView.animate and inside it's closure I call self.view.layoutIfNeeded() the view isn't updating.
#objc func moreButtonTapped(){
likeButtonCenterY?.isActive = false
likeButton.centerYAnchor.constraint(equalTo: self.moreButton.centerYAnchor, constant: -200)
likeButtonCenterY?.isActive = true
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
Where am I going wrong?
let moreButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setImage(UIImage(named: "more"), for: .normal)
button.tintColor = .red
button.clipsToBounds = true
button.addTarget(self, action: #selector(moreButtonTapped), for: .touchUpInside)
return button
}()
let likeButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setImage(UIImage(named: "like"), for: .normal)
button.tintColor = .blue
button.clipsToBounds = true
return button
}()
var likeButtonCenterY: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setAnchors()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
moreButton.layer.cornerRadius = moreButton.frame.size.width / 2
likeButton.layer.cornerRadius = likeButton.frame.size.width / 2
}
#objc func moreButtonTapped(){
likeButtonCenterY?.isActive = false
likeButton.centerYAnchor.constraint(equalTo: self.moreButton.centerYAnchor, constant: -200)
likeButtonCenterY?.isActive = true
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
func setAnchors(){
view.addSubview(likeButton)
view.addSubview(moreButton)
moreButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
moreButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -200).isActive = true
moreButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
moreButton.heightAnchor.constraint(equalToConstant: 100).isActive = true
likeButtonCenterY = likeButton.centerYAnchor.constraint(equalTo: moreButton.centerYAnchor)
likeButtonCenterY?.isActive = true
likeButton.centerXAnchor.constraint(equalTo: moreButton.centerXAnchor).isActive = true
likeButton.widthAnchor.constraint(equalToConstant: 100).isActive = true
likeButton.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
Try this
#objc func moreButtonTapped(){
likeButtonCenterY?.isActive = false
likeButtonCenterY = likeButton.centerYAnchor.constraint(equalTo: self.moreButton.centerYAnchor, constant: -200)
likeButtonCenterY?.isActive = true
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
You have forgotten to write likeButtonCenterY =
If you are activating/deactivating multiple constraints at the same time (like a batch), you might need to override the updateConstraints() method. More information is here: https://developer.apple.com/documentation/uikit/uiview/1622512-updateconstraints
Basically your code in the moreButtonTapped() will go in the overridden implementation of the updateConstraints() method. Don't forget to call super() in the last line of the method.
Then your animation code should look like look like:
UIView.animate(withDuration: 0.3) {
self.view.setNeedsUpdateConstraints()
self.view.layoutIfNeeded()
})

Swift: Screen Freezing from time to time when Dismissing a ViewController displaying a picture over the current context

I am having some troubles with: The screen freezing from time to time when Dismissing the ViewController displaying a picture over the current context.
May someone provide me some insights on how to fix this problem?
A sample of my codes is found below:
import UIKit
class ViewControllerCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
addSubview(showPhotoButton)
showPhotoButton.leftAnchor.constraint(equalTo: leftAnchor, constant: 200).isActive = true
showPhotoButton.bottomAnchor.constraint(equalTo: topAnchor, constant: 160).isActive = true
showPhotoButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
showPhotoButton.widthAnchor.constraint(equalToConstant: 70).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var showPhotoButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Show", for: .normal)
button.addTarget(self, action: #selector(showSale), for: .touchUpInside)
button.setTitleColor(UIColor(r: 120, g: 80, b: 255), for: .normal)
return button
}()
#objc func showSale() {
let popupViewController = PopupViewController()
popupViewController.modalPresentationStyle = .overCurrentContext
popupViewController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
window!.rootViewController?.present(PopupViewController, animated: true, completion: nil)
}
}
import UIKit
class SalePopupViewController: UIViewController {
override func viewDidLoad() {
view.backgroundColor = UIColor(white: 1, alpha: 0.60)
view.isOpaque = false
view.addSubview(rebateImage)
view.addSubview(dismissButton)
dismissButton.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
dismissButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
dismissButton.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
dismissButton.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
rebateImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
rebateImage.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -35).isActive = true
rebateImage.heightAnchor.constraint(equalToConstant: 290).isActive = true
rebateImage.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1).isActive = true
}
let dismissButton: UIButton = {
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(dismissPopup), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let rebateImage: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.layer.masksToBounds = false
image.layer.cornerRadius = 2
image.contentMode = .scaleAspectFill
image.clipsToBounds = true
image.image = UIImage(named: "SaleCostco")
return image
}()
#objc func dismissPopup() {
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
}
}
Your asynchronous code doesn't make sense. You dispatch onto a global queue and then immediately back onto the main thread. Try simply changing the implementation of dismissPopup() to this:
#objc func dismissPopup() {
dismiss(animated: true, completion: nil)
}

Resources