PSTCKPaymentCardTextField not displaying on view - ios

Trying to integrate Paystack with my app. Using PSTCKPaymentCardTextField as described in the guide, but it just doesn't display anything on my view when I run the app.
import UIKit
import Paystack
class PaymentViewController: UIViewController, PSTCKPaymentCardTextFieldDelegate {
let paymentTextField: PSTCKPaymentCardTextField = {
let ptf = PSTCKPaymentCardTextField()
return ptf
}()
func setupPaymentTextField() {
let paymentFormWidth = self.view.frame.width - 30
paymentTextField.frame = CGRect(x: 15, y: 15, width: paymentFormWidth, height: 44)
paymentTextField.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(paymentTextField)
setupPaymentTextField()
}
}
Am i doing something wrong? Please help me out.
Thanks
Note: I am new to swift language

Issue solved!. Used auto-layout instead of using paymentTextField.frame = CGRect(x: 15, y: 15, width: paymentFormWidth, height: 44)
func setupPaymentTextField() {
paymentTextField.delegate = self
paymentTextField.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
paymentTextField.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
paymentTextField.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -30).isActive = true
paymentTextField.heightAnchor.constraint(equalToConstant: 45).isActive = true
}

Related

Xcode ViewController shows Cannot find 'pay' in scope

I am trying to link my iOS app to stripe, but in my viewcontroller it shows error - "Cannot find 'pay' in scope"
Attaching the screenshot of the error -
My ViewController is -
import UIKit
import Stripe
import Alamofire
class ViewController: UIViewController {
// Mark UIViews
var productStackView = UIStackView()
var paymentStackView = UIStackView()
var paymentTextField = STPPaymentCardTextField()
var productImageView = UIImageView()
var productLabel = UILabel()
var payButton = UIButton()
var loadingSpinner = UIActivityIndicatorView()
var outputTextView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
self.setupUI()
}
func setupUI() {
setupProductImage()
setupProductLabel()
setupLoadingSpinner()
setupPaymentTextFiled()
setupPayButton()
setupOutputTextView()
self.productStackView.frame = CGRect(x: 0, y: 70, width: 330, height: 150)
self.productStackView.center.x = self.view.center.x
self.productStackView.alignment = .center
self.productStackView.axis = .vertical
self.productStackView.distribution = .equalSpacing
self.productStackView.addArrangedSubview(self.productImageView)
self.productStackView.setCustomSpacing(10, after: self.productImageView)
self.productStackView.addArrangedSubview(self.productLabel)
self.view.addSubview(self.productStackView)
self.paymentStackView.frame = CGRect(x:0, y: 250, width: 300, height: 100)
self.paymentStackView.center.x = self.view.center.x
self.paymentStackView.alignment = .fill
self.paymentStackView.axis = .vertical
self.paymentStackView.distribution = .equalSpacing
self.paymentStackView.addArrangedSubview(self.paymentTextField)
self.paymentStackView.addArrangedSubview(self.payButton)
self.view.addSubview(self.paymentStackView)
}
func setupProductImage(){
self.productImageView = UIImageView(frame: CGRect(x: 50, y: 50, width: 275, height: 200))
self.productImageView.image = UIImage(named: "stripe press")
self.productImageView.contentMode = .scaleAspectFit
}
func setupProductLabel() {
self.productLabel.frame = CGRect(x: 0, y: 420, width: self.view.frame.width, height: 50)
}
func setupOutputTextView() {
self.outputTextView.frame = CGRect(x: 0, y: 420, width: self.view.frame.width - 50, height: 100)
self.outputTextView.center.x = self.view.center.x
self.outputTextView.textAlignment = .left
self.outputTextView.font = UIFont.systemFont(ofSize: 18)
self.outputTextView.text = ""
self.outputTextView.layer.borderColor = UIColor.purple.cgColor
self.outputTextView.isEditable = false
self.view.addSubview(self.outputTextView)
}
func setupPaymentTextFiled() {
self.paymentTextField.frame = CGRect(x: 0, y: 0, width: 330, height: 660)
}
func setupPayButton() {
self.payButton.frame = CGRect(x: 60, y: 480, width: 150, height: 40)
self.payButton.setTitle("Submit Payment", for: .normal)
self.payButton.setTitleColor(UIColor.white, for: .normal)
self.payButton.layer.cornerRadius = 5.0
self.payButton.backgroundColor = UIColor.init(red:50/255,green: 50/255,blue: 93/255, alpha:1.0)
self.payButton.layer.borderWidth = 1.0
self.payButton.addTarget(self, action: #selector(pay), for: .touchUpInside)
}***/* ERROR -Cannot find 'pay' in scope */***
func setupLoadingSpinner() {
self.loadingSpinner.color = UIColor.darkGray
self.loadingSpinner.frame = CGRect(x: 0, y: 300, width: 25, height: 25)
self.loadingSpinner.center.x = self.view.center.x
self.view.addSubview(self.loadingSpinner)
}
func startLoading() {
DispatchQueue.main.async {
self.loadingSpinner.startAnimating()
self.loadingSpinner.isHidden = false
}
}
func stopLoading() {
DispatchQueue.main.async {
self.loadingSpinner.stopAnimating()
self.loadingSpinner.isHidden = true
}
}
func diplayStatus (_ message:String) {
DispatchQueue.main.async {
self.outputTextView.text += message + " \n"
self.outputTextView.scrollRangeToVisible(NSMakeRange(self.outputTextView.text.count - 1, 1))
}
}
}
I have boldened the error in the above code.
As mentioned i have also attached the sreenshot.
I tried everything but could not figure a way round it. How to sort-it-out ?
The selector should be an Objc function that you want to run when the user taps the pay button.
#objc func pay() {
//Your pay code goes in here
}
Yes, you guys were right, I added " #objc func pay() {}" as follows ane everything worked fine:-
.......func diplayStatus (_ message:String) {
DispatchQueue.main.async {
self.outputTextView.text += message + " \n"
self.outputTextView.scrollRangeToVisible(NSMakeRange(self.outputTextView.text.count - 1, 1))
}
}
#objc func pay() {} //here
}

