I've created an #IBOutlet weak var animationView: AnimationView! Then on ViewController I added a UIView changed its class from UIView to AnimationView. The after connecting the outlet I'm adding this code in viewDidLoad() of my class:
let animation = Animation.named("sticky", subdirectory: "Lottie-files")
animationView.animation = animation
animationView.loopMode = .loop
animationView.contentMode = .scaleAspectFill
Then in viewDidAppear() I've added:
animationView.play()
But when I run it nothing shows up. I also see this in the terminal:
[Storyboard] Unknown class AnimationView in Interface Builder file.
This warning is solved by doing
But still the animation is not appearing. No warning, no error it just not displaying.
You should start animation in viewDidAppear or something called after viewDidLoad, for example: viewWillAppear
public override func viewDidLoad() {
super.viewDidLoad()
addAnimation(to: animationView, name: "sticky")
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
animationView.play()
}
private func addAnimation(to view: AnimationView, name: String) {
let animation = Animation.named(name, subdirectory: "Lottie-files")
view.animation = animation
view.loopMode = .loop
view.contentMode = .scaleAspectFill
}
BONUS
Ekramul Hoque's Article about View Controller's Lifecycle
Make sure these
You should write Lottie to your view's Identity Inspector section in Interface Builder's right bar.
Check for subdirectory path. It can be because Xcode is unable to locate file in Lottie-files subdirectory. Try moving it in the main directory and try.
You can set programmatically
import Lottie
then add animation view in your view controller, set lottie animation in your storyboard -> animationView -> class -> AnimationView and module -> Lottie
#IBOutlet weak var animationView: AnimationView!
//Initialise a Lottie view with frame
let customAnimationView = AnimationView(name: "Your lotti file name")
customAnimationView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
//Do your configurations
customAnimationView.loopMode = .loop
customAnimationView.backgroundBehavior = .pauseAndRestore
//And play
customAnimationView.play()
animationView.addSubview(customAnimationView)
As per the lottie document you should call
play()
function inside viewDidAppear.
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
animationView.play()
}
Please check the following link
https://github.com/airbnb/lottie-ios/blob/master/Example/lottie-swift/ViewController.swift
NOTE : In some case you need to check sub directory problem
You need to add Folder References
Not a Groups
for more information on this section please check the following link.
http://www.thomashanning.com/xcode-groups-folder-references/
Related
there is a requirement like add an imageview to all viewcontrollers but I have 150+ xib's and it is time consuming to put imageview in every single xib.
Is there a common way to do it? I googled but nothing useful found.
Any help would be appreciated.
It will be easy if you use base class like this
class BaseVC: UIViewController
{
var imageView:UIImageView = UIImageView.init()
override func viewDidLoad() {
super.viewDidLoad()
addImageView()
}
override func viewWillAppear(_ animated: Bool) {
//self.view.bringSubview(toFront: imageView) //To bring imageview infront of other views put this method as per your requirement
}
func addImageView(name:String = "default")
{
let image = UIImage(named: name)
imageView.image = image
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 200)
//view.addSubview(imageView)
view.insertSubview(imageView, at: 0) /*For put image view below all image*/
}
}
You need to derive all your view controller from this like this
class YourVC: BaseVC
also you can change the image with different viewcontrollers.
like
class YourVC: BaseVC
{
override func viewDidLoad() {
super.viewDidLoad()
addImageView(name:"xyz")
}
}
you can write an extension for UIView to add imageview into it and run it into every your viewcontrollers.
extension UIView {
func addImage() {
let imageView = UIImageView(frame: frame)
imageView.image = UIImage(named: "Your Image Name")
addSubview(imageView)
imageView.didMoveToSuperview()
}
}
Create New ViewController without storyboard.
import UIKit
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setImageView()
}
func setImageView() {
let thisImageView = UIImageView(frame: CGRect(x: 10, y: 10, width: 70, height: 70))
thisImageView.image = UIImage(named: "your image name")
view.addSubview(thisImageView)
}
}
now you can set this BaseViewController as delegate of your project's ViewControllers.
import UIKit
class MainViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
now you have this ImageView in MainViewController and all ViewControllers have BaseViewContoller as delegate.
Hope to be useful. Also sorry about my English.
TL;DR No. Based on my understanding of what you are imagining, no you can't write a function to add a UIImageView to every one of your viewControllers.
Long answer:
You need to create a separate controller swift file for each View and set it up in that file. You could create a supporting file in which you setup up the the ImageView then call in in the viewDidLoad for each view controller. (You could even make this an extension of UIView so you can just call something like self.setUpImageView())
My personal recommendation would be to drop the xibs as soon as you can and recreate everything pragmatically, I know it's a headache to throw all your work away but it is really worth it in the end on top of just being good practice. I have a file that I found that makes autolayout a breeze that I can share with you if you'd like. I used to really enjoy storyboards and xibs myself but they are a hassle that just isn't worth it anymore and cause such a headache in situation like this.
I am working on my project app where I want to allow my user to change the background wallpaper to be same on all screens. I have a settings screen where I am adding that. I have added ImageViews to all view controllers and I have some view controllers that have UIscrollview so I added Imageview to slides template. Now my dilemma is how can I allow the user to pick the preview wallpaper so it changes the Imageview image on every view controller. I already created such #IBOutlets as shown below.
#IBOutlet weak var slideBackground: UIImageView!
#IBOutlet weak var homeScreenBackground: UIImageView!
#IBOutlet weak var settingsBackground: UIImageView!
You should use the system wide NotificationCenter.
Simply put, you can have objects subscribe to the default NotificationCenter and specify a selector (method) to execute when a notification is posted.
You can also post custom notifications that represent the wallpaper change event.
I have used this in an app I built to achieve a system wide 'dark mode' transition.
To post:
#objc func postWallpaperChangeNotification() {
NotificationCenter.default.post(name: .wallpaperChanged, object: nil)
}
To subscribe:
NotificationCenter.default.addObserver(self, selector: #selector(someMethodToRunWhenWallpaperChanges(_:)), name: . wallpaperChanged, object: nil)
You also need to remove the observer in deinit().
This is approximate code to give you a flavour, any questions hmu.
You have a few options.. what option is best depends on your needs really.
As Woodstock mentioned in his answer, you could use NotificationCentre, I wont re-explain that.
Another option would be to store the image name in UserDefaults that you are going to use for the background image.
any time you change the background... set the value
UserDefaults.standard.set(imageName, forKey "backgroundImageName")
Then in each view controller, just load the value on viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated: animated)
if let backgroundImageName = UserDefaults.standard.string(forKey: "backgroundImageName") {
self.backgroundImageView.image = UIImage(named: backgroundImageName)
}
}
Both of these options are not very easy to unit test though. You could use Mocks to test it.
A bonus of this method is that it will 'remember' the setting inbetween the user restarting the app.
An example of how you might reduce code repetition using subclassing:
class WallpaperedViewController: UIViewController {
lazy private var imageView: UIImageView = {
let imageView = UIImageView()
view.addSubview(imageView)
view.sendSubview(toBack: imageView)
return imageView
}()
private func setWallPaperImage() {
let imageName = UserDefaults.standard.string(forKey: "backgroundImageName")
let image = UIImage(named: imageName!)
imageView.image = image
//imageView.contentMode = .scaleAspectFill
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
imageView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setWallPaperImage()
}
}
Then for each ViewController that has this background image wallpaper just extend this class:
class SomeViewController: WallpaperedViewController {}
How Do I add multipleImages for the top part and have it scrollable without moving the rest of the content? Also, how do I have the little dots at the bottom to indicate which image I'm on? My code for the image is down below.
import SDWebImage
#IBOutlet weak var headerImage: UIImageView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let imageUrl:NSURL? = NSURL(string: headerPhoto!)
if let url = imageUrl {
headerImage.sd_setImage(with: url as URL!)
}
}
You are looking for something called image slide show or image slider.
Instead of creating them by yourself which requires lots of effort, here is a GitHub library that is easy to use.
Basicly the way slider works is that it is a horizontal scroll view and each cell in the scroll view is an image so that you can scroll. Then, put a fixed page index element on the bottom of the scroll view to tell you which image you are currently at.
To use it, create a UIView in your viewcontroller and set both class and module to ImageSlideshow. Then connect it to your ViewController.swift as IBOutLet.
Then create an array of image urls
let alamofireSource = [AlamofireSource(urlString: "imgurl1")!, AlamofireSource(urlString: "imgurl2")!, AlamofireSource(urlString: "imgurl3")!]
And finally in your viewDidLoad() function:
override func viewDidLoad() {
super.viewDidLoad()
slideshow.backgroundColor = UIColor.white
slideshow.slideshowInterval = 5.0
slideshow.pageControlPosition = PageControlPosition.underScrollView
slideshow.pageControl.currentPageIndicatorTintColor = UIColor.lightGray
slideshow.pageControl.pageIndicatorTintColor = UIColor.black
slideshow.contentScaleMode = UIViewContentMode.scaleAspectFill
slideshow.setImageInputs(alamofireSource)
}
thanks for all help:)! fixed it using iboutlet collection and add properies on viewDidLoad
I'm trying to add properties to keyboard keys like layer.shadowColor or layer.shadowRadius.
I got an error
'Value of type '(UIButton)' -> () has no member 'layer'
how to fix this ?
this is my code keyboardViewController.swift
import UIKit
class KeyboardViewController: UIInputViewController {
var newKeyboardView: UIView!
#IBAction func keyPressed(sender: UIButton) {
}
#IBOutlet var nextKeyboardButton: UIButton!
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
loadInterface()
}
func loadInterface() {
// load the nib file
let keyboardNib = UINib(nibName: "newKeyboard", bundle: nil)
// instantiate the view
newKeyboardView = keyboardNib.instantiateWithOwner(self, options: nil)[0] as! UIView
// add the interface to the main view
view.addSubview(newKeyboardView)
// copy the background color
view.backgroundColor = newKeyboardView.backgroundColor
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
textColor = UIColor.whiteColor()
} else {
textColor = UIColor.blackColor()
}
self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
}
}
I think that in order to apply some style to the button, you need an outlet to this button.
Right now, from what I can understand, you are trying to apply styles to the button from the #IBAction to the sender, which is not the proper way to do it.
Try to make an outlet to the button in the view controller and then to apply the styles from within the viewDidLoad method.
I hope this is clear, but if you want a more specific answer you need to show us what you tried, for example pasting the code you have in the view controller
EDIT:
Based on the code you post, the keyboard is a Nib you instantiate from loadInterface(). I don't have a clear vision of the whole thing with only this piece of code, but it seems to me that you are trying to apply some styles to every key button of a keyboard view. Unfortunately this really depends on how the keyboard is implemented, can you provide some more details?
Anyway, from what I see I think you didn't write this code: probably you are following a tutorial or maintaining someone else's code. That's ok, but I suggest you to follow a an introduction course to iOS development with Swift, like the Udacity's one, which is fantastic IMHO (https://www.udacity.com/course/intro-to-ios-app-development-with-swift--ud585)
If you try to format your UIButton with QuartzCore framework, you'll need to import it first:
import QuartzCore
Then you will be able to access those members.
For example (latest swift3 code):
#IBAction func keyPressed(sender: UIButton) {
let button = sender as UIButton!
button?.backgroundColor = UIColor.red
button?.layer.shadowColor = UIColor.black.cgColor
button?.layer.shadowRadius = 1.0
button?.layer.cornerRadius = 4.0
}
In case you need to apply your styles sooner, try to consider to put this code into viewDidLoad or viewDidAppear methods:
self.nextKeyboardButton.backgroundColor = UIColor.red
self.nextKeyboardButton.layer.shadowColor = UIColor.black.cgColor
self.nextKeyboardButton.layer.shadowRadius = 1.0
self.nextKeyboardButton.layer.cornerRadius = 4.0
Seems like you're trying to "add property" not to a button, but rather to a closure which accepts a button as an argument.
Make it like this:
nextKeyboardButton.layer.shadowColor = UIColor.redColor.cgColor
nextKeyboardButton.layer.shadowRadius = 5.0
I have a BaseViewController that my UIViewControllers extend so i can have explicit functions that i dont need to rewrite. Something i would like would be a functions such as self.showSpinner() and the viewController would show the spinner
My Code looks like this
class BaseViewController: UIViewController {
var actvIndicator : UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
self.actvIndicator = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
self.actvIndicator.color = UIColor.blackColor()
self.actvIndicator.backgroundColor = UIColor.blackColor()
self.actvIndicator.frame = CGRectMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2, 100, 100);
self.actvIndicator.center = self.view.center
self.actvIndicator .startAnimating()
self.view.addSubview(self.actvIndicator)
self.actvIndicator.bringSubviewToFront(self.view)
self.edgesForExtendedLayout = UIRectEdge.None
self.navigationController?.navigationBar.translucent = false
}
func showSpinner(){
self.actvIndicator.startAnimating()
}
func hideSpinner(){
self.actvIndicator.stopAnimating()
}
}
And my viewcontrollers looks like this
class MyProjectViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.showSpinner()
}
}
MyProjectViewController have UITableView that fills the entire screen. When i set tblProjects.alpha = 0 i can see the spinner. But i want it in the front.
i also tried self.view.bringSubviewToFront(self.actvIndicator)
What am i missing?
A couple quick notes before I get into what I think your problem is:
When you add a subview it is automatically added to the top layer, no need for the bringSubviewToFront: in viewDidLoad: (which is being used wrong anyway).
You should not set view frames in viewDidLoad: (e.g. centering a view). Frames are not setup yet, so you should move that to viewWillAppear: or some other variant.
Now your issue is most likely a view hierarchy problem (further confirmed by your comment) and thus can probably be fixed by pushing the spinner to the front every time you want it to be shown, like:
func showSpinner() {
self.view.bringSubviewToFront(self.actvIndicator)
self.actvIndicator.startAnimating()
}
The problem here stands on the fact that table view is draw after you are calling self.view.bringSubviewToFront(self.actvIndicator). A possible workaround for this is to call bringSubviewToFront when showing the spinner
func showSpinner(){
self.view.bringSubviewToFront(self.actvIndicator)
self.actvIndicator.startAnimating()
}