I have to create an application that has 5 UIViewControllers, each with big text and images inside the text. What I have done so far was to add a UITextView in the UIViewController and load with an rtf file the whole text (every text is big).
Now I have to add images inside the text in some places. What do you propose that could be the best way to construct it? I tried to add the image inside the the rtf file but it is not working properly. Since the text is too big I did not want to add the text manually by typing it. Also, I have a top bar menu that slides the view to each content, that is why I had to have only one UITextView. I am looking for a best solution.
What about adding your texts with images on UIWebView with loading these texts by wrapping them into html?
You can also add javascript callbacks which you will be able to handle in swift or obj-c by adding JavascriptCore.framework to your build phases:
Add button in your code:
<button text="Close" onclick="javascript:callSwiftCode()">Call swift code</button>
And in your UIWebViewDelegate class:
func webViewDidFinishLoad(webView: UIWebView) {
let context: JSContext = webView.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext") as! JSContext
let codeClosure: #convention(block) ()->() = { ()->() in
print ("This is callback from javascript you can add your code in this closure")
}
let casted: AnyObject = unsafeBitCast(codeClosure, AnyObject.self) as AnyObject
context.setObject(casted, forKeyedSubscript: "callSwiftCode")
}
You can achieve this using NSAttributedString and NSTextAttachment. Attributed strings are strings with formatting attached(bold, italics, colors, etc), but you can also attach the images inside attributed strings, and they just get drawn right along with the text. Below example might help you understand:
//Create a mutable attributed string so that we could append everything to it.
let bigText = NSMutableAttributedString(string: "Your text starts here")
//Create a NSTextAttachment
let image1Attachment = NSTextAttachment()
image1Attachment.image = UIImage(named: "image1.png")
// wrap the attachment in its own attributed string so we can append it
let image1String = NSAttributedString(attachment: image1Attachment)
// add the NSTextAttachment wrapper to our full string, then add some more text.
bigText.appendAttributedString(image1String)
bigText.appendAttributedString(NSAttributedString(string: "End of text"))
// Then set this bigText to your label's attributedText property.
yourLabel.attributedText = bigText
Related
I have a multi-line UITextView and sometimes the text wraps several lines. I want to get the text from it with line breaks from what is visible on the iphone screen.
This is useful because I have a UITextView that changes font size with the UI and I want to capture the text as the user sees it on the screen.
Getting the text from the UITextView with textview.text does not contain those. (Although it does contain any line breaks that a user typed by pressing "return" on the keyboard.)
I think maybe you need to measure the height of the UITextView and go through each character but I am not sure how to do that. I also want it to work with emojis.
It seems that you want to get a snapshot of UITextView instead of get textview.text, so what you need is to learn how to draw UITextView's content as a picture.
For how to drawing a snapshot of UIView, try this.
For how to drawing a snapshot of NSAttribeString, try draw(with:options:context:).
Core Text or TextKit are the best options to work with text.
This answer shows how to get word-wrapped lines using Core Text: https://stackoverflow.com/a/13588322/1837959.
Or you could access the layoutManager (NSLayoutManager) of the UITextView to access the layout data.
Sounds like a hacky solution but kinda not really:
Use the Vision Framework's text recognition to convert an image to text.
convert the view to image
extension UIView {
var toImage: UIImage? {
let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
return renderer.image { (context) in
self.layer.render(in: context.cgContext)
}
}
}
let yourTextView = UITextView()
let img = yourTextView.toImage()
Follow article
guard let cgimg = img.cgImage else {return}
// Create a new image-request handler.
let requestHandler = VNImageRequestHandler(cgImage: cgImage)
// Create a new request to recognize text.
let request = VNRecognizeTextRequest(completion: recognizeTextHandler)
do {
// Perform the text-recognition request.
try requestHandler.perform([request])
} catch {
print("Unable to perform the requests: \(error).")
}
// Process the Results
func recognizeTextHandler(request: VNRequest, error: Error?) {
guard let observations =
request.results as? [VNRecognizedTextObservation] else {
return
}
let recognizedStrings = observations.compactMap { observation in
// Return the string of the top VNRecognizedText instance.
return observation.topCandidates(1).first?.string
}
// Use the result
processResults(recognizedStrings)
}
UITextView Text will show '\n' for user input(when he press enter).
If User does not press enter/return and keep writing the word wrap will happen according to size/width of UITextView. So you should not anything. So if you see "\n"
just change it to , if you are displaying it in Website or using Web Views html layout. Or Just replace all "\n" with space and Don't wrap it let width of the view decide how to wrap it.
Capturing the Screen of IOS iPhone and showing it in same way looks more weird.
For Example.
Think this is
Data even
there is no
return.
It should be in one line.
I'm developing a macOS rich-text editor that applies pre-defined style for each line of the text view.
To format the lines, I'm using NSAttributedString, then, I'm inserting that string into my UITextView. To make things easier, I'm using a tool called SwiftRichString.
My code looks like below. It's straight-forward and works fine.
import Cocoa
import SwiftRichString
import AppKit
class ViewController: NSViewController {
#IBOutlet var textView: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
// Format the string
let style = Style {
$0.font = NSFont(name: "Arial", size: 20)
$0.color = NSColor.black
$0.alignment = .center
}
let attributedText = "Hello World!".set(style: style)
// Add formatted string to the text view
textView.textStorage?.append(attributedText)
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
Current situation:
User is typing a formatted line. Then when user hits Return and types something, format of the new line returns back to the default style of the UITextView.
What I want:
User is typing a certain formatted line, then he hits Return. The next line should be formatted to another pre-defined style on-the-go.
Example:
User is typing the Title line. Current style is (Arial, bold, 20pt).
He hits Return.
Next line should be styled as Normal Text using a pre-defined style (Arial, 12pt).
Important Note:
In my above code, I was able to format the line easily because it's hard-coded. My real issue is, how can I instantly format the next line, because the next line will be entered by the user. The style should be applied to the next line before user begins writing it.
Okay, I just figured out how to use typingAttributtes to solve this question (thanks to #Larme for the hint).
// Define next attributes
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: NSColor.red,
.font: NSFont(name: "Arial", size: 12)!,
]
// Assign attributes to the text view typing attributes
textView.typingAttributes = attributes
Very easy!
Pardon off topic. If you're making a text editor, you may consider using a table view, where each text line is a cell - this is extra work for you as a programmer but it'll boost the performance significantly. That's how Xcode editor is built.
Maybe you might use optional func textViewDidChange(_ textView: UITextView)
https://developer.apple.com/documentation/uikit/uitextviewdelegate/1618599-textviewdidchange
and after the change, just parse the text, find new lines, split them and apply all styling you want
I have a UITextview showing certain text by calling rtf files.
I want to let users to edit the text on UITextView and save the changes they made in rtf file.
Is there any way I can change the rtf file itself by changing the text on UITextView??
If you want a save-as-you-type solution to the problem:
Make your view controller conform to UITextViewDelegate
Connect the text view's delegate to the view controller
Add the following function to your view controller:
// Path to your RTF file
let url = NSBundle.mainBundle().URLForResource("my_document", withExtension: "rtf")!
func textViewDidChange(textView: UITextView) {
let data = try! textView.attributedText.dataFromRange(NSMakeRange(0, textView.attributedText.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType])
data.writeToURL(url, atomically: true)
}
This will save every keystroke to the file. No idea on the performance though. I have not tested this on a real iPhone. If it's too hard on the device, consider putting a time delay between saves or have an NSTimer to save every n seconds.
Is there a way to add a target to a specified word from an UITextView? For example.
I want to add a target to a hash-tagged word from a UITextView.
I'm using a function to get an array with the hash-tagged words from the textview, but I don't know how to add them a target, or a tap-gesture.
You can use an attributed string to set the text in the text view. That attributed string uses link attributes (NSLinkAttributeName with a URL value of your choice) in the range of your target hash-tagged words. You need to search the text for your hash-tagged words and add the appropriate link attributes. You probably want to create the link URLs to have a custom scheme and include information about the hash-tagged word. When one of the links is tapped you get a delegate callback from the text view.
I had the same question recently and I found a solution that fit my needs. It's not perfect but maybe it will help:
I decided to go for a whole text button with specific style around my target element. In a user experience way, user may be inclined to touch the styled word.
#IBOutlet weak var stringBtn: UIButton!
override func viewWillAppear(animated: Bool) {
let string = "string with #tag" as NSString
var attributedString = NSMutableAttributedString(string: string as String)
let firstAttributes = [NSUnderlineStyleAttributeName: 1, NSForegroundColorAttributeName: UIColor.whiteColor()]
attributedString.addAttributes(firstAttributes, range: string.rangeOfString("#tag"))
stringBtn.setAttributedTitle(attributedString, forState: .Normal)
//Add target to your button
}
I am trying to build a custom keyboard, it's like a emoji keyboard, but the keyboard's data is from a json file. After parse this json file and get the data, how to make the custom keyboard use it and show in the keyboard view, like the emoji keyboard that built in? Right now, I follow App Extension Keyboard: Custom Keyboard guide, and there only small bits of information here. Is there any tutorial or guide about how to create a custom emoji keyboard online? The current codes I am trying are below:
class KeyboardViewController: UIInputViewController {
override func viewDidLoad() {
super.viewDidLoad()
var error: NSError?
let yanFile = NSBundle.mainBundle().pathForResource("yan", ofType: "json")
let yanData = NSData(contentsOfFile: yanFile) as NSData
let yanDict = NSJSONSerialization.JSONObjectWithData(yanData, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
println("dict: \(yanDict)") //print nothing in console
// Perform custom UI setup here
self.nextKeyboardButton = UIButton.buttonWithType(.System) as UIButton
self.nextKeyboardButton.setTitle(NSLocalizedString("Next Keyboard", comment: "Title for 'Next Keyboard' button"), forState: .Normal)
}
}
The json like below:
{
"list":
[
{
"tag": "laugh",
"yan":
[
"o(*≧▽≦)ツ┏━┓",
"(/≥▽≤/)",
"ヾ(o◕∀◕)ノ"
]
},
{
"tag": "wanna",
"yan":
[
"✪ω✪",
"╰(*°▽°*)╯",
"≖‿≖✧",
">ㅂ<",
"ˋ▽ˊ",
"✪ε✪",
"✪υ✪",
"ヾ (o ° ω ° O ) ノ゙",
"(。◕ˇ∀ˇ◕)",
"(¯﹃¯)"
]
}
]
}
You can build a xib file by clicking new file -> view
1) inside the xib file create a uiview 320x216 and you can drag'n'drop whatever controls you want into it
2) then you can load the nib like this into your keyboard's inputView:
// Perform custom UI setup here
UIView *layout = [[[NSBundle mainBundle] loadNibNamed:#"keyboardXib" owner:self options:nil] objectAtIndex:0];
[self.inputView addSubview:layout];
3) i think it's amazing if you build a JSON to keyboard api
you send a JSON of the keyboard map to your app
and the app knows how to arrange the keys on the inputView accordingly
let us know if you build this project!
EDIT:
4) Most of what you need to do is parse the JSON and display the content you want from the JSON uibuttons, and also decide what text they are inserting into the text field
check out this question: How to parse a JSON file in swift?
Good luck!
First of all you need to create your UI for keyboard in your KeyboardViewController. It's up to you how you customize it, add buttons, views, gestures etc.. (By the way height of view is limited, to standard keyboard height size, so don't try to make it higher it won't draw) Template that is generated it's just sample to show how you can put a single button in it. After you setup your UI make sure you have Next Keyboard Button it's required.
Regarding Emoji, it's not real images, they are just unicode characters that later replaced with images by system. So you can't pass images, the only input that you can provide is NSString [self.textDocumentProxy insertText:#"hello "]; // Inserts the string "hello " at the insertion point
More details can be found here https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/Keyboard.html.