How to create Onboarding\Walkthrough swift

I'm trying to create a welcome onboarding for the first time users but none of the views are loafing in the simulator, all I'm getting is a red background when the onboardingVC gets presented. Can anyone see the issue as to why the titles, buttons, and images won't appear?
This is the message I'm getting in the console:
Warning: Attempt to present <EMA.WalkthroughVC: 0x7faa2401e5b0> on <EMA.HomeVC: 0x7faa22407e00> whose view is not in the window hierarchy!
FOUND ALL!!
let holderView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = true
view.backgroundColor = .darkGray
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.backgroundColor = UIColor.red
configure()
}
private func configure() {
let scrollView = UIScrollView(frame: holderView.bounds)
holderView.addSubview(scrollView)
let titles = ["Hi","Welcome","real nigga"]
for x in 0..<3 {
let pageView = UIView(frame: CGRect(x: CGFloat(x) * holderView.frame.size.width, y: 0, width: holderView.frame.size.width, height: holderView.frame.size.height))
scrollView.addSubview(pageView)
let label = UILabel(frame: CGRect(x: 10, y: 10, width: pageView.frame.size.width-20, height: 120))
let imageView = UIImageView(frame: CGRect(x: 10, y: 10+120+10, width: pageView.frame.size.width-20, height: pageView.frame.size.height - 60 - 130 - 15))
let button = UIButton(frame: CGRect(x: 10, y: pageView.frame.size.height - 60, width: pageView.frame.size.width-20, height: 50))
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
pageView.addSubview(label)
label.text = titles[x]
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "BankCard\(x)")
pageView.addSubview(imageView)
button.setTitleColor(.red, for: .normal)
button.backgroundColor = .black
button.setTitle("Continue", for: .normal)
if x == 2 {
button.setTitle("Get Started", for: .normal)
}
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
pageView.addSubview(button)
}
}
#objc func didTapButton(_ button: UIButton) {
}
}
"whose view is not in the window hierarchy"
you didn't add the views that you created to the main view try to add the subviews to the main by using this one
self.view.addSubview(holderView)
also don't forget to add the frame for the holder view like that
UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
view.translatesAutoresizingMaskIntoConstraints = true
and inside the view did load
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
self.view.addSubview(holderView)
}

How to set the frame of a ViewController without storyboard

