CustomAlert Message overWrite - swift

my model :
struct Model : Codable {
let title : String
var target : Int
var read : Int
let mean : String
let useful : String
}
and I create custom alert messages model:
class MyAlert {
struct Constants {
static let backgroundAlphaTo : CGFloat = 0.6
}
private var backgroundView : UIView = {
let backgroundView = UIView()
backgroundView.backgroundColor = .black
backgroundView.alpha = 0
return backgroundView
}()
private let alertView : UIView = {
let alertView = UIView()
alertView.backgroundColor = .white
alertView.layer.masksToBounds = true
alertView.layer.cornerRadius = 12
return alertView
}()
private var myTargetView : UIView?
func showAlert(with title :String , message : String , on ViewController : UIViewController){
guard let targetView = ViewController.view else {
return
}
myTargetView = targetView
backgroundView.frame = targetView.bounds
targetView.addSubview(backgroundView)
targetView.addSubview(alertView)
alertView.frame = CGRect(
x: 40, y: -300, width: targetView.frame.size.width-80, height: 300
)
let titleLabel = UILabel(frame: CGRect(
x: 0,
y: 0,
width: alertView.frame.size.width,
height: 80))
titleLabel.text = title
titleLabel.textAlignment = .center
alertView.addSubview(titleLabel)
let messageLabel = UILabel(frame: CGRect(
x: 0,
y: 80,
width: alertView.frame.size.width,
height: 170))
messageLabel.numberOfLines = 0
messageLabel.text = message
messageLabel.textAlignment = .center
alertView.addSubview(messageLabel)
let button = UIButton(frame: CGRect(
x: 0,
y: alertView.frame.size.height-50,
width: alertView.frame.size.width,
height: 50))
alertView.addSubview(button)
button.setTitle("Kapat", for: .normal)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: #selector(dissmissAlert), for: .touchUpInside)
UIView.animate(withDuration: 0.25) {
self.backgroundView.alpha = Constants.backgroundAlphaTo
} completion: { (done) in
if done {
UIView.animate(withDuration: 0.25) {
self.alertView.center = targetView.center
}
}
}
}
#objc func dissmissAlert() {
guard let targetView = myTargetView else {
return
}
UIView.animate(withDuration: 0.25, animations: {
self.alertView.frame = CGRect(
x: 40, y: targetView.frame.size.height, width: targetView.frame.size.width-80, height: 300
)}, completion: {done in
if done {
UIView.animate(withDuration: 0.25, animations: {
self.backgroundView.alpha = 0
}, completion: {done in
if done {
self.alertView.removeFromSuperview()
self.backgroundView.removeFromSuperview()
}
})
}
}
)
}
}
and I have segmentController :
#objc func ButtonTapped( _ sender : UISegmentedControl) {
if sender.selectedSegmentIndex == 1 {
customAlert.showAlert(with: zikirs.title, message: zikirs.mean, on: self)
} else if sender.selectedSegmentIndex == 2 {
customAlert.showAlert(with: zikirs.title, message: zikirs.useful, on: self)
}
}
private func dismissAlert(){
customAlert.dissmissAlert()
}
the problem here is the first message is normal but the second message overwrites the other.
how can I overcome this problem. I think this is from the inheritance property of the Classes. but I wanted to do my CustomAlert model with Struct because #objc can be only classes

