I have a UINavigationController that I am adding a UIViewController to. Inside my UIViewController I have a webview and also trying to set a UIActivityIndicatorView. However I can't seem to get the UIActivityIndicatorView to show up. Any help would be great!
class TestWebViewController: UIViewController {
var loadSpinner: UIActivityIndicatorView!
var webView: UIWebView!
var title: String?
init(title: String?) {
self.title = title
self.webView = UIWebView(frame: CGRect.zero)
super.init(nibName: nil, bundle: nil)
commonInit()
}
func commonInit() {
loadSpinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
loadSpinner.center = webView.center
view.addSubview(loadSpinner)
webView.delegate = self
view = webView
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
UINavigationController(rootViewController: testWebViewController)
Even when I try to add the loadSpinner to the webView it does not appear webView.addSubview(loadSpinner)
Result:
Code:
class ViewController: UIViewController {
var loadSpinner: UIActivityIndicatorView!
var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.webView = UIWebView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
loadSpinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
webView.addSubview(loadSpinner)
view = webView
loadSpinner.startAnimating()
}
override func viewDidLayoutSubviews() {
loadSpinner.center = webView.center
}
}
Your primary issue is that you first add the activity indicator to the view controller's view but two lines later you replace the view controller's view with the web view.
If you are going to replace the view controller's view you should do that in loadView. You should also setup other views in viewDidLoad, not in an init method.
The simplest change is to get rid of your commonInit method and put all of that code in viewDidLoad. Then in viewDidLoad, setup the web view first, then setup the activity indicator.
class TestWebViewController: UIViewController {
var loadSpinner: UIActivityIndicatorView!
var webView: UIWebView!
var title: String?
init(title: String?) {
self.title = title
super.init(nibName: nil, bundle: nil)
}
override func loadView() {
// don't call super
webView = UIWebView(frame: CGRect.zero)
webView.delegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
loadSpinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
loadSpinner.center = view.center
// Keep it in the center
loadSpinner.autoresizingMask = [.flexibleWidth, .flexibleLeftMargin, .flexibleRightMargin]
view.addSubview(loadSpinner)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
You also have an issue with title. UIViewController already has a title property. You should not add your own.
You need to refactor your code like this inside viewDidLoad
class TestWebViewController: UIViewController {
var loadSpinner: UIActivityIndicatorView!
var webView: UIWebView!
var title: String?
override func viewDidLoad()
{
super.viewDidLoad()
webView = UIWebView(frame:self.view.frame)
webView.delegate = self
self.view.addSubview(webview)
loadSpinner = UIActivityIndicatorView(activityIndicatorStyle: .gray)
self.view.addSubview(loadSpinner)
loadSpinner.center = self.view.center
loadSpinner.startAnimating()
}
}
Related
I have a UIView which have a button and some view to indicate sucess and failure. I am trying to use that UIView on other view controllers and receive the button action on called view controllers.
This is what i have tried so far
protocol FailViewDelegate: class {
func tryAgainTapped()
}
class AlertView: UIView {
static let instance = AlertView()
weak var delegate : FailViewDelegate?
#IBOutlet weak var titleLbl: UILabel!
#IBOutlet weak var messageLbl: UILabel!
#IBOutlet weak var dashIMageView: AnimatableImageView!
#IBOutlet weak var circleView: AnimatableView!
#IBOutlet weak var iconStatus: AnimatableImageView!
#IBOutlet weak var tryAgainButton: AnimatableButton!
#IBOutlet weak var parentView: UIView!
private override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
Bundle.main.loadNibNamed("AlertView", owner: self, options: nil)
}
enum AlertType {
case success
case failure
}
func showAlert(alertType: AlertType, to: UIViewController) {
switch alertType {
case .success:
dashIMageView.image = UIImage(named: "circle-dash-blue")
circleView.backgroundColor = UIColor(hexString: "#4EBFFF")
titleLbl.text = "Success"
titleLbl.textColor = UIColor(hexString: "#4EBFFF")
messageLbl.text = "Your ticket has been created."
tryAgainButton.isHidden = true
iconStatus.image = UIImage(named: "icon-check")
case .failure:
dashIMageView.image = UIImage(named: "circle-dash-red")
circleView.backgroundColor = UIColor(hexString: "#EB3708")
titleLbl.text = "Failure"
titleLbl.textColor = UIColor(hexString: "#EB3708")
messageLbl.text = "There was an error, creating your ticket."
tryAgainButton.isHidden = false
iconStatus.image = UIImage(named: "icon-close")
}
parentView.center = to.view.center
to.view.addSubview(parentView)
}
func dismissAlert() {
parentView.removeFromSuperview()
}
#IBAction func tryAgainButtonTapped(_ sender: AnimatableButton) {
delegate?.tryAgainTapped()
}
}
This is how i have called the view
class CreateTicketViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
AlertView.sharedInstance.delegate = self
}
#IBAction func createTicketTapped(_ sender: AnimatableButton) {
AlertView.sharedInstance.showAlert(alertType: .failure, to: self)
}
}
extension CreateTicketViewController : FailViewDelegate {
func tryAgainTapped() {
print("Try Again Tapped")
}
}
This is the error that i got
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
(in dashIMageView.image = UIImage(named: "circle-dash-red")) and when i remove the dashImageView then the error occur for nextView and so on
You don't need to make it a singleton, which in this case (View) is a very uncommon approach, I think. You can create as many instances of that view as you want any time, anywhere (on other ViewControllers) you want and specify them, the way you want them to have.
When you want a view to be rendered and be visible, it always must be part of the view hierarchy in the current visible view controllers main view. And a view can only have ONE SUPERVIEW at the time, so whenever you add a (singleton) view to another superview, it will be removed from an other superview. If you want the same view on many view controllers (no problem), just don't let it be a singleton.
So first thing to do -> Remove the singleton design by commenting out that line:
class AlertView: UIView {
// make this line a comment or just remove it
// static let instance = AlertView()
weak var delegate : FailViewDelegate?
In your different view controllers you just create that instances of your AlertView and set the delegate correctly like this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
myAlertView = AlertView()
myAlertView.delegate = self
// then you don't need this anymore
// AlertView.sharedInstance.delegate = self
}
I have an app where there is a "DadViewController" which contains a UIScrollView that has paging enabled. Each page is populated with a different UIViewController.
How Do I push a new UIViewController, from a button tap, within one of the controllers contained in the UIScrollView?
class DadView: UIView {
let model = DadModel()
let scrollView: UIScrollView = {
let view = UIScrollView()
view.isPagingEnabled = true
// Additional setup...
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupScrollView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupScrollView() {
self.addSubview(scrollView)
// Autolayout code to pin scrollview to all 4 sides
let vc1 = VC1()
scrollView.addSubview(vc1.view)
vc1.view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
// Add additional view controller views with the appropriate frames...
}
}
class DadController: UIViewController {
var dadView: DadView!
override func loadView() {
super.loadView()
dadView = DadView()
view = dadView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
class VC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
}
Change your DadView setupScrollView to accept a UIViewController instance as argument. And don't call this method in init
class DadView: UIView {
let model = DadModel()
let scrollView: UIScrollView = {
let view = UIScrollView()
view.isPagingEnabled = true
// Additional setup...
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
// setupScrollView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupScrollView(_ parentVC: UIViewController) {
self.addSubview(scrollView)
// Autolayout code to pin scrollview to all 4 sides
let vc1 = VC1()
vc1.view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
parentVC.addChild(vc1)
scrollView.addSubview(vc1.view)
vc1.didMove(toParent: parentVC)
// Add additional view controller views with the appropriate frames...
}
}
In DadViewController after creating DadView instance call setupScrollView method with self
class DadController: UIViewController {
var dadView: DadView!
override func loadView() {
super.loadView()
dadView = DadView()
dadView.setupScrollView(self)
view = dadView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Then you can get parent view controller from child viewcontroller and perform push
class VC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
#IBAction func buttonAction(_ sender: UIButton) {
self.parent?.navigationController?.pushViewController(NewVC(), animated: true)
}
}
Now I'm practicing build IOS app without using storyboard , but I have a problem want to solve , I created a custom UIView called BannerView and added a background(UIView) and a title(UILabel) , and called this BannerView in the MainVC , but run this app , it crashes at the function setupSubviews() and I don't know why.
import UIKit
import SnapKit
class BannerView: UIView {
var background: UIView!
var title: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
convenience init() {
self.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
func setupSubviews() {
background.backgroundColor = .gray
title.text = "INHEART"
self.addSubview(background)
self.addSubview(title)
}
override func layoutSubviews() {
background.snp.makeConstraints { make in
make.width.equalTo(ScreenWidth)
make.height.equalTo(BannerHeight)
make.left.top.right.equalTo(0)
}
title.snp.makeConstraints { make in
make.width.equalTo(100)
make.center.equalTo(background.snp.center)
}
}
}
class MainVC: UIViewController {
var bannerView:BannerView!
override func viewDidLoad() {
super.viewDidLoad()
bannerView = BannerView(frame: CGRect.zero)
view.addSubview(bannerView)
}
}
Your properties do not appear to be initialised
var background: UIView!
var title: UILabel!
You should initialize these in your init method
self.background = UIView()
self.title = UILabel()
If you use force unwrapping on a class property you must initialize in the init method. XCode should be complaining to you about this and your error message should show a similar error
You are not initialised the background view please initialised them
self.background = UIView()
self.title = UILabel()
and if you want to create custom view by use of xib the follow them Custum View
You must have to initialised the self.background = UIView() and self.title = UILabel() first.
You can initalised them in setupSubviews() function before the set/assign values to them.
I have created a custom view from xib(freeform) in which there are two button (Login and cancel) and i have present it at a view according to some condition. Custom view get present on another view nicely but the button(Login an cancel) not getting any touch event.
Code of custom class and init method:
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
}
#IBAction func cancelButtonAction(sender: AnyObject) {
}
}
This is the block of code from where i have add the custom view as a subview.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if Reachability.isConnectedToNetwork() {
categoryObj = categoryArray .objectAtIndex(indexPath.row) as! TECategoryDetails
if categoryObj.categoryType == "premium" {
let screen = UIScreen.mainScreen().bounds
customView = customAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
else{
watchAllFlag = false
self.performSegueWithIdentifier("Episode", sender: self)
}
}
else {
self.showAlertPopUp()
}
}
You can also do like this way.
import UIKit
class customAlertView: UIView {
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
loginButton.addTarget(self, action: Selector(“loginButtonAction:”), forControlEvents: .TouchUpInside)
cancelButton.addTarget(self, action: Selector(“cancelButtonAction:”), forControlEvents: .TouchUpInside)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "customAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
func loginButtonAction(sender: AnyObject) {
}
func cancelButtonAction(sender: AnyObject) {
}
}
Check it, its working:
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func displayAlertBtnTapped(sender: AnyObject) {
let screen = UIScreen.mainScreen().bounds
let customView = CustomAlertView.init(frame: CGRect(origin: CGPoint(x: 0,y: 80), size: CGSize(width: screen.width, height: screen.height/3)))
self.view .addSubview(customView)
}
}
CustomAlertView.swift:
import UIKit
class CustomAlertView: UIView {
#IBOutlet weak var loginButton : UIButton!
#IBOutlet weak var cancelButton: UIButton!
var view : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = setUpFromXib()
view.frame = frame
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setUpFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CustomAlertView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
translatesAutoresizingMaskIntoConstraints = true
return view
}
#IBAction func loginButtonAction(sender: AnyObject) {
print("Login button clicked");
}
#IBAction func cancelButtonAction(sender: AnyObject) {
print("Cancel button clicked");
}
}
For testing, use the following GitHub link:
https://github.com/k-sathireddy/AlertViewSample
I am trying to create a custom UIView and display it as a pop up in my main View using Swift.
My Custom UIView code is
class DatePopUpView: UIView {
var uiView:UIView?
override init() {
super.init()
self.uiView = NSBundle.mainBundle().loadNibNamed("DatePopUpView", owner: self, options: nil)[0] as? UIView
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
required override init(frame: CGRect) {
super.init(frame: frame)
}
}
And I am Calling it in my main view as:
#IBAction func date_button_pressed (sender : AnyObject?) {
var popUpView = DatePopUpView()
var centre : CGPoint = CGPoint(x: self.view.center.x, y: self.view.center.y)
popUpView.center = centre
popUpView.layer.cornerRadius = 10.0
let trans = CGAffineTransformScale(popUpView.transform, 0.01, 0.01)
popUpView.transform = trans
self.view .addSubview(popUpView)
UIView .animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
popUpView.transform = CGAffineTransformScale(popUpView.transform, 100.0, 100.0)
}, completion: {
(value: Bool) in
})
}
But popUp is not Coming. I used breakpoint and noticed that value is getting assigned to my popUpView but still it is not displayed on my main View. Please Help
Please Note: I am using StoryBoard for my mainView and custom View i have made using xib.
Without additional description on what you are attempting to do, may I suggest something like the code below? Basically, you can use .hidden feature of a view (or any other control) to show/hide the view. You can set the size and positioning of the view to be popped by using the layout editor.
import UIKit
class ViewController: UIViewController {
var popped = false
var popupBtnTitle = "Show Popup"
#IBAction func popupButton(sender: UIButton) {
popped = !popped
anotherView.hidden = !popped
popupBtnTitle = popped ? "Hide Popup" : "Show Popup"
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
}
#IBOutlet weak var popupButtonOutlet: UIButton!
#IBOutlet weak var anotherView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
popped = false
anotherView.hidden = !popped
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}