I'm making a text-based iOS game which uses a single view consisting of a UITextView (scrollable, not editable) and a UITextField. I've made it so when I press return while editing the textField, the keyboard closes and the text of the textField is added to the textView. However, the text of the UITextView doesn't appear at all. The background color still appears, but nothing else, no matter how I try to display it. I've already tried setting the font size and color.
Here's code from the ViewController that handles both UI components.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
// outlets / actions
#IBOutlet weak var outputView: UITextView!
#IBOutlet weak var inputField: UITextField!
var uni: Universe? // a custom class that contains the game's data
override func viewDidLoad() {
//outputView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.New, context: nil)
inputField.delegate = self
outputView.delegate = self
inputField.text = "press return for help"
outputView.text = ""
outputView.textColor = UIColor.greenColor()
outputView.frame = self.view.frame
// The next 3 lines make a new Universe object.
uni = Assembler.build(outputView)
uni!.setUni()
uni!.setParser()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
uni!.player.viewLocation()
}
// delegate method; this should do 3 things:
// 1. remove the keyboard
// 2. call uni.parser.read(text)
// 3. remove the text in the field
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
outputView.text! += textField.text! + "\n"
uni!.parser!.read(textField.text!) // This function interprets the text from textField and prints something appropriate in the textView.
textField.text = ""
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// The rest of the code makes the whole frame shift up/down when the keyboard appears/disappears to keep the UITextField visible.
}
Any help at all would be greatly appreciated. The similar questions on this site haven't given me anything to go on.
Related
when launching the iOS share extension the textView will by default already be selected / entered. (the keyboard will be visible and the textView will be in edit mode)
I don't want this to happen, how do I programatically exit the textView
override func viewDidLoad() {
self.textView.exit() // obviously doesn't work
}
I see tons of posts about how to exit when user press enter on the keyboard, I do not want to do it "when something delegate" I just want the textview to not be in edit mode when the extension is launched (on viewDidLoad).
I have also tried (as suggested in other post)
self.textView.endEditing(true)
which did not hide the keyboard or exit the textView
You can call textView.resignFirstResponder() in presentationAnimationDidFinish
class ShareViewController: SLComposeServiceViewController {
var textViewTintColor: UIColor?
override func viewDidLoad() {
super.viewDidLoad()
// hide cursor which appears during presentation animation
self.textViewTintColor = self.textView.tintColor
self.textView.tintColor = .clear
}
override func presentationAnimationDidFinish() {
super.presentationAnimationDidFinish()
guard let tintColor = self.textViewTintColor else { return }
self.textView.resignFirstResponder()
// reset cursor
self.textView.tintColor = tintColor
self.textViewTintColor = nil
}
}
thanks for all help:)! fixed it using iboutlet collection and add properies on viewDidLoad
I'm trying to add properties to keyboard keys like layer.shadowColor or layer.shadowRadius.
I got an error
'Value of type '(UIButton)' -> () has no member 'layer'
how to fix this ?
this is my code keyboardViewController.swift
import UIKit
class KeyboardViewController: UIInputViewController {
var newKeyboardView: UIView!
#IBAction func keyPressed(sender: UIButton) {
}
#IBOutlet var nextKeyboardButton: UIButton!
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
loadInterface()
}
func loadInterface() {
// load the nib file
let keyboardNib = UINib(nibName: "newKeyboard", bundle: nil)
// instantiate the view
newKeyboardView = keyboardNib.instantiateWithOwner(self, options: nil)[0] as! UIView
// add the interface to the main view
view.addSubview(newKeyboardView)
// copy the background color
view.backgroundColor = newKeyboardView.backgroundColor
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
textColor = UIColor.whiteColor()
} else {
textColor = UIColor.blackColor()
}
self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
}
}
I think that in order to apply some style to the button, you need an outlet to this button.
Right now, from what I can understand, you are trying to apply styles to the button from the #IBAction to the sender, which is not the proper way to do it.
Try to make an outlet to the button in the view controller and then to apply the styles from within the viewDidLoad method.
I hope this is clear, but if you want a more specific answer you need to show us what you tried, for example pasting the code you have in the view controller
EDIT:
Based on the code you post, the keyboard is a Nib you instantiate from loadInterface(). I don't have a clear vision of the whole thing with only this piece of code, but it seems to me that you are trying to apply some styles to every key button of a keyboard view. Unfortunately this really depends on how the keyboard is implemented, can you provide some more details?
Anyway, from what I see I think you didn't write this code: probably you are following a tutorial or maintaining someone else's code. That's ok, but I suggest you to follow a an introduction course to iOS development with Swift, like the Udacity's one, which is fantastic IMHO (https://www.udacity.com/course/intro-to-ios-app-development-with-swift--ud585)
If you try to format your UIButton with QuartzCore framework, you'll need to import it first:
import QuartzCore
Then you will be able to access those members.
For example (latest swift3 code):
#IBAction func keyPressed(sender: UIButton) {
let button = sender as UIButton!
button?.backgroundColor = UIColor.red
button?.layer.shadowColor = UIColor.black.cgColor
button?.layer.shadowRadius = 1.0
button?.layer.cornerRadius = 4.0
}
In case you need to apply your styles sooner, try to consider to put this code into viewDidLoad or viewDidAppear methods:
self.nextKeyboardButton.backgroundColor = UIColor.red
self.nextKeyboardButton.layer.shadowColor = UIColor.black.cgColor
self.nextKeyboardButton.layer.shadowRadius = 1.0
self.nextKeyboardButton.layer.cornerRadius = 4.0
Seems like you're trying to "add property" not to a button, but rather to a closure which accepts a button as an argument.
Make it like this:
nextKeyboardButton.layer.shadowColor = UIColor.redColor.cgColor
nextKeyboardButton.layer.shadowRadius = 5.0
I have a UITextView that is not editable but needs to be able to select a word upon a single touch of that word and have the selected word be passed on to another function. What's a way to go about this? Any help would be appreciated.
Superhacky solution (if you have a lot of words this is a bad bad idea):
Make all words in UITextView links (but don't format them as such).
Make your UITextView selectable in IB
Have your VC (or whoever owns the UITextVeiw) to implement UITextViewDelegate
Implement -(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
Use the characterRange to set UITextView selectedTextRange
Profit!
Less hacky solution would be to use a UITapGestureRecognizer to get the tap location, translate it to UITextView and select the glyphs that horizontally surrond the tap location.
Step 1:
To get the selected string from textView, you have to implement UITextViewDelegate delegate and implement a method.
Step 2:
pass the selectedText to another function
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.textView.delegate = self;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textViewDidChangeSelection(textView: UITextView) {
let range: NSRange = textView.selectedRange
let text = textView.text as NSString
let selectedText = text.substringWithRange(NSMakeRange(range.location, range.length))
self.getSelectedText(selectedText)
}
func getSelectedText(text: String) {
NSLog("\(text)")
}
}
I am trying to clear multiple textviews on editing. I know how do so with one textView (IE):
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var myTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
myTextView.delegate = self
}
func textViewDidBeginEditing(textView: UITextView) {
myTextView.text = ""
}
How would I use the same concept for multiple textviews?
func textViewDidBeginEditing(textView: UITextView) {
myTextView.text = ""
}
The above delegate method will get called when a text view begins editing. And this method holds the reference to the textView that called in the textView object. You can use that reference to clear the text instead of using a separate reference/outlet to the textView.
So the method would be:
func textViewDidBeginEditing(textView: UITextView) {
textView.text = ""
}
From the Documentation:
Description:
Tells the delegate that editing began in the specified text field.
This method notifies the delegate that the specified text field just
became the first responder. Use this method to update state
information or perform other tasks. For example, you might use this
method to show overlay views that are visible only while editing.
Implementation of this method by the delegate is optional.
Parameters:
textView
The text view in which an editing session began.
I'm trying to design a view within my app that displays an error UILabel when the text inside of a UITextField does not match a certain regex. Everything works fine except for when my UITextField contains an invalid entry and then I tap the screen to dismiss the keyboard. After the keyboard dismisses, the UITextField moves on top of my UITextView (the red text) and I cannot find out why. I have set breakpoints in my code, but it seems that none of my code is executed after the keyboard dismisses. Any help is appreciated.
//
// ViewController.swift
// KeyboardLabel
//
import UIKit
class ViewController: UIViewController {
#IBOutlet var titleLabel:UILabel!
#IBOutlet var errorLabel:UITextView!
#IBOutlet var textBox:UITextField!
#IBOutlet var createButton:UIButton!
var deltaHeight:CGFloat!
var beenMoved = true
override func viewDidLoad() {
super.viewDidLoad()
// Register for notifications when the text in the text field is changed
NSNotificationCenter.defaultCenter().addObserver(self, selector: "validateText", name: UITextFieldTextDidChangeNotification, object: textBox)
// Add a gesture recognizer to dismiss the keyboard
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "dismissKeyboard"))
// Set the text of the labels
titleLabel.text = "Container Number:"
errorLabel.text = "Error, Invalid container number.\nRe-enter number."
// Calculate the height to move the text field and button
deltaHeight = errorLabel.frame.size.height + 8.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func dismissKeyboard() {
textBox.resignFirstResponder()
}
func validateText() {
dispatch_async(dispatch_get_main_queue(), {
// Regular expression for determining whether the text is valid
let predicate = NSPredicate(format: "SELF MATCHES %#", "[a-zA-Z0-9#]+")
let empty = self.textBox.text!.isEmpty
let valid = predicate.evaluateWithObject(self.textBox.text)
// If the string is valid
if valid || empty {
// If the view has been moved down
if(!self.beenMoved) {
// Hide the error label then move the text field and create button up
self.errorLabel.hidden = true
UIView.animateWithDuration(0.4, animations: {
self.textBox.frame.origin.y -= self.deltaHeight
self.createButton.frame.origin.y -= self.deltaHeight
})
// Flip the flag
self.beenMoved = true
}
}
// If the string is invalid
else {
// If the view has been moved up
if(self.beenMoved) {
// Show the error label then move the text field and create button down
UIView.animateWithDuration(0.4, animations: {
self.textBox.frame.origin.y += self.deltaHeight
self.createButton.frame.origin.y += self.deltaHeight
}, completion: {
(flag:Bool) in
self.errorLabel.hidden = false
})
// Flip the flag
self.beenMoved = false
}
}
// If the text field is empty
if empty {
// Disable the create button
self.createButton.enabled = false
}
else {
// Enable the create button
self.createButton.enabled = true
}
})
}
}
The behavior is actually such that initially, the UITextField moves on top of the UITextView if you enter something that does not match the regex. This is because you are moving the UITextField and button with the following lines of code:
self.textBox.frame.origin.y += self.deltaHeight
self.createButton.frame.origin.y += self.deltaHeight
When the keyboard dismisses, the UITextField and UIButton return to their original locations. I am assuming you have no constraints on the UI elements.