The problem is that you don't remove the labels and the button from alertView but add new ones on the next call.
My suggestion is to assign tags to the views and create them only the first time
class MyAlert {
struct Constants {
static let backgroundAlphaTo : CGFloat = 0.6
}
private var backgroundView : UIView = {
let backgroundView = UIView()
backgroundView.backgroundColor = .black
backgroundView.alpha = 0
return backgroundView
}()
private let alertView : UIView = {
let alertView = UIView()
alertView.backgroundColor = .white
alertView.layer.masksToBounds = true
alertView.layer.cornerRadius = 12
return alertView
}()
private var myTargetView : UIView?
func showAlert(with title :String , message : String , on ViewController : UIViewController){
guard let targetView = ViewController.view else {
return
}
myTargetView = targetView
backgroundView.frame = targetView.bounds
targetView.addSubview(backgroundView)
targetView.addSubview(alertView)
alertView.frame = CGRect(
x: 40, y: -300, width: targetView.frame.size.width-80, height: 300
)
if let titleLabel = alertView.viewWithTag(100) as? UILabel {
titleLabel.text = title
} else {
let titleLabel = UILabel(frame: CGRect(
x: 0,
y: 0,
width: alertView.frame.size.width,
height: 80))
titleLabel.tag = 100
titleLabel.text = title
titleLabel.textAlignment = .center
alertView.addSubview(titleLabel)
}
if let messageLabel = alertView.viewWithTag(101) as? UILabel {
messageLabel.text = message
} else {
let messageLabel = UILabel(frame: CGRect(
x: 0,
y: 80,
width: alertView.frame.size.width,
height: 170))
messageLabel.tag = 101
messageLabel.numberOfLines = 0
messageLabel.text = message
messageLabel.textAlignment = .center
alertView.addSubview(messageLabel)
}
if alertView.viewWithTag(102) == nil {
let button = UIButton(frame: CGRect(
x: 0,
y: alertView.frame.size.height-50,
width: alertView.frame.size.width,
height: 50))
button.tag = 102
alertView.addSubview(button)
button.setTitle("Kapat", for: .normal)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: #selector(dissmissAlert), for: .touchUpInside)
}
UIView.animate(withDuration: 0.25) {
self.backgroundView.alpha = Constants.backgroundAlphaTo
} completion: { (done) in
if done {
UIView.animate(withDuration: 0.25) {
self.alertView.center = targetView.center
}
}
}
}
#objc func dissmissAlert() {
guard let targetView = myTargetView else {
return
}
UIView.animate(withDuration: 0.25, animations: {
self.alertView.frame = CGRect(
x: 40, y: targetView.frame.size.height, width: targetView.frame.size.width-80, height: 300
)}, completion: {done in
if done {
UIView.animate(withDuration: 0.25, animations: {
self.backgroundView.alpha = 0
}, completion: {done in
if done {
self.alertView.removeFromSuperview()
self.backgroundView.removeFromSuperview()
}
})
}
}
)
}
}

Related

iOS UIkit custom segmented buttons

