Swift: Use of unresolved identifier 'present' - ios

I have a UIView added to UIViewController, and some code of them
ViewController.swift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let listView = ListView()
self.view.addSubview(listView)
}
ListView.swift
class ListView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(btnGO)
}
convenience init() {
self.init(frame: CGRect.zero)
}
required init(coder aDecoder: NSCoder) {
fatalError("This class does not support NSCoding")
}
lazy var btnGO:(UIButton) = {
let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 34))
btn.addTarget(self, action: #selector(btnClicked), for: .touchUpInside)
//some codes
return btn
}()
#objc func btnClicked(sender:UIButton) {
let shareWOW = "some content"
let objectsToShare = [shareWOW]
let activityController = UIActivityViewController(
activityItems: objectsToShare,
applicationActivities: nil)
activityController.popoverPresentationController?.sourceRect = self.frame
activityController.popoverPresentationController?.sourceView = self
activityController.popoverPresentationController?.permittedArrowDirections = .any
present(activityController, animated: true, completion: nil)
}
}
I always get error information Use of unresolved identifier 'present', and I know UIActivityViewController should be placed in UIViewController, and my question is I place the function btnClicked in ViewController.swift, how to call this function in a UIView as ListView.swift? Many thanks

present(_:animated:completion:) method should be used with UIViewController instance. You can't call this method in a UIView subclass. Use delegate to call a method in ViewController from ListView and present UIActivityViewController from the ViewController like this
ViewController.swift
class ViewController: UIViewController, ListViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let listView = ListView()
listView.delegate = self
self.view.addSubview(listView)
}
func btnClicked(sender: UIButton) {
let shareWOW = "some content"
let objectsToShare = [shareWOW]
let activityController = UIActivityViewController(
activityItems: objectsToShare,
applicationActivities: nil)
activityController.popoverPresentationController?.sourceRect = sender.frame
activityController.popoverPresentationController?.sourceView = sender
activityController.popoverPresentationController?.permittedArrowDirections = .any
self.present(activityController, animated: true, completion: nil)
}
}
ListView.swift
protocol ListViewDelegate {
func btnClicked(sender:UIButton)
}
class ListView: UIView {
var delegate: ListViewDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(btnGO)
}
convenience init() {
self.init(frame: CGRect.zero)
}
required init(coder aDecoder: NSCoder) {
fatalError("This class does not support NSCoding")
}
lazy var btnGO:(UIButton) = {
let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 34))
btn.addTarget(self, action: #selector(btnClicked), for: .touchUpInside)
//some codes
return btn
}()
#objc func btnClicked(sender:UIButton) {
delegate?.btnClicked(sender: sender)
}
}

Related

How to make a button work on a custom view from .xib instantiated programmatically

The button works if I add the view via the Interface Builder but it doesn't work when I add the view programmatically.
.xib design:
My custom view class:
class customView: UIView {
static let singleton1 = customView()
#IBOutlet weak var newView: UIView!
#IBAction func changeColor(_ sender: Any) {
newView.backgroundColor = UIColor.systemBlue // this is what the button should do
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
window?.windowLevel = UIWindow.Level(rawValue: CGFloat.greatestFiniteMagnitude)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
window?.windowLevel = UIWindow.Level(rawValue: CGFloat.greatestFiniteMagnitude)
}
func commonInit() {
let viewFromXib = Bundle.main.loadNibNamed("customView", owner: self, options: nil)![0] as! UIView
viewFromXib.bounds = self.bounds
addSubview(viewFromXib)
}
This is the way I instantiate it:
#IBAction func showView(_ sender: Any) {
let playerview = customView.singleton1
view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(playerview)
playerview.tag = 100
UIApplication.shared.keyWindow?.addSubview(playerview)// yes it needs to be in the window
Not sure if my initializer is wrong or something else.
You are trying to load "customView" xib into its own init method. Try below.
Replace commonInit() method with getView(frame:CGRect)->UIView
class customView: UIView {
static let singleton1 = customView()
#IBOutlet weak var newView: UIView!
#IBAction func changeColor(_ sender: Any) {
newView.backgroundColor = UIColor.systemBlue // this is what the button should do
}
override init(frame: CGRect) {
super.init(frame: frame)
window?.windowLevel = UIWindow.Level(rawValue: CGFloat.greatestFiniteMagnitude)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
window?.windowLevel = UIWindow.Level(rawValue: CGFloat.greatestFiniteMagnitude)
}
func getView(frame:CGRect)->UIView{
let viewFromXib = Bundle.main.loadNibNamed("customView", owner: nil, options: nil)![0] as! UIView
viewFromXib.frame = frame
return viewFromXib
}
}
Replace showView() method
#IBAction func showView(_ sender: Any) {
let playerview = customView.singleton1.getView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 200))
self.view.addSubview(playerview)
playerview.tag = 100
UIApplication.shared.keyWindow?.addSubview(playerview)
}

