How can I add UIView to UITextView - swift

I'm trying to append a UIView inside a UITextView. Visually speaking it would be some text, banner, more text.
This is what I tried:
// does nothing
text.textContainer.exclusionPaths = [UIBezierPath(rect: view.frame)]
// works but it also removes the text
text.addSubview(view)
This is my class
class ViewController: BannerController {
#IBOutlet weak var text: UITextView!
override func viewDidLoad() {
let view = UIView()
banners.append(view)
let myString = NSMutableAttributedString(string: "Text at the beginning\n")
super.viewDidLoad()
// text.textContainer.exclusionPaths = [UIBezierPath(rect: view.frame)]
// text.addSubview(view)
text.attributedText = myString
}
}
I also saw this https://github.com/vlas-voloshin/SubviewAttachingTextView, but I couldn't figure it out how to apply to my code.
Is it even possible? I'm new at Swift and I have no idea what to do.

If you want to use https://github.com/vlas-voloshin/SubviewAttachingTextView
Just follow below link:
https://github.com/vlas-voloshin/SubviewAttachingTextView/blob/master/Example.playground/Contents.swift

Related

what to recast as an NSSplitViewItem

I am trying to self-learn OSX application development so I can make up all of my own bad habits 8).
Probably extraneous information
I have a trial app that works successfully - it resizes itself based on input from the user via a slider.
The key piece of code that does this is in one View controller ...
class JunkViewController2: NSViewController {
var myY: CGFloat!
#IBOutlet weak var mySlider: NSSlider!
#IBOutlet weak var myView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.preferredContentSize = NSMakeSize(self.view.frame.width, 83)
}
#IBAction func mySlider(sender: NSSlider) {
let mySplitViewController = self.childViewControllers[0] as! JunkSplitViewController
switch mySlider.intValue {
case 3:
myY = 140.0
mySplitViewController.splitViewItems[2].collapsed = false
mySplitViewController.splitViewItems[1].collapsed = false
mySplitViewController.showSubview(2)
mySplitViewController.showSubview(1)
mySplitViewController.showSubview(0)
case 2:
myY = 110.0
mySplitViewController.splitViewItems[2].collapsed = true
mySplitViewController.splitViewItems[1].collapsed = false
mySplitViewController.hideSubview(2)
mySplitViewController.showSubview(1)
mySplitViewController.showSubview(0)
default:
myY = 80.0
mySplitViewController.splitViewItems[2].collapsed = true
mySplitViewController.splitViewItems[1].collapsed = true
mySplitViewController.hideSubview(2)
mySplitViewController.hideSubview(1)
mySplitViewController.showSubview(0)
}
mySplitViewController.preferredContentSize = NSMakeSize(self.view.frame.width, myY - 50 + 3)
self.preferredContentSize = NSMakeSize(self.view.frame.width, myY + 3)
}
}
More pertinent information
In what is working, above, on the story board I have three duplicate ViewControllers connected to a SplitView controller. I do a bunch of what feels like belts and suspenders work to make sure that everything gets resized properly - but the key part (I think) is the .collapsed property.
I am now trying to accomplish the same thing, using a completely different method - dynamically adding / removing split view items. This should allow me to have only one of the small ViewControllers on my story board, and then instantiate it as needed.
Following that idea, here is my SplitViewController ...
class JunkSplitViewController: NSSplitViewController {
#IBOutlet weak var mySplitView: NSSplitView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
//mySplitView.adjustSubviews()
}
func makeChild() -> SmallViewController {
let mySmallGroup = NSStoryboard(name: "Main", bundle: nil).instantiateControllerWithIdentifier("smallVwCtl")
self.addSplitViewItem(mySmallGroup as! NSSplitViewItem)
return mySmallGroup as! SmallViewController
}
}
The main view controller invokes the makeChild function.
class JunkViewController: NSViewController {
#IBOutlet weak var mySlider: NSSlider!
#IBOutlet weak var myView: NSView!
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.preferredContentSize = NSMakeSize(self.view.frame.width, 83)
}
#IBAction func mySlider(sender: NSSlider) {
let mySplitViewController = self.childViewControllers[0] as! JunkSplitViewController
while mySlider.intValue.toIntMax() > mySplitViewController.splitViewItems.count.toIntMax() {
mySplitViewController.makeChild()
}
while mySlider.intValue.toIntMax() < mySplitViewController.splitViewItems.count.toIntMax(){
mySplitViewController.splitViewItems.removeLast()
}
}
}
I get an error at the self.addSplitViewItem(mySmallGroup as! NSSplitViewItem) line of JunkSplitViewController ... "Could not cast value of type Scratch2.SmallViewController to NSSplitViewItem"
I've tried a handful of combinations (forcing mySmallGroup, 'self.addSplitViewItem(mySmallGroup as! SmallViewController)`, etc.) Everything leads to a similar error, either at compile or run time.
I cannot find any documentation on SplitViewItem.
So the question - what will work as input to addSplitViewItem and still successfully connect a new instance of SmallViewController?
And gratefully accept any comments/feedback on the methodology
I hate it when I find my answer minutes after posting a question ...
Based on info I found here ...
func makeChild() -> SmallViewController {
let mySmallGroup = NSStoryboard(name: "Main", bundle: nil).instantiateControllerWithIdentifier("smallVwCtl") as! SmallViewController
self.addSplitViewItem(NSSplitViewItem(viewController: mySmallGroup))
return mySmallGroup
}
... but I'd still like to hear any feedback on methodology. Thanks.

Why does a UITextField have a .text value of Optional("Actual Text") Swift

I have a UITextField and when I get the MyTextField.text value, instead of just the text value it prints
Optional("UITextField Value")
How do I get it to print just the actual text without the Optional(), so it is just the text that is in the UITextField. For Example:
import UIKit
class FirstViewController: UIViewController {
#IBOutlet var MyTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
print(MyTextField.text)
}
}
Let's say the TextField value was "Hello World"
It would print: "optional("Hello World")"
Thank You in advance
Since your MyTextField is an optional, you will have to unwrap the value in your text before printing it.
override func viewDidLoad() {
super.viewDidLoad()
if let text = MyTextField.text {
print(text)
}
}
Xcode is simply saying it does not know if there is actually text in the textfield. Simply putting
print(MyTextField.text!)
should do the trick. By putting the exclamation mark there, you are telling Xcode that you know that there is text within the textfield. However, if you put this code and MyTextField.text does not exist, you will receive a crash. To prevent this, do something like this:
if MyTextField.text != nil {
print(MyTextField.text!)
}
Hope this helps.

Line breaks recognition in swift

I've made an app that would call data from Database via webservice, create an XML page and parse it. After that it would post a text in WebView but for some reason it can't recognise line breaks and just post the text ignoring all "\n".
Is there something I've missed?
Thanks!
This is how I add text to my WebView:
import UIKit
class PubViewController: UIViewController {
#IBOutlet weak var myWebView1: UIWebView!
var selectedFeedTitle = String()
var selectedFeedFeedContent = String()
var selectedFeedURL = String()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let feedContent:String! = "<h3>\(selectedFeedTitle)</h3>\(selectedFeedFeedContent)"
myWebView1.loadHTMLString(feedContent, baseURL: nil)
}
Line breaks are ignored in HTML. You have to use the <br/> tag:
let feedContent:String! = "<h3>\(selectedFeedTitle)</h3>\(selectedFeedFeedContent)"
.stringByReplacingOccurrencesOfString("\n", withString: "<br/>")

Swift Compiler error while referencing existing variable [duplicate]

This question already has an answer here:
Swift: expected declaration error setting "Label" to a string variable
(1 answer)
Closed 7 years ago.
I am trying to manually create some placeholder text for a UITextView, and when I try to set the placeholder text, I get a Swift compiler error. Xcode is telling me that it expected a declaration for pinContent where I first try to set it's text value. Here's my code:
class FirstViewController: UIViewController {
#IBOutlet var pinTitle: UITextField!
#IBOutlet var pinContent: UITextView!
#IBAction func createPin(sender: AnyObject) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println(userLocation)
}
// Manually create a placeholder for the text view
pinContent.text = "Description" // This line is where I get my error
pinContent.textColor = UIColor.lightGrayColor()
// Change the text properties of the text view when the user begins editing, so it types in the normal black font
func textViewDidBeginEditing(textView: UITextView) {
if textView.textColor == UIColor.lightGrayColor() {
textView.text = nil
textView.textColor = UIColor.blackColor()
}
}
// If the user leaves the text view blank when they're done editing, re-set the placeholder
func textViewDidEndEditing(textView: UITextView) {
if textView.text.isEmpty {
textView.text = "Description" // Sometimes I get the same error here as well
textView.textColor = UIColor.lightGrayColor()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The problem seems to be that you want to set the text outside of the scope of a method or a closure. Try this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Manually create a placeholder for the text view
pinContent.text = "Description" // This line is where I get my error
pinContent.textColor = UIColor.lightGrayColor()
println(userLocation)
}

Sending data to another view: can't unwrap option

I know that this has to be a simple fix, but can't seem to understand why my code is not working. Basically I am trying to send a value from a text field in 1 view to a 2nd view's label.
ViewController.swift
#IBOutlet var Text1st: UITextField
#IBAction func Goto2ndView(sender: AnyObject) {
let view2 = self.storyboard.instantiateViewControllerWithIdentifier("view2") as MyView2
//view2.Label2nd.text=text;
self.navigationController.pushViewController(view2, animated: true)
}
MyView2.swift
#IBOutlet var Label2nd: UILabel
override func viewDidLoad() {
super.viewDidLoad()
var VC = ViewController()
var string = (VC.Text1st.text) //it doesn't like this, I get a 'Can't unwrap Option.. error'
println(string)
}
-------EDITED UPDATED CODE FROM (drewag)-------
ViewController.swift
let text = "text"
var sendString = Text1st.text
println(sendString) //successfully print it out.
let view2 = self.storyboard.instantiateViewControllerWithIdentifier("view2") as MyView2
view2.Label2nd.text=sendString;
self.navigationController.pushViewController(view2, animated: true)
MyView2.swift
#IBOutlet var Label2nd: UILabel
override func viewDidLoad() {
super.viewDidLoad()
var VC = ViewController()
var string = self.Label2nd.text
println(string) //still getting the error of an unwrap optional.none
}
var VC = ViewController() creates a new instance of ViewController. Unless there is a default value, you are not going to get any value out of VC.Text1st.text. You really should use a string variable on your second view controller to pass the data to it.
Also, a note on common formatting:
Class names should start with a capital letter (as you have)
Method / function names should start with a lower case letter
UIViewController subclasses should have "Controller" included in their name, otherwise, it looks like it is a subclass of UIView which is an entirely different level of Model View Controller (the architecture of all UIKit and Cocoa frameworks)
Edit:
Here is some example code:
class ViewController1 : UIViewController {
...
func goToSecondView() {
var viewController = ViewController2()
viewController.myString = "Some String"
self.navigationController.pushViewController(viewController, animated: true)
}
}
class ViewController2 : UIViewController {
var myString : String?
func methodToUseMyString() {
if let string = self.myString {
println(string)
}
}
...
}
Note, I am not creating ViewController2 using a storyboard. I personally prefer avoiding storyboards because they don't scale well and I find editing them to be very cumbersome. You can of course change it to create the view controller out of the storyboard if you prefer.
jatoben is correct that you want to use optional binding. IBOutlets are automatically optionals so you should check the textfield to see if it is nil.
if let textField = VC.Text1st {
println(textField.text)
}
This should prevent your app from crashing, but it will not print out anything because your text field has not yet been initialized.
Edit:
If you want to have a reference to your initial ViewController inside your second you're going to have to change a few things. First add a property on your second viewcontroller that will be for the first view controller:
#IBOutlet var Label2nd: UILabel //existing code
var firstVC: ViewController? //new
Then after you create view2, set it's firstVC as the ViewController you are currently in:
let view2 = self.storyboard.instantiateViewControllerWithIdentifier("view2") as MyView2 //already in your code
view2.firstVC = self //new
Finally in your viewDidLoad in your second view controller, use firstVC instead of the ViewController you recreated. It will look something like this:
override func viewDidLoad() {
super.viewDidLoad()
if let textField = firstVC?.Text2nd {
println(textField.text)
}
}
Use optional binding to unwrap the property:
if let string = VC.Text1st.text {
println(string)
}