I'm looking to create a view with these buttons. There is a background animation when one of the button touched.
Not sure how to do this.
Is custom segmented buttons the way to go?
I went with custom control
import UIKit
protocol MSegmentedControlDelegate:AnyObject {
func segSelectedIndexChange(to index:Int)
}
class MSegmentedControl: UIControl {
private var buttonTitles:[String]!
private var buttons: [UIButton]!
private var selectorView: UIView!
var textColor:UIColor = .black
var selectorViewColor: UIColor = .white
var selectorTextColor: UIColor = .red
weak var delegate:MSegmentedControlDelegate?
public private(set) var selectedIndex : Int = 0
convenience init(frame:CGRect,buttonTitle:[String]) {
self.init(frame: frame)
self.buttonTitles = buttonTitle
}
override func draw(_ rect: CGRect) {
super.draw(rect)
self.backgroundColor = UIColor.white
updateView()
}
func setButtonTitles(buttonTitles:[String]) {
self.buttonTitles = buttonTitles
self.updateView()
}
func setIndex(index:Int) {
buttons.forEach({ $0.setTitleColor(textColor, for: .normal) })
let button = buttons[index]
selectedIndex = index
button.setTitleColor(selectorTextColor, for: .normal)
let selectorPosition = frame.width/CGFloat(buttonTitles.count) * CGFloat(index)
UIView.animate(withDuration: 0.2) {
self.selectorView.frame.origin.x = selectorPosition
}
}
#objc func buttonAction(sender:UIButton) {
for (buttonIndex, btn) in buttons.enumerated() {
btn.setTitleColor(textColor, for: .normal)
if btn == sender {
let selectorPosition = frame.width/CGFloat(buttonTitles.count) * CGFloat(buttonIndex)
selectedIndex = buttonIndex
delegate?.segSelectedIndexChange(to: selectedIndex)
UIView.animate(withDuration: 0.3) {
self.selectorView.frame.origin.x = selectorPosition
}
btn.setTitleColor(selectorTextColor, for: .normal)
}
}
}
}
//Configuration View
extension MSegmentedControl {
private func updateView() {
createButton()
configSelectorView()
configStackView()
}
private func configStackView() {
let stack = UIStackView(arrangedSubviews: buttons)
stack.axis = .horizontal
stack.alignment = .fill
stack.distribution = .fillEqually
addSubview(stack)
stack.translatesAutoresizingMaskIntoConstraints = false
stack.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
stack.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
stack.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
stack.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
}
private func configSelectorView() {
let selectorWidth = frame.width / CGFloat(self.buttonTitles.count)
selectorView = UIView(frame: CGRect(x: 0, y: 8, width: selectorWidth, height: 32))
selectorView.backgroundColor = selectorViewColor
selectorView.layer.cornerRadius = 16
selectorView.layer.opacity = 0.5
addSubview(selectorView)
}
private func createButton() {
buttons = [UIButton]()
buttons.removeAll()
subviews.forEach({$0.removeFromSuperview()})
for buttonTitle in buttonTitles {
let button = UIButton(type: .system)
button.setTitle(buttonTitle, for: .normal)
button.addTarget(self, action:#selector(MSegmentedControl.buttonAction(sender:)), for: .touchUpInside)
button.setTitleColor(textColor, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
buttons.append(button)
}
buttons[0].setTitleColor(selectorTextColor, for: .normal)
}
}
Usage:
private let segControl: MSegmentedControl = {
let segControl = MSegmentedControl(
frame: CGRect(x: 0, y: 240, width: 280, height: 50),
buttonTitle: ["Average","Total","Pending"])
segControl.textColor = M.Colors.greyWhite
segControl.selectorTextColor = .white
return segControl
}()
To access index change event:
Implement the delegate on parent view:
addSubview(segControl)
segControl.delegate = self
Delegate:
func segSelectedIndexChange(to index: Int) {
switch index {
case 0: print("Average")
case 1: print("Total")
case 2: print("Pending")
default: break
}
}
Result:

How to show a backgroundVIew for empty tableView using RxSwift

not very expert with RxSwift, I tested some solution found here, such this but not working. Don't know if issue is about size of an empty tableview or som other UI update related issue.
the tableView I am using is a bit customized such this
public class SelfSizedTableView: UITableView {
public override var intrinsicContentSize: CGSize {
self.layoutIfNeeded()
return self.contentSize
}
public override var contentSize: CGSize {
didSet{
self.invalidateIntrinsicContentSize()
}
}
public override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}
}
the solution I am testing
extension UITableView {
func setEmptyMessage(_ message: String) {
let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height))
messageLabel.text = message
messageLabel.textColor = .black
messageLabel.numberOfLines = 0
messageLabel.textAlignment = .center
messageLabel.font = UIFont(name: "TrebuchetMS", size: 15)
messageLabel.sizeToFit()
self.backgroundView = messageLabel
self.separatorStyle = .none
}
func restore() {
self.backgroundView = nil
self.separatorStyle = .singleLine
}
}
self.viewModel.things.subscribe(onNext: { [unowned self] things in
if things.isEmpty {
self.myTableView.backgroundColor = .purple
self.myTableView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
self.myTableView.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(200), height: CGFloat(200))
self.myTableView.setNeedsLayout()
self.myTableView.layoutIfNeeded()
self.myTableView.setEmptyMessage("My Message")
} else {
self.myTableView.restore()
}
}).disposed(by: self.rx.disposeBag)
I think you can use a pod called pod 'EmptyDataSet-Swift' It will help you do this regarding any empty tableView
Try this
Update UIElements inside DispatchQueue.main.async {...}
self.viewModel.things.subscribe(onNext: { [unowned self] things in
if things.isEmpty {
DispatchQueue.main.async {
self.myTableView.backgroundColor = .purple
self.myTableView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
self.myTableView.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(200), height: CGFloat(200))
self.myTableView.setNeedsLayout()
self.myTableView.layoutIfNeeded()
self.myTableView.setEmptyMessage("My Message")
}
} else {
DispatchQueue.main.async {
self.myTableView.restore()
}
}
}).disposed(by: self.rx.disposeBag)

