EXC_BAD_ACCESS when setting properties of an option view property - ios

I'm trying to figure out how to make a UIProgessView (loading Bar) have the color tint of green. I've looked around and there is no working Swift version for this. I am also trying to figure out how to take the bar off of the screen when it's finished. Nothing is done with the storyboard, everything is done programmatically.
I'm trying to customize the bar with this but it says "Bad access".
self.progressView!.tintColor = UIColor.greenColor()
This is where I'm trying to hide the bar, but there is a bad access here as well.
progressView!.hidden = true
The context:
import UIKit
import AVFoundation
class MainController: UIViewController {
var progressView: UIProgressView?
override func viewDidLoad() {
super.viewDidLoad()
addControls()
}
func addControls() {
//----This where it try to change the tint below
self.progressView!.tintColor = UIColor.greenColor()
// Create Progress View Control
progressView = UIProgressView(progressViewStyle: UIProgressViewStyle.Default)
progressView?.center = self.view.center
view.addSubview(progressView!)
}
}

You haven't actually created the UIProgressView before you call self.progressView!.tintColor thus, progressView is nil at this point but you're trying to force unwrap it.
Move the progressView = UIProgressView(...) line up to the top of addControls() and that should solve the problem.

Related

How to change background color in iOS/XCode on click

I'm trying to learn iOS programming. To start I want to change the background color of my view when a button is clicked. My entire code looks as follows, but when I click the button no change happens. I'm using Xcode 13.1. Also I'm using a storyboard.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NSLog("The app has launched")
}
#IBAction func changeColorClicked(_ sender: UIButton) {
self.myBtn.backgroundColor=UIColor.green
NSLog("I want to change color to green")
}
}
I see the NSLog message when I click, just no color change.
Check a few things:
First make sure your IBOutlet and IBAction are connected to the button itself.
You don't need to declare self here as the button as its already declared above and you don't need to call an instance of the view controller you're using to access the button.
You can also declare it like this to change the colour of the button in the function:
myBtn.backgroundColor = .green
To change the button's background colour when pressed.
Update on this thread if you can get it working.

How to use Lottie Animation using storyboard

I'm using the latest version of Xcode.
I have a JSON file whose name is "rainynight".
I want to display it into 'View' component using storyboard.
Below is the code I wrote on my ViewController.
import UIKit
import Lottie
class ViewController: UIViewController {
#IBOutlet weak var animationView: AnimationView!
override func viewDidLoad() {
super.viewDidLoad()
animationView.contentMode = .scaleAspectFit
animationView.loopMode = .loop
animationView.play()
}
and then, I went to attribute inspector to set the Animation View's Animation name.
Screenshot of main.stroyboard
Until now, everything works fine.
The "rainynight" JSON file is shown in the view perfectly fine.
But the problem is that my ultimate goal is displaying several Lottie animations randomly.
Actually, I will connect Lottie animation with weather API but for convenience's sake let's say I want to display JSON files randomly.
For example, I have an array that contains JSON files' name like this.
let jsonArray = ["rainynight", "storm", "foggy"]
I have these JSON files on my file list.
But how do I show randomly one of these elements on the view using storyboard?
I know it can be solved super easily by writing a code.
But by writing a code, as far as I know, I can only set the animation in the center or something else.
I want the animation to be set at the place I exactly want it to be.
The location of the animation view can't be described with just simple word 'center'.
That's why I want to use storyboard.
Put a UIView wherever you want in your storyboard, and change the class name to AnimationView. Drag an outlet to your view controller.
Then the rest is just as easy.
#IBOutlet weak var animationView: AnimationView!
override func viewDidLoad() {
super.viewDidLoad()
let subAnimationView = AnimationView(name: "myAnimationName")
animationView.contentMode = .scaleAspectFit
animationView.addSubview(subAnimationView)
subAnimationView.frame = animationView.bounds
subAnimationView.play()
}

Is there a way to change the background colour of a UINavigationBar in swift 4

As the title implies I'm wondering if there is a way to change the background colour of a UINavigationBar in Swift. I know this question has been asked once before as I found this question here but I couldn't get any of the code to work when I tried to bring it up to date. I have linked the custom class which is a subclass of UINavigationController. Currently, the background colour of all the child UINavigationItem's have the default background colour of a slightly tinted white. I want to be able to change their colour to fit the rest of the UI elements in my app as most of them are extremely dark so I'm trying to change that below there is a picture of what I'm trying to replicate.
Is there is a more recent way to do this? Maybe using User defined runtime attributes. I'm out of ideas.
I've tried
#objc func changebarColor(){
self.navigationController?.navigationBar.barTintColor = UIColor.red;
}
override func viewDidLoad() {
super.viewDidLoad()
changebarColor()
}
And
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.barStyle = UIBarStyle.blackTranslucent
self.navigationController?.navigationBar.barTintColor = UIColor.red;
}
And
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController!.navigationBar .setBackgroundImage(UIImage(), for: UIBarMetrics.default)
self.navigationController!.navigationBar.shadowImage = UIImage();
self.navigationController!.navigationBar.isTranslucent = true;
self.navigationController!.navigationBar.backgroundColor = UIColor.red;
}
As well as all of the other answers posted on the page. Slightly tweaking them to remove errors.
You are on the right track, but you are calling it in the wrong place. You should move it to viewWillAppear which is called every time you view is going to be displayed. viewDidLoad() is only called once.
This means that another view controller or even the OS can change the colour of your navigation bar after viewDidLoad()
override func viewWillAppear(_ animated:Bool)
{
super.viewWillAppear( animated)
self.navigationController?.navigationBar.barTintColor = UIColor.red
}
Also, you don't need semi colons in Swift.

