How to convert smileys to emoticon? - ios

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.

Related

Put two words in a same line if they fit, if not put them in a new line

So I have the following question:
I have attributed string contained in a UITextView. Attributed string is contained of two parts - the normal one is ordinary text, and the second part has NSURL in it - so for better visualisation it would look like:
For more information READ HERE
The problem that I am having is that if the text fits in the one line I must keep it in one line, and if "HERE" falls in second line I must put READ also in the second line.
So, the first case - if all fits
For more information READ HERE
All other cases -
For more information
READ HERE
I tried to do it with checking if size of the screen is bigger than textfield bounds but it didn't work:
if (label.bounds.size.width < size.width) ...
I tried also other similar solutions but i think they are all addable on normal UILabels and not modified attributed texts.
If you have any idea how to deal with this I would appreciate it.
Thanks :)
There are multiple solution to resolve this.
First one is to use non-breakable space
simply add "\u{00a0}" in between click here like CLICK\u{00a0}HERE
here is the link
Second one is instead of adding space you can add "_" into it.
e.g.
"CLICK_HERE" and you can replace the color of "_" with clear.
here is the code
class ViewController: UIViewController {
#IBOutlet weak var temp : UILabel!
override func viewDidLoad() {
let myString = "For more detail information READ_HERE"
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: myString)
attributedString.setColorForText(textForAttribute: "_", withColor: .clear)
temp.attributedText = attributedString
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension NSMutableAttributedString {
func setColorForText(textForAttribute: String, withColor color: UIColor) {
let range: NSRange = self.mutableString.range(of: textForAttribute, options: .caseInsensitive)
self.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
}
}

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.

How to use NSAttributedStrings in iOS with Swift?

I would like to have a label with an attributed string that changes dynamically at runtime. Something like this
Is there a better way to dynamically change the price value without hardcoding the attributed keys dictionaries and manually building the NSAttributedString?
The best way to approach Attributed Strings on iOS is by using the built-in Attributed Text editor in the interface builder and avoid uneccessary hardcoding NSAtrributedStringKeys in your source files.
You can later dynamically replace placehoderls at runtime by using this extension:
extension NSAttributedString {
func replacing(placeholder:String, with valueString:String) -> NSAttributedString {
if let range = self.string.range(of:placeholder) {
let nsRange = NSRange(range,in:valueString)
let mutableText = NSMutableAttributedString(attributedString: self)
mutableText.replaceCharacters(in: nsRange, with: valueString)
return mutableText as NSAttributedString
}
return self
}
}
Add a storyboard label with attributed text looking like this.
Then you simply update the value each time you need like this:
label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)
Make sure to save into initalAttributedString the original value.
You can better understand this approach by reading this article:
https://medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e
May not know, this is what you're looking for but will solve your problem.
You may use labels for each and update amount easily without touching attributed string.
Here is result:
Sample code, I've tried for this demo:
#IBOutlet weak var lblAmount: UILabel!
func pricelabel() -> Void {
var amount = 0
Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true) { (timer) in
amount += 10
self.lblAmount.text = "\(amount)"
}.fire()
}

Changing font of strings separated by spaces