Why is my UIViewController not updating when delegate function called from UICollectionView class

I have a ViewController that has a delegate function in it from a UICollectionViewController. The delegate (named getCollectionViewSelection) function works as expected when it is called.
Here's the delegate function.
//protocol func from collectionview.
func getCollectionViewSelection(allSounds: SoundsWithSectionIndex, sound: Sounds) {
let test2 = sound.playerBackgroundImage
let iVB = self.imageViewBackground
iVB.image = UIImage(named: test2)
self.whatsPlaying.text = sound.description
print("delegate called : \(test2)")
}
I know this works because the print statement works. However the iVB.image=UIImage(named: test2) is not updating the image background.
Here's the whole view controller:
import UIKit
class SoundViewLeftViewController: UIViewController, MainCollectionViewControllerDelegate {
private lazy var whatsPlaying: UILabel = {
let wP = UILabel()
wP.textAlignment = NSTextAlignment.center
let strokeTextAttributes = [
//NSAttributedString.Key.strokeColor : UIColor.black,
NSAttributedString.Key.foregroundColor : UIColor.black,
//NSAttributedString.Key.strokeWidth : -4.0,
NSAttributedString.Key.font : UIFont(name: "DINAlternate-Bold", size: 18)]
as [NSAttributedString.Key : Any]
wP.attributedText = NSMutableAttributedString(string: "Sleepzzzzzz", attributes: strokeTextAttributes)
wP.backgroundColor = .lightGray
wP.sizeToFit()
wP.alpha = 0.75
wP.layer.borderWidth = 1
wP.layer.cornerRadius = 10
wP.layer.masksToBounds = true
wP.layer.borderColor = UIColor.white.cgColor
wP.isHidden = false
return wP
}()
private lazy var imageViewBackground: UIImageView = {
let iVB = UIImageView()
return iVB
}()
private lazy var playPauseButton: UIButton = {
let pPB = UIButton()
let playImage = UIImage(named: "play")
let pauseImage = UIImage(named: "pause")
pPB.setImage(playImage, for: .selected)
pPB.setImage(pauseImage, for: .normal)
//let tapGesturePlayPause = UITapGestureRecognizer(target: self, action: #selector(togglePlayPause))
//pPB.addGestureRecognizer(tapGesturePlayPause)
pPB.imageView?.contentMode = .scaleAspectFit
pPB.alpha = 0.75
return pPB
}()
//protocol func from collectionview.
func getCollectionViewSelection(allSounds: SoundsWithSectionIndex, sound: Sounds) {
let test2 = sound.playerBackgroundImage
let iVB = self.imageViewBackground
iVB.image = UIImage(named: test2)
self.whatsPlaying.text = sound.description
print("delegate called : \(test2)")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.black
loadViewItems()
}
func loadViewItems() {
let viewWidth = self.view.frame.size.width
let viewHeight = self.view.frame.size.height
let pPB = playPauseButton
pPB.frame = CGRect(x: 0, y: viewHeight * 0.45, width: viewWidth * 0.1, height: viewHeight * 0.05)
pPB.center.x = view.center.x
pPB.isHidden = false
let wP = whatsPlaying
wP.frame = CGRect(x: 0, y: viewHeight * 0.03, width: viewWidth, height: viewHeight * 0.05)
let iVB = imageViewBackground
iVB.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)
iVB.image = UIImage(named: "bird2")
iVB.contentMode = .scaleAspectFill
self.view.addSubview(iVB)
self.view.addSubview(pPB)
self.view.addSubview(wP)
}
}
Is it because I use private lazy vars in the view? I'm at a total loss as to why the image background isn't updating.
Thanks!

