How to copy text to clipboard/pasteboard with Swift - ios

I'm looking for a clean example of how to copy text to iOS clipboard that can then be used/pasted in other apps.
The benefit of this function is that the text can be copied quickly, without the standard text highlighting functions of the traditional text copying.
I am assuming that the key classes are in UIPasteboard, but can't find the relevant areas in the code example they supply.

If all you want is plain text, you can just use the string property. It's both readable and writable:
// write to clipboard
UIPasteboard.general.string = "Hello world"
// read from clipboard
let content = UIPasteboard.general.string
(When reading from the clipboard, the UIPasteboard documentation also suggests you might want to first check hasStrings, "to avoid causing the system to needlessly attempt to fetch data before it is needed or when the data might not be present", such as when using Handoff.)

Since copying and pasting is usually done in pairs, this is supplemental answer to #jtbandes good, concise answer. I originally came here looking how to paste.
iOS makes this easy because the general pasteboard can be used like a variable. Just get and set UIPasteboard.general.string.
Here is an example showing both being used with a UITextField:
Copy
UIPasteboard.general.string = myTextField.text
Paste
if let myString = UIPasteboard.general.string {
myTextField.insertText(myString)
}
Note that the pasteboard string is an Optional, so it has to be unwrapped first.

Copying text from the app to the clipboard:
let pasteboard = UIPasteboard.general
pasteboard.string = employee.phoneNumber

SWIFT 4
UIPasteboard.general.string = "TEXT"

in Swift 5 i can copy text to clipboard using
UIPasteboard.general.string = "Hello world"
then you can paste the text anywhere of your device

Write below the code where you want to Copying String or Text
UIPasteboard.general.string = "Dhaval Gevariya" // Put your String here
this is for read String from clipboard.
var readString = UIPasteboard.general.string

import UIKit.UIPasteboard
extension UIPasteboard {
static func pasteToClipboard(_ content: String) {
self.general.string = content
}
static func readFromClipboard() -> String? {
return self.general.string
}
}

Related

How to convert smileys to emoticon?

Is there a way to convert ":)" to 😊 like : detection and conversion, I have a UITextView in a chat application which should convert the smiley to the respective emoticon.
Get the offical list: emoji
Just an example: yourTextView.text = "your smiley: \u{1f642}"
If you want to convert emoticons to emoji on the fly either you need to specify it by yourself and analyze the input string or using a 3rd-party lib e.g. pods for converting and watching input string through text change events e.g.: docs
You can use the logic in this package npm, you find also a map of smile and the respective emoji:
https://www.npmjs.com/package/smile2emoji
I have created this simple class based on the npm package suggested by #emish89 https://www.npmjs.com/package/smile2emoji.
https://gist.github.com/lorenzOliveto/f20a89e9f68276cae21497a177ad8a4c
Swift 5
You should implement delegate textViewDidChange for your UITextView and find all need substrings in its text then replace them inside with textStorage property:
extension ViewController : UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
guard let text = textView.text else { return }
var index = text.startIndex
while let range = text.range(of: ":)", range: index..<text.endIndex) {
index = range.upperBound
textView.textStorage.replaceCharacters(in: NSRange(range, in: text), with: "😀")
}
}
}
It works while editing or paste text.

Insert line break for UILabel text when a specific character is found

I have a UILabel that dynamically gets updated every time I click a button, the data will be fetched from firebase and displayed on the uilabel.I am able to display the text as shown below. I would like to insert a line break when a specific delimiter(say '.' PERIOD) is encountered in the text. I have looked into many solutions about UIlabel line break but couldn't find one what exactly I am looking for, every solution deals with static text that we provide in the storyboard itself. Any help will be appreciated. Thank you.
)
Created an outlet for the label and have taken a string which has three sentences separated by ".". The content in the image attached will be this string. Try using replacingOccurences() function as given below.
#IBOutlet weak var trialLabel: UILabel!
var string = "This is a trial text.Let us jump to a new line when the full stop is encountered.Hope it helps."
string = string.replacingOccurrences(of: ".", with: ".\n")
trialLabel.text = string
Check https://developer.apple.com/documentation/foundation/nsstring/1412937-replacingoccurrences for further reference. Happy Coding!!
You can achieve this with the attributed text property of UILabel. Try to find and replace the character with html line break and then assign this text to the UILabel attributed text.
You can replace string by
let str = "This is the string to be replaced by a new string"
let replacedStr = str.replacingOccurrences(of: "string", with: "str")
use below code
// HTML Tag Remove Method
extension String{
func removeHtmlFromString(inPutString: String) -> String{
return inPutString.replacingOccurrences(of: ".", with: ".\n", options: .regularExpression, range: nil)
}
}
let str = "Lorem Ipsum is simply dummy text.Lorem Ipsum has been the industry's standard dummy text ever since the 1500."
let postDiscription = str!.removeHtmlFromString(inPutString: str!)
You can add a \n in the text string to where you want to create a line break.