I want to create a view (e.g. 100x100) with ViewController without using the storyboard. I am wondering what the best way to declare the frame of the ViewController is.
I tried:
class MyLittleViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}
}
And I tried to see this view on my MainViewController:
override func viewDidLoad() {
super.viewDidLoad()
let myLittleView = MyLittleViewController()
myLittleView.willMove(toParent: self)
myLittleView.view.translatesAutoresizingMaskIntoConstraints = false
myLittleView.view.backgroundColor = .red
view.addSubview(myLittleView.view)
// enable auto-sizing (for example, if the device is rotated)
myLittleView.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addChild(myLittleView)
myLittleView.didMove(toParent: self)
myLittleView.view.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myLittleView.view.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
It doesn't work like I expected because the little view doesn't appear on the main view. Any hints?
You shouldn't mix frame layout with auto-layout set a width & height constraints also
NSLayoutConstraint.activate([
myLittleView.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
myLittleView.view.centerYAnchor.constraint(equalTo: view.centerYAnchor),
myLittleView.view.heightAnchor.constraint(equalToConstant:100),
myLittleView.view.widthAnchor.constraint(equalToConstant:100)
])
OR
myLittleView.view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myLittleView.view.center = view.center
OR
override func loadView() {
view = UIView()
view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}
Edit:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .green
let myLittleView = MyLittleViewController()
myLittleView.willMove(toParent: self)
myLittleView.view.backgroundColor = .red
view.addSubview(myLittleView.view)
// enable auto-sizing (for example, if the device is rotated)
myLittleView.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addChild(myLittleView)
myLittleView.didMove(toParent: self)
myLittleView.view.center = view.center
}
}
class MyLittleViewController: UIViewController {
override func loadView() {
view = UIView()
view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}
}
Another way to set frame of the view controller is override method loadView() and set the view frame like this
func loadView() {
view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}

How can I create reusable view controllers inside of UIScrollView?

I am trying to create a full page sized horizontally scrolling UIScrollView. On each page I am adding instances of the same UIViewController class. I would like to create some kind of reusable functionality to conserve both memory and processor use needed. Below is a basic implementation I have created with some toying around with how reusability might work although Im not quite sure. Thank you for any help you can offer.
Current UIScroll ViewController Model
let scrollView:UIScrollView = {
let scrollView = UIScrollView(frame: CGRect.zero)
scrollView.isPagingEnabled = true
scrollView.backgroundColor = UIColor.gray
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = true
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
scrollView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: self.view.bounds.size)
self.view.addSubview(scrollView)
scrollView.delegate = self
scrollView.contentSize = CGSize(width: 3 * self.view.frame.width, height: self.view.frame.height)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0),
scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0)
])
let viewController1 = UIViewController()
viewController1.view.backgroundColor = UIColor.red
let viewController2 = UIViewController()
viewController2.view.backgroundColor = UIColor.blue
let viewController3 = UIViewController()
viewController3.view.backgroundColor = UIColor.green
self.addChild(viewController1)
viewController1.view.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: self.view.bounds.size)
scrollView.addSubview(viewController1.view)
addViewControllerContraints(viewController: viewController1, index: 0)
viewController1.didMove(toParent: self)
self.addChild(viewController2)
viewController2.view.frame = CGRect(origin: CGPoint(x: self.view.bounds.width, y: 0), size: self.view.bounds.size)
scrollView.addSubview(viewController2.view)
addViewControllerContraints(viewController: viewController2, index: 1)
viewController2.didMove(toParent: self)
self.addChild(viewController3)
viewController3.view.frame = CGRect(origin: CGPoint(x: 2 * self.view.bounds.width, y: 0), size: self.view.bounds.size)
scrollView.addSubview(viewController3.view)
addViewControllerContraints(viewController: viewController3, index: 2)
viewController3.didMove(toParent: self)
}
func addViewControllerContraints( viewController: UIViewController, index:Int){
guard let view = viewController.view else{
print("View found nil")
return
}
view.translatesAutoresizingMaskIntoConstraints = false
let offset:CGFloat = UIScreen.main.bounds.width * CGFloat(index)
print("Offset: \(offset)")
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0),
view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: offset),
view.heightAnchor.constraint(equalToConstant: self.view.bounds.height),
view.widthAnchor.constraint(equalToConstant: self.view.bounds.width)
])
}
Is there a good way to create some type of reuse functionality this is something I was playing around with based on This Answer although I realize that is primarily for UIPageViewControllers where allocation and deallocation of UIViewController's is handled for you.
Possible Reuse Functionality
var reuseableViewControllers:[UIViewController] = [UIViewController]()
private func unusedViewController() -> UIViewController {
let unusedViewControllers = reuseableViewControllers.filter { $0.parent == nil }
if let someUnusedViewController = unusedViewControllers.first {
return someUnusedViewController
} else {
let newViewController = UIViewController()
reuseableViewControllers.append(newViewController)
return newViewController
}
}

