Nesting Fields within Views - ios

First and foremost, I am not using Apple's storyboard. I want the freedom to create applications without the constraints that are applied using their out-of-the-box features. Is there a way to nest objects within one another. For example, two UITextFields found within a UIView. This is programmatically and not on the scene it self. I know you can two text fields found within the UIView on the actual scene itself.
Here is an example of what I'm talking about.
let credentials: UIView = {
let credential = UIView()
let CredUserName: UITextField = {
let username = UITextField()
username.placeholder = "Username"
return username
}()
let CredPassword: UITextField = {
let password = UITextField()
password.placeholder = "Password"
return password
}()
return credential
} ()
If it's not possible then I will separate them.
Thanks!

Try to use UIView.addSubView()
let credentials: UIView = {
let credential = UIView()
let CredUserName: UITextField = {
let username = UITextField()
username.placeholder = "Username"
return username
}()
let CredPassword: UITextField = {
let password = UITextField()
password.placeholder = "Password"
return password
}()
credential.addSubView(CredUserName)
credential.addSubView(CredPassword)
return credential
} ()

Related

Microblink: reading an image

I'm asking the Microblink care reader to look at a photo of a card, rather than using the camera:
lazy var blinkCardRecognizer: MBCBlinkCardRecognizer = {
return MBCBlinkCardRecognizer()
}()
lazy var recognizerCollection: MBCRecognizerCollection = {
blinkCardRecognizer.extractCvv = false
blinkCardRecognizer.extractIban = false
blinkCardRecognizer.extractExpiryDate = false
let recognizerList = [blinkCardRecognizer]
return MBCRecognizerCollection(recognizers: recognizerList)
}()
My class has declared these two delegates:
MBCBlinkCardOverlayViewControllerDelegate, MBCScanningRecognizerRunnerDelegate
I'm sure that I'm passing this function a correct UIImage, and I do get to the processImage call:
func prepareToReadImage(_ theImage: UIImage?) {
let recognizerRunner: MBCRecognizerRunner = MBCRecognizerRunner(recognizerCollection: recognizerCollection)
recognizerRunner.scanningRecognizerRunnerDelegate = self
var image: MBCImage? = nil
if let anImage = theImage {
image = MBCImage(uiImage: anImage)
}
image?.cameraFrame = true
image?.orientation = MBCProcessingOrientation.left
let _serialQueue = DispatchQueue(label: "com.microblink.DirectAPI-sample-swift")
_serialQueue.async(execute: {() -> Void in
recognizerRunner.processImage(image!)
})
}
But this callback is not being hit:
func recognizerRunner(_ recognizerRunner: MBCRecognizerRunner, didFinishScanningWith state: MBCRecognizerResultState) {
if state == .valid {
print (state)
}
}
Can you see why it isn't? Does it matter that I see the log warning You are using time-limited license key!?
From the presented code, I can see that the recognizerRunner and the prepareToReadImage methods have been entered correctly.
However, in the first block of code, where you're defining the recognizer and the recognizerCollection, I can see that the issue could be with the MBCRecognizerCollection since its parameter, recognizers, is of type [MBCRecognizer], and you're placing there [MBCBlinkCardRecognizer]. I can suggest this solution to see if it works:
blinkCardRecognizer = MBCBlinkCardRecognizer()
var recognizerList = [MBCRecognizer]()
let recognizerCollection: MBCRecognizerCollection = {
blinkCardRecognizer.extractCvv = false
blinkCardRecognizer.extractIban = false
blinkCardRecognizer.extractExpiryDate = false
recognizerList.append(blinkCardRecognizer!)
return MBCRecognizerCollection(recognizers: recognizerList)
}()
recognizerRunner = MBCRecognizerRunner(recognizerCollection: recognizerCollection)
The only difference is that I've previously defined the BlinkCardRecognizer and the RecognizerRunner, so that should not make any difference:
private var recognizerRunner: MBCRecognizerRunner?
private var blinkCardRecognizer: MBCBlinkCardRecognizer?
Just to add here, it does not matter if you see the You are using time-limited license key!, it is simply an indicator that you using a time-limited key and it should not affect the scanning process.

