Add CAGradientLayer to view - ios

I have this custom UIView
import UIKit
class LoginView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupBackground()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupBackground()
}
private func setupBackground() {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [
UIColor(r: 0, g: 17, b: 214).cgColor,
UIColor(r: 0, g: 9, b: 119).cgColor
]
gradientLayer.locations = [0, 1]
gradientLayer.frame = bounds
layer.addSublayer(gradientLayer)
}
}
And this is my UIViewController
import UIKit
class LoginController: UIViewController {
let loginView = LoginView()
override func viewDidLoad() {
super.viewDidLoad()
view = loginView
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
}
The problem is that the GradientLayer doesn't show on the screen, the background is still black.
Thanks for the help!

If you like to use in viewDidLoad (Load once), just declare your custom view inside like following code:
override func viewDidLoad() {
super.viewDidLoad()
let loginView = LoginView(frame: self.view.bounds)
self.view = loginView
}

You need to init LoginView correctly at right time.
class LoginController: UIViewController {
var loginView : LoginView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view = LoginView.init(frame: view.bounds)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
}

Related

Push View Controller From Child View Controller

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

How to test a UILabel on a programatically added UIView with XCTest

I want to test the .text of my dashboardLabel, but i don't know how to access it via XCTest.
The DashboardView.swift looks like this:
import UIKit
class DashBoardView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
createSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
// MARK: - Create Subviews
func createSubviews() {
backgroundColor = .white
var dashboardLabel : UILabel
dashboardLabel = {
let label = UILabel()
label.text = "Dashboard Label"
label.textColor = .black
label.frame = CGRect(x:60, y:80, width: 200, height: 30)
label.backgroundColor = .green
label.backgroundColor = .lightGray
label.font = UIFont(name: "Avenir-Oblique", size: 13)
label.textAlignment = .center
return label
}()
}
The DashboardViewController.swift looks like this:
import UIKit
class DashBoardViewController: UIViewController {
var dashboardview = DashBoardView()
//MARK: View Cycle
override func loadView() {
view = dashboardview
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidLoad() {
super.viewDidLoad()
title = "DashBoard"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I know how to test the Title of the DashboardViewController.swift
import XCTest
#testable import DashBoard
class DashBoardTests: XCTestCase {
func test_if_title_is_DashBoard() {
let vc = DashBoardViewController()
let _ = vc.view
XCTAssertEqual(vc.navigationItem.title, "Dashboard")
}
but i have absolutely no clue, how to access the dashboardLabel on the DashBoardView.swift.
I hope this explains my problem and anyone of you can help me, or point me in the right direction!
Thx ✌️
you can do that using accessibilityIdentifier
Refer : iOS XCUITests access element by accesibility
A fellow Software developer told me a solution which is pretty cool! You need to declare the Label as a property as follows
private(set) var dashboardLabel = UILabel()
and now you are able to access the property within the XCTest. Which makes sense, because you can only test things that are accessible from outside
import UIKit
class DashBoardView : UIView {
private(set) var dashboardLabel = UILabel()
}
XCTestFile
import XCTest
#testable import DashBoard
class DashBoardTests: XCTestCase {
func test_if_dashboard_label_has_title_DashBoard() {
let vc = DashBoardView()
XCTAssertEqual(vc.dashboardLabel.text, "DashBoard")
}
}
Hope that helps!

UIActivityIndicatorView not showing in webview

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

Custom UIView without Storyboard

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.

Swift: UIButton touch event not getting called inside the custom view

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

Resources