Capitalized text in UILabel from visual editor in xcode

I am starter in iOS. I found out that there are ways around making the text bold, and changing font and font size etc from visual editor. But are there any ways to set the UILabel text All Capitalized from visual editor (STORYBOARD, NOT CODE). I searched but only found code (Swift/Objective C) based answers like this:
testDisplayLabel.text = testDisplayLabel.text.uppercased()
A legitimate question -- and a useless (if not arrogant) answer marked as Accepted. It is not unusual when you receive from a copywriter a LOT of text that is not All Caps. So the answer is -- you have to process it all programmatically.
EDIT Generally it is a good idea to wrap your text constants programmatically. First it gives you the opportunity to localize your app (even in the future):
extension String {
func localized (lang: String) -> String {
guard let path = Bundle.main.path (forResource: lang, ofType: "lproj") else { return "" }
guard let bundle = Bundle (path: path) else { return "" }
return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "")
}
func localized () -> String {
guard let loc = Locale.current.languageCode else { return "" }
return localized(lang: loc)
}
}
So whenever you need to display a string, you apply this method like this:
"My String".localized()
Likewise, your string should start with a common localisation, and then you make them capitalized when needed:
"This should be all caps".localized().uppercased()
By default "lowercase word" and "uppercase word" are unbound in Preferences -> Key Bindings -> Text Key Bindings. Just create a new set and bind them to something. Then you will be able to use the binding to capitalize the text.
Just turn ON caps lock and type text :) that's the way we do in storyboard, Other thing you can do is select a font that has only Uppercase character in it.

Paste Formatted Text, Not Images or HTML

I am trying to emulate the pasteboard behavior of the iOS Pages and Keynote apps. In short, allowing basic NSAttributedString text formatting (i.e. BIU) to be pasted into a UITextView, but not images, HTML, etc.
BEHAVIOR SUMMARY
If you copy formatted text from the Notes app, Evernote, or text and images from a web site, Pages will only paste the plain text string
If you copy formatted text from within Pages or Keynote, it will paste the formatted text elsewhere in Pages, Keynote, etc.
An undesired consequence, but perhaps important to acknowledge, is that neither Notes app or Evernote will paste formatted text copied from Pages or Keynote. I am speculating that the discrepancy between apps is the use of NSAttributedStrings, versus HTML?
How is this accomplished? On Mac OS, it appears you can ask the pasteboard to return different types of itself, have it provide both a rich text and a string representation, and use rich text as preferred. Unfortunately, the readObjectsForClasses doesn't appear to exist for iOS. That said, I can see via log that iOS does have an RTF related type of pasteboard, thanks to this post. I can't however, find a way to request an NSAttributedString version of pasteboard contents so I can prioritize it for pasting.
BACKGROUND
I have an app that allows basic NSAttributedString user editable formatting (i.e. bold, italic, underline) of text in UITextViews. Users want to copy text from other apps (e.g. web page in Safari, text in Notes app), to paste into a UITextView in my app. Allowing pasteboard to operate as default means I may end up with background colors, images, fonts, etc. that my app isn't intended to handle. Example below shows text how copied text with a background color looks when pasted into my app's UITextView.
I can overcome 1 by subclassing UITextView
- (void)paste:(id)sender
{
UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
NSString *string = pasteBoard.string;
NSLog(#"Pasteboard string: %#", string);
[self insertText:string];
}
The unintended consequence is, losing the ability to retain formatting of text that's copied from within my app. Users may want to copy text from one UITextView in my app, and paste it to another UITextView in my app. They will expect formatting (i.e. bold, italics, underline) to be retained.
Insight and suggestions appreciated.
Some copy/paste goodies and ideas, for you :)
// Setup code in overridden UITextView.copy/paste
let pb = UIPasteboard.generalPasteboard()
let selectedRange = self.selectedRange
let selectedText = self.attributedText.attributedSubstringFromRange(selectedRange)
// UTI List
let utf8StringType = "public.utf8-plain-text"
let rtfdStringType = "com.apple.flat-rtfd"
let myType = "com.my-domain.my-type"
Override UITextView copy: and use your custom pasteboard type
pb.setValue(selectedText.string, forPasteboardType: myType)
To allow rich text copy (in copy:):
// Try custom copy
do {
// Convert attributedString to rtfd data
let fullRange = NSRange(location: 0, length: selectedText.string.characters.count)
let data:NSData? = try selectedText.dataFromRange(fullRange, documentAttributes: [NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType])
if let data = data {
// Set pasteboard values (rtfd and plain text fallback)
pb.items = [[rtfdStringType: data], [utf8StringType: selectedText.string]]
return
}
} catch { print("Couldn't copy") }
// If custom copy not available;
// Copy as usual
super.copy(sender)
To allow rich text paste (in paste:):
// Custom handling for rtfd type pasteboard data
if let data = pb.dataForPasteboardType(rtfdStringType) {
do {
// Convert rtfd data to attributedString
let attStr = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType], documentAttributes: nil)
// Bonus: Possibly strip all unwanted attributes here.
// Insert it into textview
replaceSelection(attStr)
return
} catch {print("Couldn't convert pasted rtfd")}
}
// Default handling otherwise (plain-text)
else { super.paste(sender) }
Even better then using a custom pasteboard type, white-list all possibly wanted tags, loop through and strip away all other on paste.
(Bonus: help UX in other apps by stripping away unnecessary attributes you've added, on copy (like font and fg-color))
Also worth noting, the textView might not want to allow pasting when the pasteboard contains a specific type, to fix that:
// Allow all sort of paste (might want to use a white list to check pb.items agains here)
override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
if action == #selector(UITextView.paste(_:)) {
return true
}
return super.canPerformAction(action, withSender: sender)
}
Furthermore, cut: could be nice to implement as well. Basically just copy: and replaceSelection(emptyString)
For your convenience:
// Helper to insert attributed text at current selection/cursor position
func replaceSelection(attributedString: NSAttributedString) {
var selectedRange = self.selectedRange
let m = NSMutableAttributedString(attributedString: self.attributedText)
m.replaceCharactersInRange(self.selectedRange, withAttributedString: attributedString)
selectedRange.location += attributedString.string.characters.count
selectedRange.length = 0
self.attributedText = m
self.selectedRange = selectedRange
}
Good luck!
Refs:
Uniform Type Identifiers Reference
This should be a comment on Leonard Pauli's answer, but I don't have enough reputation to make comments yet.
Instead of:
selectedRange.location += attributedString.string.characters.count
(or attributedString.string.count as it is in more recent versions of Swift)
It's best to use:
selectedRange.location += attributedString.length
Otherwise when you paste text that contains emoji that cause attributedString.length and attributedString.string.count to differ, the selection will end up in the wrong place.