I'm trying to make the words split by spaces green in a UITextField, kind of like the way it works when you compose of a new iMessage. I commented out the part of my code that's giving me a runtime error. Please let me know if you have any ideas:
func textChanged(sender : UITextField) {
var myMutableString = NSMutableAttributedString()
let arr = sender.text!.componentsSeparatedByString(" ")
var c = 0
for i in arr {
/*
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor.greenColor(), range: NSRange(location:c,length:i.characters.count))
sender.attributedText = myMutableString
*/
print(c,i.characters.count)
c += i.characters.count + 1
}
}
Your code has at least two parts needed to be fixed.
var myMutableString = NSMutableAttributedString()
This line creates an empty NSMutableAttributedString. Any access to the content may cause runtime error.
The other is i.characters.count. You should not use Character based locations and counts, when the APIs you want use is based on the behaviour of NSString. Use UTF-16 based count.
And one more, this is not critical, but you should use sort of meaningful names for variables.
So, all included:
func textChanged(sender: UITextField) {
let text = sender.text ?? ""
let myMutableString = NSMutableAttributedString(string: text)
let components = text.componentsSeparatedByString(" ")
var currentPosition = 0
for component in components {
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor.greenColor(), range: NSRange(location: currentPosition,length: component.utf16.count))
sender.attributedText = myMutableString
print(currentPosition, component.utf16.count)
currentPosition += component.utf16.count + 1
}
}
But whether this works as you expect or not depends on when this method is called.
You create an empty attributed string but never install any text into it.
The addAttribute call apples attributes to text in a string. If you try to apply attributes to a range that does not contain text, you will crash.
You need to install the content of the unattributed string into the attributed string, then apply attributes.
Note that you should probably move the line
sender.attributedText = myMutableString
Outside of your for loop. There is no good reason to install the attributed string to the text field repeatedly as you add color attributes to each word.
Note this bit from the Xcode docs on addAttribute:
Raises... an NSRangeException if any part of aRange lies beyond the
end of the receiver’s characters.
If you are getting an NSRangeException that would be a clue as to what is wrong with your current code. Pay careful attention to the error messages you get. They usually offer important clues as to what's going wrong.

Multiple lines UILabel with multiple buttons and fonts

I'm making a UITableViewCell for some activity feed objects, to give you an idea they're going to be like the Facebook posts where you have multiple links in one post.
In my case there are going to be two links to other UIViewController for each post and one plain UILabel that connects the two and explains the connection (such as "X has commented on Y's post") where you could tap both X and Y for some actions to happen.
As right now, I just made 3 separate UILabels. The problem with that is that I'm not sure how to handle names that are too long in multiple lines.
Meaning if for example instead of X, the post was "XXXXXXXXXXXXXXXXX has commented on Y's post", then "has commented on Y's post" would need to go on another line.
As right now I just link the 3 UILabels with constraints such that they're next to each other but that wouldn't work when they're too long.
If you have any idea on how could I approach this issue, it would be really appreciated if you could let me know.
Thanks in advance.
There are too many labels, I think you can use this extension:
extension NSMutableAttributedString {
public func setAsLink(textToFind:String, linkURL:String) -> Bool {
let foundRange = self.mutableString.rangeOfString(textToFind)
if foundRange.location != NSNotFound {
self.addAttribute(NSLinkAttributeName, value: linkURL, range: foundRange)
return true
}
return false
}
}
Then you can do:
let labelFont = UIFont(name: "HelveticaNeue-Bold", size: 18)
let attributes :[String:AnyObject] = [NSFontAttributeName : labelFont!]
let attrString = NSAttributedString(string:"foo www.google.com", attributes: attributes)
let urlPath: String = "http://www.google.com"
let url: NSURL = NSURL(string: urlPath)!
attrString.setAsLink("www.google.com", linkURL:url)
myLabel.attributedText = attrString
UPDATE: (after your comments)
If you need to intercept urllink you can transform your label to textView (UITextView), set it the delegate and handle the shouldInteractWithURL method:
class ViewController: UIViewController, UITextViewDelegate {
... // on your code do:
myTextView.delegate = self
...
func textView(textView: UITextView!, shouldInteractWithURL URL: NSURL!, inRange characterRange: NSRange) -> Bool {
if URL.scheme == "http://www.google.com" {
//do whatever you want
launchMyMethodForThisUrl()
}
}
Set number of line of label to zero like,
label.numberOfLines = 0 // it will increase line when needed
And use attribute string to for different fonts and size or links etc.
and then set that string to label as,
label.attributedText = attributedString
Update :
If you want some action event on particular text then you should use UITextview instead of label. it will be more easier by implementing shouldInteractWithURL delegate of it.
Another good solution is use thirdparty library like TTTAttributedLabel. It is exact what you want i think. have a look once.
Update 2 :
refer this link or this link for your desired output
Hope this will help :)

Resources