Set NSTextView to wrap by char either programmatically or through xcode? - swift

There are a couple of solutions online but they are either 10 years old and no longer work or are written in objective C (And also very outdated). One solution involved AttributedText and changing the line break style every single time the content is updated, which for me would be hundreds of calls every few minutes. Surely this can't be the best way. I must be missing something here, there must be a way to set an NSTextView to wrap by char permanently.
I've tried this but it doesn't work and continues to wrap by word:
consoleTextView.textContainer?.lineBreakMode = NSLineBreakMode.byCharWrapping
I've also tried using the attributes inspector in xcode. I finally found the option for it but clicking it does nothing, it just continues to say 'empty selection' in the 'line breaking' field:

You are supposed to set the line break modes on the paragraph styles. This is the smallest possible example to make it work:
let textView = NSTextView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
let paragraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.lineBreakMode = .byCharWrapping
textView.defaultParagraphStyle = paragraphStyle
textView.string = "12345 12345 12345"
view.addSubview(textView)

Anyone looking for an objective-c answer would use something similar to:
NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
myTextView.defaultParagraphStyle = paragraphStyle;

Related

How to make `attributedReadMoreText` in `ReadMoreTextView` library not selectable - swift

I am a new iOS programming. Now i am creating a sample app which display text using ReadMoreTextView library. My content may contain many lines but by using this library i can maximumNumberOfLines to display how many lines of content should be displayed. I implement those content in cell of UITableView and i have problem is that, when i use label.attributedReadMoreText = NSAttributedString(string: "...") then end of content will display ... and when i click on it and then whole content will be display so, my question is that: How to not letting user click on that ... because i want user to click on cell then i will show another view and display whole content there?
How can i achieve something like this? Thank in advance.
This is how i set UITextView
lazy var categoryShortDetailLabel: ReadMoreTextView = {
let label = ReadMoreTextView()
label.font = UIFont(name: "SFCompactText-Regular", size: 16)
label.textColor = .black
label.isEditable = false
label.isSelectable = false
label.maximumNumberOfLines = 3
label.shouldTrim = true
label.attributedReadMoreText = NSAttributedString(string: "...")
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
Looking at the code here, I found that, the ReadMoreTextView is meant to provide you the feature like, ReadMore and ReadLess for the larger texts in textView.
However your requirement is to stop that functionality. Now, if you take a look at the code here, you will get the idea, that the function shoreMoreText and it's a private function so, can't override it. and this function is expanding the texts and setting the numberOfLines to zero. so, what you can do is, comment the code within and return from function to stop doing the action. Also as the ReadMoreTextView is Licensed as MIT(Read licence here) so, it's okay to modify the code.
private func showMoreText() {
return
/*if let readLessText = readLessText, text.hasSuffix(readLessText) { return }
shouldTrim = false
textContainer.maximumNumberOfLines = 0
if let originalAttributedText = _originalAttributedText?.mutableCopy() as? NSMutableAttributedString {
attributedText = _originalAttributedText
let range = NSRange(location: 0, length: text.count)
if let attributedReadLessText = attributedReadLessText {
originalAttributedText.append(attributedReadLessText)
}
textStorage.replaceCharacters(in: range, with: originalAttributedText)
}
invalidateIntrinsicContentSize()
invokeOnSizeChangeIfNeeded()*/
}
Try and share your results.
Hope it helps!

Attributed string cutting and displaying single word into two lines on UILabel

I'm creating attributed text using following attributes,
func attributedString(font: UIFont, contentColor: UIColor, alignment: NSTextAlignment) -> NSAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 0.6
paragraphStyle.lineHeightMultiple = 0.8
paragraphStyle.alignment = alignment
paragraphStyle.lineBreakMode = .byWordWrapping
let lineSpacingAttribute: [NSAttributedStringKey: Any] = [NSAttributedStringKey.paragraphStyle: paragraphStyle, NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: contentColor]
let attributedString = NSAttributedString(string: self, attributes: lineSpacingAttribute)
return attributedString
}
I'm displaying this text on UILabel inside a custom tableViewCell. But, it is cutting a single word into two (cutting last letter of a word and displaying it on next line). I've set the numberOfLines to zero, and preferredMaxLayoutWidth for label. And I'm using a custom font.
This problem is happening on small screens only, iPhone SE and iPhone 5S simulators. But, on other simulators it is displaying correctly. Could you please help me to figure out what is wrong in this?
Thanks!
From Apple doc:
var preferredMaxLayoutWidth: CGFloat
This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text flows to one or more new lines, increasing the height of the label.
Depending on your text you can use the adjustsFontSizeToFitWidth property with the minimumScaleFactor property