Localized String with Interface Builder User Defined Runtime Attributes

I am currently trying to create a localized accessibilityLabel in the storyboard (I am trying to avoid doing it programatically). It seems that whenever I use the Localized String option, the accessibilityLabels ends up being set to the localized string key that I have provided rather than the string itself. Does anyone have the solution to this problem? Any help would be greatly appreciated.
I guess you expect the localized string to be taken from Localizable.strings. The "Localized String" type doesn't work this way, it's just a marker to indicate that the value of the user defined runtime attribute will participate in the localization process when you use base localization. Please take a look at https://stackoverflow.com/a/24527990/2876231 for a lengthier explanation.
The attribute type needs to be Localizable String, and then you'd translate it in the .strings file using the following property:
"KLc-fp-ZVK.ibExternalUserDefinedRuntimeAttributesLocalizableStrings[0]" = "¡Hola!";
Unfortunately, it doesn't seem to work with a named attribute, but only with the long property above.
(Based on Andrew's answer here: Localize a view within a storyboard using "User Defined Runtime Attributes")
I did the customization of an attribute with the simple solution of localizing the attribute by code:
private struct AssociatedKeys {
static var someTagKey = "someTag"
}
#IBInspectable var someTag: String? {
get {
return NSLocalizedString(
objc_getAssociatedObject(self, &AssociatedKeys.someTagsKey) as? String ?? "", comment: "")
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.someTagsKey,
newValue as NSString?,
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
And after that you can easily extract all the strings from the xib and storyboard files with an egrep:
egrep -ohr --include="*.xib" --include="*.storyboard" '<userDefinedRuntimeAttribute type="string" keyPath="someTag" value="[^"]+"/>' . >> extracted-strings.txt
And after that eliminate the tags in the strings file by the following sed and then you have to plain strings file for xcode ready:
sed -i -e 's/^<userDefinedRuntimeAttribute type="string" keyPath="someTag" value=\("[^"]*"\)\/>/\1 = \1;/g' extracted-strings.txt

Resources