I am getting a delay on animation when popping a view controller.
The reason I am getting the delay is because I have a background image.
override func viewDidLoad() {
super.viewDidLoad()
setBackgroundImage()
}
#IBAction func navigationButton(_ sender: Any) {
print("navigation button presssed")
self.navigationController?.popViewController(animated: true)
}
func setBackgroundImage() {
let backgroundImage = UIImageView(frame: UIScreen.main.bounds)
backgroundImage.image = UIImage(named: "RewardsBackgroundONLY")
backgroundImage.contentMode = UIView.ContentMode.scaleAspectFill
self.view.insertSubview(backgroundImage, at: 0)
}
How do I prevent the delay from happening while setting the background image.
I also tried popping the view controller on the main thread, still doesnt work.
Probably your image is too large and the content mode backgroundImage.contentMode = UIView.ContentMode.scaleAspectFill cause this behavior.
you have two ways to resolve this problem.
change the UIView.ContentMode value and check if is ok for you. try scaleToFill or scaleAspectFit
resize image to fit on your app.
just set
clipsToBounds = true
it works for me
Related
I have a form that should be completed from the user, which is split between 3 UITabBarItems in 1 UITabBarController. I would like to change UITabBarItem's image dynamically. For example, the user is on the first step and right after he completes the configuration needed on that step I want the UITabBarItem that is responsible for this UIViewController to change its image to a tick indicating that the user can proceed to step two
I tried to set the tabBarItem in the current view controller to an image when all the values are completed, but it didn't work
if manufacturerCompleted
&& modelCompleted
{
let image = UIImage(named: "tick")
self.tabBarItem.image = image?.withRenderingMode(.automatic)
}
Thank you in advance! :)
Personally, I don't see any mistakes in the code. Maybe it doesn't get executed?
I suppose, you don't have an #IBAction function which gets called on the text change event (or whatever it is called). Try setting up one, connect it to the storyboard and then try again.
Oh, and a more 'swift-ey' way to handle optionals is the 'optional binding'. See more here.
var manufacturerCompleted = false
var modelCompleted = false
#IBAction func handleKeyDown(_ sender: UITextField) {
updateManufacturerComplete(sender)
updateModelComplete(sender)
if manufacturerCompleted && modelCompleted {
if let image = UIImage(named: "tick") as UIImage? {
self.tabBarItem.image = image.withRenderingMode(.automatic)
}
}
}
func updateManufacturerComplete(_ sender: UITextField) {
// Your condition here
// ...
self.manufacturerCompleted = true
}
func modelCompleted(_ sender: UITextField) {
// Your condition here
// ...
self.modelCompleted = true
}
How can I implement the fullscreen image and dismiss image functionality of the Apple Photos? Additionally, how can I get the aspect ratio of an image to fit within a fullscreen view? Are they sending a UIImage to a new view controller?
My current method of fullscreening an image simply sets a UIImageView's frame equal to the superview's frame while turning the alphas of the UINavigationBar and UITabBar to 0. And to dismiss, I added a tap gesture recognizer that reverses the alphas and removes the UIImageView from the superview.
Here's my fullscreen and dismiss code
func fullscreen(forImage image: UIImage) {
let imageView = UIImageView(image: image)
imageView.frame = self.view.frame
imageView.backgroundColor = .black
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.isUserInteractionEnabled = true
self.navigationController?.navigationBar.alpha = 0
self.tabBarController?.tabBar.alpha = 0
let dismissTap = UITapGestureRecognizer(target: self, action: #selector(dismissFullscreenImage))
imageView.addGestureRecognizer(dismissTap)
self.view.addSubview(imageView)
}
#objc func dismissFullscreenImage(_ sender: UITapGestureRecognizer) {
sender.view?.removeFromSuperview()
self.navigationController?.navigationBar.alpha = 1
self.tabBarController?.tabBar.alpha = 1
}
This could easily be achieved using Apple's QuickLook framework as it works great for many extensions and collections of images.
Edit: Most of the functionality you want is built into the QLPreviewController
let previewController = QLPreviewController()
previewController.dataSource = self
self.present(previewController, animated: true, completion: nil)
The data source is whatever class conforms to the QLPreviewControllerDataSource protocol
Here is a video guide from apple on how to achieve this easily
Edit: This part goes in the previewItemAt function
guard let url = Bundle.main.url(forResource: "imageName", withExtension: "jpg")
else {
fatalError("Could not load imageName.jpg")
}
return url as QLPreviewItem
I understand there are other questions like this but so far I have not been able to get an answer that works for so this is why I am writing this.
I right now have the following code to place a leftBarButtonItem:
let user = FIRAuth.auth()?.currentUser
var imageView: UIImageView?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupNavBar()
}
func setupNavBar() {
//left bar button item setup
let url = URL(string: (self.user?.photoURL?.absoluteString)!)
let data = try? Data(contentsOf: url!)
imageView?.image = UIImage(data: data!)
imageView?.layer.masksToBounds = true
imageView?.layer.borderWidth = 1.5
imageView?.layer.borderColor = UIColor.white.cgColor
imageView?.layer.cornerRadius=(imageView?.bounds.width)! / 2
let profileImageButton = UIBarButtonItem(image: UIImage(named: (self.user?.photoURL?.absoluteString)!), style: .plain, target: self, action:#selector(UserGroupsMainViewController.navLeftBarButtonTapped))
self.navigationController?.navigationItem.leftBarButtonItem = profileImageButton
}
func navLeftBarButtonTapped() {
}
For some reason, the button does not appear on the navigation controller. I do know for sure that I have a URL that is not nil because I tested it in my print output. Any help would be appreciated. Thanks!
Just use navigationItem not navigationController.navigationItem
Ok, I just saw your problem.
You are using a URL as the "name" of an image. It doesn't work that way.
The function UIImage(named: "blah") will load an image from the app bundle stored with the name given.
If you want to download the image from a URL then you need to have a download task run in the background and then load the image once that's done.
Try using the AlamofireImage framework also.
As the code shows, I have the switch which starts the animation when turned on, but the confetti anyway is displayed and doesn't let me have button interactions !
#IBAction func `switch`(_ sender: UISwitch) {
if(sender.isOn==true){
senderText.text="YAYA!"
supportText.text="we have added a reminder for you"
supportIcon.isHidden=false
support2.isHidden=true
confettiView.startConfetti()
}
else{
senderText.text="OKAY"
supportText.text="you wont be disturbed"
supportIcon.isHidden=true
support2.isHidden=false
}
}
var confettiView: SAConfettiView!
override func viewDidLoad() {
super.viewDidLoad()
confettiView = SAConfettiView(frame: self.view.bounds)
confettiView.colors = [UIColor(red:0.95, green:0.40, blue:0.27, alpha:1.0),
UIColor(red:1.00, green:0.78, blue:0.36, alpha:1.0),
UIColor(red:0.48, green:0.78, blue:0.64, alpha:1.0),
UIColor(red:0.30, green:0.76, blue:0.85, alpha:1.0),
UIColor(red:0.58, green:0.39, blue:0.55, alpha:1.0)]
confettiView.intensity = 0.5
confettiView.type = .Diamond
confettiView.type = .Confetti
view.addSubview(confettiView)
What is happening is that your confettiView is on top of all the other views and is receiving all the touches, preventing buttons and switches to receive them
confettiView.isUserInteractionEnabled = false
This line of code to be inserted right after your confettiView initialization should solve the issue, as the confetti view will no longer intercept all touches.
Another solution (depending on your design requirements) would be to bring all the buttons to front, if you have a reference for them, or to remove the confetti view if you want an animation of defined duration.
Also please not that
confettiView.type = .Diamond
confettiView.type = .Confetti
will cause the type to be .Confetti. Consider to remove one of the two type assign statement. :)
Your confettiView is above all of your other UIView's and UIButton's.
confettiView = SAConfettiView(frame: self.view.bounds) makes your confettiView the size of the entire screen. You're then adding it to the view with view.addSubview(confettiView). Remove the confettiView after your animation.
For example:
confettiView.removeFromSuperview()
I'm putting the finishing touches on an app I'm about to publish and I've enountered difficulty getting the contentMode of a UIButton's background image to be respected. Regardless of the contentMode I specify, the image just gets plopped in the background with no regard for the contentMode setting.
I've looked at a post covering this topic, but it doesn't appear to do anything in my circumstance.
This is called in from viewDidLoad:
// I tried putting the contentMode lines here...
myButton.imageView!.contentMode = .scaleAspectFit
myButton.contentMode = .scaleAspectFit
myButton.setBackgroundImage(UIImage(named: "myImage.png"), for: .normal)
// ...and here
// myButton.imageView!.contentMode = .scaleAspectFit
// myButton.contentMode = .scaleAspectFit
// I threw this in for S's & G's to see if it would work...it didn't
myButton.translatesAutoresizingMaskIntoConstraints = false
myButton.imageView?.translatesAutoresizingMaskIntoConstraints = true
I'm not sure what I'm missing, but I rest assured it will be something startling stupid on my part. I welcome suggestions on how I can get the contentMode of a UIButton's background image to be respected. Thank you for reading.
Update
The button is typed as a custom button, not a system button.
The problem is that you add an image using setBackgroundImage() method. This adds your image to some private UIImageView that you can't reach directly like myButton.imageView!. In your code, you're applying contentType for you button instead of its background image.
If you want to reach this background UIImageView you need to use subviews array. But if you try to do this inside your viewDidLoad() method, you'll find that background UIImageView hasn't been added yet because your buttons layout method wasn't called. There are 2 ways to fix that.
Solution 1 – call layoutIfNeeded explicitly:
override func viewDidLoad() {
super.viewDidLoad()
myButton.setBackgroundImage(UIImage(named: "myImage"), for: .normal)
myButton.layoutIfNeeded()
myButton.subviews.first?.contentMode = .scaleAspectFit
}
Solution 2 – move contentMode setup at viewDidAppear method.
override func viewDidLoad() {
super.viewDidLoad()
myButton.setBackgroundImage(UIImage(named: "myImage"), for: .normal)
myButton.setTitle("Some title", for: .normal)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
myButton.subviews.first?.contentMode = .scaleAspectFit
}
Hope it helps you.
To simplify the accepted answer, all you need to do is layout the subviews and your setup code can be done in one place.
override func viewDidLoad() {
super.viewDidLoad()
myButton.setBackgroundImage(UIImage(named: "myImage.png"), for: .normal)
myButton.layoutIfNeeded()
myButton.subviews.first?.contentMode = .scaleAspectFill
}
A button's imageView property and backgroundImage property are two separate things.
Unlike the accepted answer, you can use the imageView property instead.
override func viewDidLoad() {
super.viewDidLoad()
myButton.setImage(UIImage(named: "myImage.png"), for: .normal)
myButton.imageView?.contentMode = .scaleAspectFill
}