MDCTextInputController error messages cover entered text

Using material-components/material-components-ios v85.8.0
import MaterialComponents
....
var usernameTextField = MDCTextField()
var userNameTextLayout = MDCTextInputControllerUnderline()
usernameTextField = {
let usernameTextEdit = MDCTextField()
usernameTextEdit.translatesAutoresizingMaskIntoConstraints = false
usernameTextEdit.clearButtonMode = .unlessEditing
usernameTextEdit.backgroundColor = .white
return usernameTextEdit
}()
userNameTextLayout.textInput = usernameTextField
userNameTextLayout.placeholderText = "Username"
// add to view
....
private func isUserNameValid() -> Bool {
let enteredUsername = usernameTextField.text ?? ""
if (!enteredUsername.isValidEmail) {
userNameTextLayout.setErrorText("Invalid e-mail address",
errorAccessibilityValue: nil)
return false
}
}
Error messages cover the text entered and it looks bad:
Android material design does however place the error underneath the line:
Was wondering if there's a way to do that, or if I'm doing it wrong.
I followed their tutorial: https://codelabs.developers.google.com/codelabs/mdc-101-swift/#2
I had set the height of the MDCTextField too small. In increasing it from 50->80pts it did the trick and moved the error message below the line.

How to add a parameter to UITapGestureRecognizer so that the action function can access that parameter