Multiple ViewControllers with same background

How can one still background image in multiple view controllers be implemented?
With self.view.backgroundColor = UIColor(patternImage: UIImage(named: "file.png")) background would move along with UIViewController while screen switching.
Is it possible to place image on separate layer under view controllers?
Solution 1
Create a class called MyBackground:
class MyBackground {
class func addBackgroundImage() {
UIGraphicsBeginImageContext(self.view.frame.size)
UIImage(named: "file")?.drawInRect(self.view.bounds)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
view.backgroundColor = UIColor(patternImage: image)
}
}
If you want to call it in your AViewController, simply call MyBackground.addBackgroundImage()
Solution 2
Create a ViewController called MyViewController:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addBackgroundImage()
}
func addBackgroundImage() {
UIGraphicsBeginImageContext(self.view.frame.size)
UIImage(named: "file")?.drawInRect(self.view.bounds)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
view.backgroundColor = UIColor(patternImage: image)
}
}
If you AViewController want to set this image, simply do like this:
AViewController: MyViewController //AViewController is a subclass of MyViewController
For example: I have an image call background, and I will set it as a background image of my ViewController:
If I just add it in one line as #startupthekid said:
If I add it as I said:
i think you can set background in your container view controllers, such as navi controller, tab controller, then set all your view controller's background to clear color.
A better answer is to use UIAppearance. If you're not familiar with it, UIAppearance is a proxy protocol that you send messages to and it modifies later instances of that class.
For example if I have a custom button class RoundButton:
RoundButton.appearance().titleFont = Font.Heavy(20)
And in my RoundButton class:
dynamic var titleFont: UIFont? {
get { return self.titleLabel?.font }
set { self.titleLabel?.font = newValue }
}
The dynamic keywords is incredibly important. It's used for objective-c compatibility and setting properties via UIAppearance that don't use it will cause a crash.
You can do as many custom properties as you want and there's a bunch already default in the os.
In your case you can do something like:
UIImageView.appearanceWhenContainedInInstancesOfClasses([MyCustomViewController.self)].customImage = UIImage(...)
You can of course get away with just a custom view controller but in my opinion, UIApperance keeps your UI code separate from your controller logic.
One way you could implement the behavior you want is a UIViewController subclass:
class MyCustomViewController: UIViewController {
private let backgroundImageView = UIImageView()
dynamic var backgroundImage: UIImage? {
get { self.backgroundImageView.image }
set { self.backgroundImageView.image = newValue }
}
}
and then modify the backgroundImage property on the appearance instance of MyCustomViewController.
MyCustomViewController.appearance().backgroundImage = ...
EDIT: Given that your question was misleading and that you instead want a shared image that never moves throughout all your view controllers, you can simply insert an image view into the application window:
if let window = UIApplication.sharedApplication().windows.first {
let imageView = UIImageView(image: UIImage(named: "face-mask"))
window.addSubview(imageView)
imageView.frame = window.bounds
}
If you like Autolayout, like I do, then I'd set constraints to pin the image view to the window edges.
you should set the image in viewDidload of every viewController
Update :
either you should set in every view controller or you can set to windows . Second thing if your background changes dynamically with different images then you can use prepareforsegue method to pass images to nextviewcontroller if images are different for each viewcontroller. if same image for every viewcontroller then you can set it to window.
:)

Adding View Programmatically from ViewController super class doesn't show in front

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()
}

Resources