Subview Not Removing after Several "Remove View" Methods

I have this nice function that adds an activity indicator view, with a regular view behind it. When I add it, it adds fine. The problem is, when I try to remove it, nothing happens. I've tried:
.removeFromSuperview,
.isHidden = true and putting these methods in the main queue:
DispatchQueue.main.async() {
alertView.alpha = 0
alertView.removeFromSuperview()
activityIndicator.removeFromSuperview()
alertView.isHidden = true
activityIndicator.isHidden = true
}
I don't know what other methods to try...It seems all the other questions like this have one of the methods that I have as a solution. The function uses a boolean to determine whether or not to stop the activityIndicator. Here is my code:
static func showLoadingView(inViewController: UIViewController, turning: Bool){
let activityIndicator = UIActivityIndicatorView()
let alertView = UIView(frame: CGRect(x: activityIndicator.frame.origin.x, y: activityIndicator.frame.origin.y , width: 35, height: 35))
if(turning){
alertView.backgroundColor = UIColor(displayP3Red: 230, green: 230, blue: 230, alpha: 0.8)
alertView.layer.cornerRadius = 5
activityIndicator.center = alertView.center
inViewController.view.addSubview(alertView)
activityIndicator.activityIndicatorViewStyle = .gray
activityIndicator.startAnimating()
alertView.alpha = 0
activityIndicator.backgroundColor = UIColor.lightGray
alertView.center = inViewController.view.center
alertView.addSubview(activityIndicator)
alertView.transform = CGAffineTransform.init(scaleX: 1.3,y: 1.3)
UIView.animate(withDuration: 0.4) {
alertView.alpha = 1
alertView.transform = CGAffineTransform.identity
}
}
///////
else {
activityIndicator.stopAnimating()
alertView.transform = CGAffineTransform.init(scaleX: 1.3, y:1.3)
DispatchQueue.main.async() {
alertView.alpha = 0
alertView.removeFromSuperview()
activityIndicator.removeFromSuperview()
alertView.isHidden = true
activityIndicator.isHidden = true
}
print("Done")
}
}
You declared alertView which is out of scope when you called false.As a result, your call could not identify the alertView instance.
You can solve this issue in tow ways:
Declare your alertView outside of the function as a static.
static let activityIndicator = UIActivityIndicatorView()
static let alertView = UIView(frame: CGRect(x: activityIndicator.frame.origin.x, y: activityIndicator.frame.origin.y , width: 35, height: 35))
static func showLoadingView(inViewController: UIViewController, turning: Bool){}
In false case: find the subview using restorationIdentifier and remove.
static func showLoadingView(inViewController: UIViewController, turning: Bool){
if(turning){
let activityIndicator = UIActivityIndicatorView()
let alertView = UIView(frame: CGRect(x: activityIndicator.frame.origin.x, y: activityIndicator.frame.origin.y , width: 35, height: 35))
alertView.restorationIdentifier = "myalert"
alertView.backgroundColor = UIColor(displayP3Red: 230, green: 230, blue: 230, alpha: 0.8)
alertView.layer.cornerRadius = 5
activityIndicator.center = alertView.center
inViewController.view.addSubview(alertView)
activityIndicator.activityIndicatorViewStyle = .gray
activityIndicator.startAnimating()
alertView.alpha = 0
activityIndicator.backgroundColor = UIColor.lightGray
alertView.center = inViewController.view.center
alertView.addSubview(activityIndicator)
alertView.transform = CGAffineTransform.init(scaleX: 1.3,y: 1.3)
UIView.animate(withDuration: 0.4) {
alertView.alpha = 1
alertView.transform = CGAffineTransform.identity
}
}
///////
else {
for view in inViewController.view.subviews {
if (view.restorationIdentifier == "myalert") {
print("I FIND IT");
(view as! UIView).removeFromSuperview();
}
}
}
}