How to create custom class Loading view using Swift

I am implementing loading concept by custom class loading view. I need to use this custom class by using simple self.show() and self.dismiss function. Here, I achieved this concept by using UIActivityController within UIAlertView but I need to do this using custom class.
Below code what I achieved by using UIActivityController within UIAlertView
func loadinHubShow() {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.style = UIActivityIndicatorView.Style.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: true, completion: nil)
}
func loadinHubDismiss() {
dismiss(animated: false, completion: nil)
}
How to change this to custom class loading view. I don’t want to use UIActivityController within UIAlertView, Alternatively need to create same look and feel UI design by UIView.
import Foundation
import UIKit
public class Indicator {
public static let sharedInstance = Indicator()
var blurImg = UIImageView()
var indicator = UIActivityIndicatorView()
private init()
{
blurImg.frame = UIScreen.main.bounds
blurImg.backgroundColor = UIColor.black
blurImg.isUserInteractionEnabled = true
blurImg.alpha = 0.5
indicator.style = .whiteLarge
indicator.center = blurImg.center
indicator.startAnimating()
indicator.color = .red
}
func showIndicator(){
DispatchQueue.main.async( execute: {
UIApplication.shared.keyWindow?.addSubview(self.blurImg)
UIApplication.shared.keyWindow?.addSubview(self.indicator)
})
}
func hideIndicator(){
DispatchQueue.main.async( execute:
{
self.blurImg.removeFromSuperview()
self.indicator.removeFromSuperview()
})
}
}
import UIKit
class Loader: UIView {
var view: UIView!
#IBOutlet fileprivate weak var blurView: UIVisualEffectView!
#IBOutlet fileprivate weak var loader: UIActivityIndicatorView!
var targetView: UIView?
required init(forView view: UIView) {
super.init(frame: view.bounds)
targetView = view
self._setup()
targetView?.addSubview(self)
}
override init(frame: CGRect) {
super.init(frame: frame)
_setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self._setup()
}
private func _setup() {
view = _loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.translatesAutoresizingMaskIntoConstraints = true
addSubview(view)
}
private func _loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView
return nibView
}
func showLoading(withCompletion completion: (() -> Swift.Void)? = nil) {
UIView.animate(withDuration: 0.5, animations: {
}) { _ in
completion?()
}
}
func hideLoading() {
UIView.animate(withDuration: 0.5, animations: {
}) { _ in
self.removeFromSuperview()
}
}
}
You can call below functions in your ViewController
func showLoading() {
if self.view.subviews.map({ $0 is Loader }).contains(true) {
return
}
let loader = Loader(forView: self.view)
loader.showLoading()
}
func hideLoading() {
for view in self.view.subviews {
if let view = view as? Loader {
view.hideLoading()
break
}
}
}
You can customize the below code according to your needs
func showActivityIndicatory(uiView: UIView) {
var container: UIView = UIView()
container.frame = uiView.frame
container.center = uiView.center
container.backgroundColor = UIColorFromHex(0xffffff, alpha: 0.3)
var loadingView: UIView = UIView()
loadingView.frame = CGRectMake(0, 0, 80, 80)
loadingView.center = uiView.center
loadingView.backgroundColor = UIColorFromHex(0x444444, alpha: 0.7)
loadingView.clipsToBounds = true
loadingView.layer.cornerRadius = 10
var actInd: UIActivityIndicatorView = UIActivityIndicatorView()
actInd.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
actInd.activityIndicatorViewStyle =
UIActivityIndicatorViewStyle.WhiteLarge
actInd.center = CGPointMake(loadingView.frame.size.width / 2,
loadingView.frame.size.height / 2);
loadingView.addSubview(actInd)
container.addSubview(loadingView)
uiView.addSubview(container)
actInd.startAnimating()
}

How to add UIButton action in closure in custom UIToolbar class initialization?