Fill gradually a shape using swift and UIViewAnimation?

I have an iOS 10 app that contains a button ("Press Me!"), and a UIView containing a blue outlined rectangle, with no fill. I want to fill the rectangle gradually (in like 5 seconds) with red, using any possible method (I tried using UIView.animation(withDuration:, animations:)). I will include the code below:
Here's the viewController:
class ViewController: UIViewController {
#IBOutlet weak var tronkyy: tronc!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func didPress(_ sender: UIButton) {
tronkyy.full = true
tronkyy.setNeedsDisplay()
} }
And the view:
#IBDesignable class tronc: UIView {
//var value = 0.0
var full = false
override func draw(_ rect: CGRect) {
UIColor.blue.setStroke()
boxPath().stroke()
drawDynamic()
}
private func boxPath() -> UIBezierPath {
let path = UIBezierPath(rect: CGRect(x: 0.1 * frame.width, y: 0.1 * frame.height, width: 0.8 * frame.width, height: 0.8 * frame.height))
UIColor.blue.setStroke()
return path
}
func drawDynamic() {
if full {
UIView.animate(withDuration: 10) { _ in
//while self.value < 1 {
let path = UIBezierPath(rect: CGRect(x: 0.1 * self.frame.width, y: 0.1 * self.frame.height, width: (0.8 * self.frame.width), height: 0.8 * self.frame.height)) //* CGFloat(value)))
UIColor.red.setFill()
path.fill()
//self.value += 0.1
//}
}
full = false
}
} }
Ah, and yes, please ignore that the red view cover the rectangle.
The problem is that there is no gradual filling. it just fills it once and for all.
Edit: I commented out the "value" property and the while loop, as suggested in the answers, but it still doesn't work.
This is an approach using a view with a subview. For a more complex shape than a rectangle, it could be done with masks.
You can run this directly in a Playground page:
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let btn: UIButton = {
let b = UIButton()
b.setTitle("Tap Me", for: .normal)
b.backgroundColor = .blue
b.frame = CGRect(x: 20, y: 20, width: 200, height: 30)
return b
}()
let blueRect: UIView = {
let v = UIView()
v.layer.borderColor = UIColor.blue.cgColor
v.layer.borderWidth = 2.0
v.backgroundColor = .clear
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let redRect: UIView = {
let v = UIView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
var redRectHeightConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(btn)
btn.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
blueRect.addSubview(redRect)
self.view.addSubview(blueRect)
redRect.leftAnchor.constraint(equalTo: blueRect.leftAnchor, constant: 0.0).isActive = true
redRect.rightAnchor.constraint(equalTo: blueRect.rightAnchor, constant: 0.0).isActive = true
redRect.bottomAnchor.constraint(equalTo: blueRect.bottomAnchor, constant: 0.0).isActive = true
redRectHeightConstraint = NSLayoutConstraint(item: redRect,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1.0,
constant: 0.0)
redRect.addConstraint(redRectHeightConstraint!)
blueRect.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.5).isActive = true
blueRect.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.5).isActive = true
blueRect.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
blueRect.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
}
func didTap(_ sender: Any?) -> Void {
UIView.animate(withDuration: 5.0, animations: {
_ in
self.redRectHeightConstraint!.constant = self.blueRect.frame.size.height
self.view.setNeedsLayout()
}, completion: {
finished in
})
}
}
let vc = TestViewController()
vc.view.backgroundColor = .yellow
vc.view.frame = CGRect(x: 0, y: 0, width: 600, height: 600)
PlaygroundPage.current.liveView = vc
Note: this is just sample, demonstration code... not meant to be a copy/paste solution.
You should not use a while loop in an animation function. Try this version
UIView.animate(withDuration: 10) { _ in
let path = UIBezierPath(rect: CGRect(x: 0.1 * self.frame.width, y: 0.1 * self.frame.height, width: (0.8 * self.frame.width), height: 0.8 * self.frame.height))
UIColor.red.setFill()
path.fill()
}

Resources