UIView is not hidden when condition is met in if else statement

I am trying to create an animation and hide it 5 seconds after the task has been completed.
For some reason overlayView is not hidden off the screen when counter == 5.
var counter = 0
var timer = Timer()
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool? = false
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off screen
animateDidLayout()
}
override func viewDidAppear(_ animated: Bool) {
//move picture on screen and adjust view
animateDidAppear()
}
//called by timer every 1 seconds
func startCounting() {
if counter == 5 {
self.timer.invalidate()
self.overlayView.isHidden = true //it is not hidden
self.imageLogo.isHidden = true
self.labelLogo.isHidden = true
self.logoAppeared = true
print("counter in if \(counter)")
} else {
counter += 1
print("counter in else \(counter)")
}
}
//animate the image before it appears on screen
func animateDidLayout(){
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidLayoutSubviews, in else")
return
}
print("appeared value after else in ViewDidLayoutSubvies \(appeared)")
//animate overlayView
self.overlayView = UIView(frame: self.view.frame)
self.overlayView.backgroundColor = UIColor.black
self.overlayView.alpha = 0.4
self.view.addSubview(self.overlayView)
//animate imageLogo
self.imageLogo = UIImageView(image:paymentLogo)
imageLogo.frame = CGRect(x: 0, y: 0, width: 100,
height: 100)
imageLogo.center.x -= 400
self.view.addSubview(imageLogo)
//animate labelLogo
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textAlignment = .center
self.view.addSubview(labelLogo)
}//end of animateDidLayout
//animate the logo when the view has appeared
//call it in ViewDidAppear
func animateDidAppear() {
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidAppear, in else")
return
}
print("appeared value in viewDidAppear after else \(appeared)")
UIView.animate(withDuration: 1.0, delay: 0.1, options: [],
animations: {
//animate overlayView
// self.overlayView = UIView(frame: self.view.frame)
//self.overlayView.backgroundColor = UIColor.black
//self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x - 100,
y: 340, width: 200, height: 21)
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textColor = .white
self.labelLogo.textAlignment = .center
self.labelLogo.sizeToFit()
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x - 50,y: 250,width: 100,height: 90)
}) { finished in
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self,
selector: #selector(ThirteenthViewController.startCounting), userInfo: nil,
repeats: true)
}
} //end of animateDidAppear
I would either use a delay or use another animation with a delay to remove hide the views. I would not rely on the timer. Example with animation to remove using your code and removing the timer.
class ViewController: UIViewController {
var counter = 0
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool? = false
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off screen
animateDidLayout()
}
override func viewDidAppear(_ animated: Bool) {
//move picture on screen and adjust view
animateDidAppear()
}
//animate the image before it appears on screen
func animateDidLayout(){
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidLayoutSubviews, in else")
return
}
print("appeared value after else in ViewDidLayoutSubvies \(appeared)")
//animate overlayView
if self.view.subviews.contains(overlayView) != true{
self.overlayView = UIView(frame: self.view.frame)
self.view.addSubview(self.overlayView)
}
self.overlayView.backgroundColor = UIColor.black
self.overlayView.layer.opacity = 0.4
self.overlayView.alpha = 0.4
//animate imageLogo
if self.view.subviews.contains(imageLogo) != true{
self.imageLogo = UIImageView(image:paymentLogo)
self.view.addSubview(imageLogo)
}
imageLogo.frame = CGRect(x: 0, y: 0, width: 100,
height: 100)
imageLogo.center.x -= 400
//animate labelLogo
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textAlignment = .center
if self.view.subviews.contains(labelLogo) != true{
self.view.addSubview(labelLogo)
}
}//end of animateDidLayout
//animate the logo when the view has appeared
//call it in ViewDidAppear
func animateDidAppear() {
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidAppear, in else")
return
}
print("appeared value in viewDidAppear after else \(appeared)")
UIView.animate(withDuration: 1.0, delay: 0.1, options: [],
animations: {
//animate overlayView
// self.overlayView = UIView(frame: self.view.frame)
//self.overlayView.backgroundColor = UIColor.black
//self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x - 100,
y: 340, width: 200, height: 21)
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textColor = .white
self.labelLogo.textAlignment = .center
self.labelLogo.sizeToFit()
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x - 50,y: 250,width: 100,height: 90)
}) { finished in
}
UIView.animate(withDuration: 0.5, delay: 5.0, options: .curveEaseInOut, animations: {
self.overlayView.alpha = 0
self.imageLogo.alpha = 0
self.labelLogo.alpha = 0
}, completion: {
finished in
self.overlayView.isHidden = true //it is hidden :)
self.imageLogo.isHidden = true
self.labelLogo.isHidden = true
self.logoAppeared = true
})
} //end of animateDidAppear}
If you prefer to wait 5 seconds and hide without animation you could use
let when = DispatchTime.now() + 5
DispatchQueue.main.asyncAfter(deadline: when) {// Your code with delay}
Or as a really fun alternative using your code and the delay
class ViewController: UIViewController {
var counter = 0
let paymentLogo = UIImage(named: "paymentImage")
var imageLogo:UIImageView!
var overlayView = UIView()
var logoAppeared:Bool? = false
let labelLogo = UILabel()
override func viewDidLayoutSubviews() {
//move picture off screen
animateDidLayout()
}
override func viewDidAppear(_ animated: Bool) {
//move picture on screen and adjust view
animateDidAppear()
}
//animate the image before it appears on screen
func animateDidLayout(){
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidLayoutSubviews, in else")
return
}
print("appeared value after else in ViewDidLayoutSubvies \(appeared)")
//animate overlayView
if self.view.subviews.contains(overlayView) != true{
self.overlayView = UIView(frame: self.view.frame)
self.view.addSubview(self.overlayView)
}
self.overlayView.backgroundColor = UIColor.black
self.overlayView.layer.opacity = 0.4
self.overlayView.alpha = 0.4
//animate imageLogo
if self.view.subviews.contains(imageLogo) != true{
self.imageLogo = UIImageView(image:paymentLogo)
self.view.addSubview(imageLogo)
}
imageLogo.frame = CGRect(x: 0, y: 0, width: 100,
height: 100)
imageLogo.center.x -= 400
//animate labelLogo
self.labelLogo.frame =
CGRect(x: 0, y: 0, width: 200, height: 21)
self.labelLogo.center.x -= 400
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textAlignment = .center
if self.view.subviews.contains(labelLogo) != true{
self.view.addSubview(labelLogo)
}
}//end of animateDidLayout
//animate the logo when the view has appeared
//call it in ViewDidAppear
func animateDidAppear() {
guard let appeared = self.logoAppeared, appeared == false else{
print("appeared is true in viewDidAppear, in else")
return
}
print("appeared value in viewDidAppear after else \(appeared)")
UIView.animate(withDuration: 1.0, delay: 0.1, options: [],
animations: {
//animate overlayView
// self.overlayView = UIView(frame: self.view.frame)
//self.overlayView.backgroundColor = UIColor.black
//self.overlayView.alpha = 0.4
//animate labelLogo
self.labelLogo.frame = CGRect(x: self.view.center.x - 100,
y: 340, width: 200, height: 21)
self.labelLogo.text = "Your booking is confirmed!"
self.labelLogo.textColor = .white
self.labelLogo.textAlignment = .center
self.labelLogo.sizeToFit()
//animate imageLogo
self.imageLogo.frame =
CGRect(x: self.view.center.x - 50,y: 250,width: 100,height: 90)
}) { finished in
}
let when = DispatchTime.now() + 5
DispatchQueue.main.asyncAfter(deadline: when) {
let transition = CATransition()
transition.duration = 0.5
transition.type = "suckEffect"
self.view.layer.add(transition, forKey: nil)
self.overlayView.isHidden = true //it is hidden :)
self.imageLogo.isHidden = true
self.labelLogo.isHidden = true
self.logoAppeared = true
}
} //end of animateDidAppear}