I have a custom UIToolbar class with two UIBarButtonItem. I know I can create custom delegate action for UIBarButtonItem item. But how can I use closure as UIBarButtonItem action in custom UIToolbar class initialization?
class KeyboardToolBar: UIToolbar
{
let done = UIButton.init()
init() {
super.init(frame: .zero)
self.backgroundColor = UIColor.gray
self.sizeToFit()
let flexBarBtn = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
done.frame = CGRect(x: 0, y: 0, width: 50, height: 44)
done.setTitle("Done", for: .normal)
done.setTitleColor(.black, for: .normal)
let doneBarBtn:UIBarButtonItem! = UIBarButtonItem.init(customView: done)
self.items = [flexBarBtn,doneBarBtn]
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In ViewController
super.viewDidLoad()
txt.keyboardType = .numberPad
txt.inputAccessoryView = KeyboardToolBar()
// How can I use some thing like this
// txt.inputAccessoryView = KeyboardToolBar(doneBtnAction: {
// print("done button pressed")
// })
}
Here you go ...
class KeyboardToolBar: UIToolbar {
let done = UIButton.init()
var doneBtnAction:((Void) -> Void)?
convenience init(_ doneBtnAction: #escaping (Void) -> Void) {
self.init()
self.doneBtnAction = doneBtnAction
}
private init() {
super.init(frame: .zero)
self.backgroundColor = UIColor.gray
self.sizeToFit()
let flexBarBtn = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
done.frame = CGRect(x: 0, y: 0, width: 50, height: 44)
done.setTitle("Done", for: .normal)
done.setTitleColor(.black, for: .normal)
done.addTarget(self, action: #selector(callbackDoneButton(_:)), for: .touchUpInside)
let doneBarBtn:UIBarButtonItem! = UIBarButtonItem.init(customView: done)
self.items = [flexBarBtn,doneBarBtn]
}
func callbackDoneButton(_ id:Any) -> Void {
if self.doneBtnAction != nil {
self.doneBtnAction!()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In ViewController
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
txt.keyboardType = .numberPad
txt.inputAccessoryView = KeyboardToolBar.init( {
(Void) -> Void in
print("done");
})
}

add tapGestureRecognizer to UIImageView in UIView and call method by protocol

I want to make touch recognized on an UIImageView(orange) in an UIView(blue). And hopefully, handle the touch event in a delegate method, which will be used in other classes. However, I can't make touch recognized with below code. How can I implement to recognize touch only in the ImageView(orange).
code:
import UIKit
protocol CustomViewDelegate {
func imageViewTapped()
}
class CustomView: UIView {
var delegate: CustomViewDelegate?
var imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.blue
self.imageView.backgroundColor = UIColor.orange
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapped))
imageView.addGestureRecognizer(tapGestureRecognizer)
self.addSubview(imageView)
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func tapped() {
print("tapped method called")
delegate?.imageViewTapped()
}
}
class ViewController: UIViewController, CustomViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let view = CustomView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
view.delegate = self
self.view.addSubview(view)
}
func imageViewTapped() {
print("come to view controller")
}
}
UIImageView default userinteraction is false, so enable imageView userinteraction in CustomView init.
imageView.isUserInteractionEnabled = true
Add Different UITapGestureRecognizer to different views and handle as per your requirement . or add tag and access like this
func tapOneAct(sender: UITapGestureRecognizer){
if let tag = sender.view?.tag {
switch tag {
case 1:
println("First View Tapped")
case 2:
println("Second View Tapped")
default:
println("Nothing Tapped")
}
}
}
enable isUserInteractionEnabled property on UIImageView as it defaults to false
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(CustomView.tapped(_:)))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(tapGestureRecognizer)
self.addSubview(imageView)
in tapGesture method
func tapgesture(_ sender: UITapGestureRecognizer){
if sender.state == .ended {
let touchLocation: CGPoint = sender.location(in: sender.view?.superview)
if imageView.frame.contains(touchLocation) {
print("tapped method called")
delegate?.imageViewTapped()
}
}
}

Snapkit seems to be blocking all the GestureRecognizers on subviews

I've created a custom UIView which has a UITapGestureRecognizer added to it in it's own init:
class BoxView: UIView, UIGestureRecognizerDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
self.construct()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.construct()
}
convenience init() {
self.init(frame: CGRect.zero)
}
func construct() {
self.backgroundColor = UIColor.whiteColor()
self.frame.size = CGSize(width: 125, height: 125)
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
tapGesture.delegate = self
self.addGestureRecognizer(tapGesture)
}
func handleTap(sender: UITapGestureRecognizer? = nil) {
print("handleTap called!")
}
}
I'm using it in a ViewController, like this:
import Foundation
import UIKit
import AVFoundation
class StartViewController: UIViewController {
private var boxView: BoxView = BoxView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blackColor()
self.view.addSubview(self.boxView)
/* block: XXX
self.boxView.snp_makeConstraints { (make) -> Void in
make.center.equalTo(self.view)
}
*/
}
}
The gestures don't seem to work as soon as I uncomment the block marked "XXX" in the ViewController which adds the SnapKit constraints. Can someone help me understand what's going on here? Am I using the gesture recognizer correctly?
Looks like I missed an important constraint, adding a "size" constraint on the custom view (BoxView) fixed it.
func construct() {
self.backgroundColor = UIColor.whiteColor()
self.frame.size = CGSize(width: 125, height: 125)
self.snp_makeConstraints { (make) -> Void in
make.size.equalTo(self.frame.size)
}
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
tapGesture.delegate = self
self.addGestureRecognizer(tapGesture)
}

Resources