How can I vertically align my status bar item text?

Left one on the picture is the date and time from Apple and one is my application one. As you may see the text of my application appears lower than the Apple one. Which doesn't look pretty. How can this be resolved?
self.statusBarItem.image = nil
self.statusBarItem.button?.imagePosition = .NoImage
self.statusBarItem.button?.title = "Sun 5 Jun 13:35"
You could do it in offset. You cannot do it like this since it needs to be done on the status item button bar.
button.frame = CGRectMake(0.0, 0.5, button.frame.width, button.frame.height)
I wanted to make a quick addition to this. While the accepted answer does indeed work based on the context of the question. It will not work if you have an image, as this moves everything (image and text). I have found for some reason, the image is vertically centered, but the text is not.
What you actually want to do in that case is set NSAttributedString.Key.baselineOffset, where you derive the baseline value as follows
var displayScale: CGFloat = 1.0
let pstyle = NSMutableParagraphStyle()
pstyle.alignment = .center;
let aStr = NSAttributedString(string: str, attributes: [NSAttributedString.Key.paragraphStyle: pstyle, NSAttributedString.Key.font: font])
if let main = NSScreen.main {
displayScale = main.backingScaleFactor
if displayScale <= 0.0 {
displayScale = 1.0
}
}
let textHeight = aStr.size().height
baselineOffset = ((font.ascender - font.descender) - textHeight) / displayScale
button.attributedTitle = = NSAttributedString(string: str, attributes: [NSAttributedString.Key.paragraphStyle: pstyle, NSAttributedString.Key.baselineOffset: baselineOffset, NSAttributedString.Key.font: font])
Disclaimers here are that I'm not completely sure about the displayScale part. I theorize this is needed to correct for pixels/points.
I've only added this answer because I was struggling to find a good answer for this. I got my inspiration to do this based on this: Center two fonts with different different sizes vertically in an NSAttributedString
If this technique is wrong, I'd be interested to know so I can fix it.

How to insert Custom Label with text into View with Animation?

Im making a small boxing app. This whole week iv been trying to work out how to solve my current problem above, with no luck :(.
Summary
Basically Its a 1 v 1 game. Each time the user hits the other player I want to make a tiny number pop up near him and float up and dissappear.
Its sort of like when you play MMORPG's and when you do dmg you see how much you did. See image below for an example!
So basically everytime the user hits the other player I want a little number to pop up on the screen to show the dmg and then float up and disappear.
Details
I am building the game on a simple UIView
The label is a UILabel
Anywhere How I can achieve this?
Thank you!
Create a label, then use UIView.animateWithDuration to animate it.
let label = UILabel(frame: CGRect(origin: point/*The point where you want to add your label*/, size: CGSize(width: 50, height: 50)))
label.text = "+1"
label.font = UIFont()//Your font
label.textColor = UIColor.blueColor()
label.alpha = 1
self.view.addSubview(label)
UIView.animateWithDuration(1) {
label.center = CGPoint()//The point where you want your label to end up
label.alpha = 0
}
Edit: As mentioned in the comments, you asked for how to create the label at a random point. Try this:
let screenWidth = self.view.frame.width
let screenHeight = self.view.frame.height
let randomX = CGFloat(arc4random_uniform(UInt32(screenWidth)))
let randomY = CGFloat(arc4random_uniform(UInt32(screenHeight)))
let point = CGPoint(x: randomX, y: randomY)
As you will notice, for the width and height, I use the view's frame's width and height. You may want to use the view's bounds. For more on this, check out this SO Post.

NSTextView: apply paragraph style

I'm trying to apply the default paragraph style to a NSTextView but it doesn't seem to work. Any idea?
var paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle();
paragraphStyle.lineSpacing = 100.0;
paragraphStyle.firstLineHeadIndent = 100.0;
WLMainEditor.defaultParagraphStyle = paragraphStyle;
I find that it always works best to start with an existing paragraph style and make changes to it. If you don't have one to start with, use NSParagraphStyle.default()
let paragraphStyle = NSParagraphStyle.default().mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.lineSpacing = 100
paragraphStyle.firstLineHeadIndent = 100
WLMainEditor.defaultParagraphStyle = paragraphStyle
Also, at least in this code snippet, the paragraphStyle can (and should be) a let instead of a var since it's an Objective-C mutable object and not a Swift mutable collection.