I have created UIViews programmatically based on the number of items i stored in my UserDefaults and each UIView represents an item from the userDefaults and have added UITapGestureRecognizer on top of it. Now this UIViews when clicked will send my user to a new view controller, now my problem is how do I pass a parameter which will hold a value so that the new view controller can determine which view was clicked. Below is my code
//Retrieving my userDefaults values
let items = preferences.object(forKey: selectedOffer)
//How i loop and create my UIViews
if let array = items as! NSArray?{
totalOffers = array.count
let castTotalOffers = CGFloat(totalOffers)
var topAnchorConstraint: CGFloat = 170
var cardHeight: CGFloat = 145
for obj in array {
if let dict = obj as? NSDictionary{
offerName = dict.value(forKey: "NAME") as! String
let offerPrice = dict.value(forKey: "PRICE") as! String
let offerDescription = dict.value(forKey: "DESCRIPTION") as! String
//creating the uiview
let offerView = UIView()
self.scrollView.addSubview(offerView)
offerView.translatesAutoresizingMaskIntoConstraints = false
offerView.topAnchor.constraint(equalTo: self.appBackImage.bottomAnchor, constant: topAnchorConstraint).isActive = true
offerView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20.0).isActive = true
offerView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -20.0).isActive = true
offerView.backgroundColor = UIColor.white
offerView.heightAnchor.constraint(equalToConstant: 130).isActive = true
//transforming to cards
offerView.layer.cornerRadius = 2
offerView.layer.shadowOffset = CGSize(width: 0, height: 5)
offerView.layer.shadowColor = UIColor.black.cgColor
offerView.layer.shadowOpacity = 0.1
self.scrollView.contentSize.height = CGFloat(totalOffers) + topAnchorConstraint + 70
//Adding gesture
let touchRec = UITapGestureRecognizer(target: self, action: #selector(goToBuyBundle(offerClicked:offerName)))
offerView.addGestureRecognizer(touchRec)
}
}
}
//Function to go to buy offer
#objc func goToBuyBundle(_sender: UITapGestureRecognizer, offerClicked:String){
guard let moveTo = storyboard?.instantiateViewController(withIdentifier: "BuyOfferViewController") as? BuyOfferViewController else {return}
moveTo.selectedOffer = offerClicked
self.addChildViewController(moveTo)
moveTo.view.frame = self.view.frame
self.view.addSubview(moveTo.view)
moveTo.didMove(toParentViewController: self)
}
Just want a way when i navigate to the next view controller i can retrieve which UIView was clicked by using the offerName.
Thanks in Advance
Make your custom View and store the parameter that you want to pass through the Gesture Recognizer inside the view.
class GestureView: UIView{
var myViewValue: String? // Or whichever type of value you want to store and send via the gesture
}
When you initiate your view, add the value as per your requirement:
let panReceptor = GestureView()
panReceptor.myViewValue = "Hello World"
Add a simple TapGesture on this custom view and you may pass the value as below:
let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(viewTapped(sender:)))
panReceptor.addGestureRecognizer(tapGesture)
#objc func viewTapped(sender: UITapGestureRecognizer){
guard let unwrappedView = sender.view as? GestureView else { return }
print("Gesture View value : \(unwrappedView.myViewValue)")
}
In the above example I have in effect passed a String parameter through the sender.view.
You may pass any type in this manner and use the value as per your requirement in the selector method.
You could add custom variable to UITapGestureRecognizer something like:
import UIKit
private var assocKey : UInt8 = 0
extension UITapGestureRecognizer {
public var offerName:String{
get{
return objc_getAssociatedObject(self, &assocKey) as! String
}
set(newValue){
objc_setAssociatedObject(self, &assocKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
}
And then use it like:
...
let touchRec = UITapGestureRecognizer(target: self, action: #selector(goToBuyBundle(offerClicked:offerName)))
touchRec.offerName = offerName
offerView.addGestureRecognizer(touchRec)
...
#objc func goToBuyBundle(_sender: UITapGestureRecognizer, offerClicked:String){
guard let moveTo = storyboard?.instantiateViewController(withIdentifier: "BuyOfferViewController") as? BuyOfferViewController else {return}
moveTo.selectedOffer = sender.offerName
...
}

textLabel.text in UIViewController comes up nil while assigning string from NSObject

I'm an iOS and programming noob so I apologize for any bad phrasing or mistakes.
I'm parsing quotes from an API for my app which displays it on a textLabel each time a UIButton is clicked. In order to keep the string from going off the textLabel or be resized to an unreadable font, I'm trying to request a new quote if the string character count is too high by calling a function in my NSObject. I set up a NSObject to do the refetching but whenever I try to reassign the the string to the textLabel.text from the NSObject or try to send the string back to the ViewController the qouteLabel.text comes back nil
Here is my viewcontroller where I'm making the initial request for the quote
import UIKit
import Alamofire
class RSQuotesViewController: RSViewController {
var ronImageView: UIImageView!
var quoteLabel = UILabel!()
override func loadView() {
let frame = UIScreen.mainScreen().bounds
let view = UIView(frame: frame)
view.backgroundColor = UIColor.grayColor()
ronImageView = UIImageView(frame: CGRectMake(frame.width/2-160, frame.height-600, 320, 600))
let ron = "ron.png"
let ronImage = UIImage(named: ron)
ronImageView.image = ronImage
view.addSubview(ronImageView);
let labelWidth = ronImageView.frame.width/2
let quoteLabelX = labelWidth-40
quoteLabel = UILabel(frame: CGRect(x: quoteLabelX, y: ronImageView.frame.height/4+15, width: labelWidth, height: 160))
quoteLabel.textAlignment = .Center
quoteLabel.text = "Click to Start"
quoteLabel.shadowColor = UIColor.grayColor()
quoteLabel.adjustsFontSizeToFitWidth = true
quoteLabel.lineBreakMode = .ByWordWrapping // or NSLineBreakMode.ByWordWrapping
quoteLabel.numberOfLines = 0
view.addSubview(quoteLabel)
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
let frame = UIScreen.mainScreen().bounds
let getQuote = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width+50, height: frame.size.height))
getQuote.backgroundColor = UIColor.clearColor()
getQuote.setTitle("", forState: UIControlState.Normal)
getQuote.addTarget(self, action: #selector(RSQuotesViewController.getQuote(_:)), forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(getQuote)
}
// Gets quote when button is pressed
func getQuote(sender: UIButton){
let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
if let JSON = response.result.value as? Array<String>{
let quoteDict = RSQoute()
// if quote is too large get another one
if (JSON[0].characters.count > 120){
print("greater than 120")
quoteDict.fetchQuote()
} else {
self.quoteLabel.text = JSON[0]
}
}
}
}
This is my model where I'm trying to reassign the quoteLabel.text and getting nil
import UIKit
import Alamofire
class RSQoute: NSObject {
var newQuote = String()
// fetchs new quote if quote is too large
func fetchQuote(){
let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
if let JSON = response.result.value as? Array<String>{
self.newQuote = JSON[0]
if (self.newQuote.characters.count > 120) {
print("Try Again: ---->\(self.newQuote)")
return self.fetchQuote()
} else {
let quoteVC = RSQuotesViewController()
print("Retry was less than 120: ---->\(self.newQuote)")
print("quoteLabelText: ---->\(RSQuotesViewController().quoteLabel.text)")// comes back nil
RSQuotesViewController().quoteLabel.text = self.newQuote
}
}
}
}
}
Please let me know if there something I'm missing or an easier/better way of trying to fetch a new quote from the API :)
In your function fetchQuote(), you set quoteVC as a new instantiation of RSQuotesViewController() with let quoteVC = RSQuotesViewController(). Instead you should be setting the quoteLabel.text for the applications instance of RSQuotesViewController(). You are also making two API requests. Once inside the fetchQuote() function for RSQuotesViewController and once inside your fetchQuote() function for RSQuotes
I think what you are looking for would involve closures. Try this out for your fetchQuote() function in your RSQuotes class
func fetchQuote(completion: (result:String)){
let url = "http://ron-swanson-quotes.herokuapp.com/v2/quotes"
Alamofire.request(.GET, url, parameters: nil).responseJSON { response in
if let JSON = response.result.value as? Array<String>{
self.newQuote = JSON[0]
if (self.newQuote.characters.count > 120) {
print("Try Again: ---->\(self.newQuote)")
completion(result: self.newQuote)
} else {
print("Retry was less than 120: ---->\(self.newQuote)")
print("quoteLabelText: ---->\(RSQuotesViewController().quoteLabel.text)")// comes back nil
completion(result: self.newQuote)
}
}
Then, I would have a setQuote function RSQuotesViewController where you could just do something like this
func setQuote() {
let quoteObj = RSQuote()
quoteObj.fetchQuote() {
result in
quoteLabel.text = result
}
}
I would take a look at some posts related to swift closures and also check out. http://goshdarnclosuresyntax.com/
On a side note, I'm not sure if you were planning to manipulate the quoteString within your RSQuote class. If not, it might be better for fetchQuote() to be a static func. This way you can just call it without initializing the object in RSQuoteViewController. It'd be something like RSQuote.fetchQuote()

how to pass data to buttons through an array in swift

I am trying to fetch data from the database to a slide menu. I am using the following code for fetching the data and need to connect to buttons in the buttons present in the UI.
func fetchiingcontact()
{
var allusers:NSMutableArray = NSMutableArray()
allusers = ModelManager.getInstance().getAlldrawerData()//Fetching contacts objects from Sqlite
for var i = 0 ; i < allusers.count ; i++
{
var userobject : user = user()
userobject = allusers.objectAtIndex(i) as! user
let contactobjectuser:UserContactsClass = UserContactsClass()
let userdefault = NSUserDefaults.standardUserDefaults()
let ownuserid = userdefault.integerForKey("Userid")
if(userobject.userid == ownuserid)
{
}
else
{
contactobjectuser.firstName = userobject.firstName
contactobjectuser.lastName = userobject.lastName
contactobjectuser.profilePic = userobject.profilePic
contactobjectuser.nickName = userobject.nickName
usercontactslistarray.addObject(contactobjectuser)
self.secondLabel.text = contactobjectuser.lastName
self.userFlname.text = contactobjectuser.firstName
}
}
how do i connect the usercontactslistarray to the ui buttons by code as self.secondlabel.text is not working
You can use
self. userFlname.setText(contactobjectuser.lastName)
self.secondLabel.setText(contactobjectuser.lastName)
let string = "Your Text"
yourButton.setTitle(string as String, forState: UIControlState.Normal)

Resources