10

I know the TextView is embedded in a ScrollView. And if there is a fairly long String(Which contains no "\n")

The TextView will automatically do the line-wrap, according to the width of the TextView.

If TextView's height is short, then we are able to scroll it vertically. How do you disable the auto line-wrap? Such that, if there are no "\n" encounters, it does not line wrap. Rather, it lets the user scroll horizontally to view the text.

How can I implement this?

Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
Microos
  • 1,728
  • 3
  • 17
  • 34
  • look at this http://stackoverflow.com/questions/15190000/uitextview-horizontal-scrolling – Saurabh Prajapati Oct 29 '15 at 06:44
  • @SaurabhPrajapati Thank you! I just saw your link! Because I just know the Swift, but nothing Object-C. So I meet another key problem which is how to get the length( means size.width ) of the text. I don't know how to interpret this step into Swift language: { CGFloat textLength = [titleView.text sizeWithFont:titleView.font constrainedToSize:CGSizeMake(9999, 50) lineBreakMode:NSLineBreakByWordWrapping].width } – Microos Oct 29 '15 at 07:05
  • just use this instead textLength = titleView.text.sizeWithAttributes([NSFontAttributeName: UIFont.systemFontOfSize(14.0)]) – Saurabh Prajapati Oct 29 '15 at 08:20
  • @SaurabhPrajapati string does not have this function( sizeWithAttributes) – Microos Oct 29 '15 at 08:26
  • (titleView.text as! NSString).sizeWithAttributes([NSFontAttributeName: UIFont.systemFontOfSize(14.0)]) – Saurabh Prajapati Oct 29 '15 at 08:29

4 Answers4

6

I figure out how to do this with many helps of you guys :D, thanks, and here we go!

1. So, firstly, We need a longlonglong String, right?

let displayStr = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 "

2. Assume we have a UIScrollView which is linked by @IBOutlet or got by calling the .viewWithTag(xxx) .We will let it be named as scroll :

3. It's time to get the size of our string, here is a key function we'll use it:

Oh! I almost forget to define what kind of Font( this's a crucial parameter ) we will use, and What is the max-size of our string's size

let maxSize = CGSizeMake(9999, 9999)
let font = UIFont(name: "Menlo", size: 16)!
//key function is coming!!!
let strSize = (displayStr as NSString).boundingRectWithSize(maxSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName : font], context: nil)

4. OK, now we can put the string into a textView, you need to programmatically create a new UITextView, so that we can define the frame which is identical to the string's size(Oh, maybe a little bigger :D) :

let frame = CGRectMake(0, 0, size.width+50, size.height+10)
let textView = UITextView(frame: frame)
textView.editable = false
textView.scrollEnabled = false//let textView becomes unScrollable
textView.font = font
textView.text = displayStr

5. Back to our scroll, we will set its contentSize:

scroll.contentSize = CGSizeMake(size.width, size.height)

6. Finally, addSubview: scroll.addSubview(textView)

You can see, textView is embed in a scrollView, which allow it to scroll with 2 directions.

B.T.W. My implement is just a demo for static String. if you want user to use a textView which will not line wrap if he doesn't input any "\n", you may need dynamically calculate the string size. :D

[I hope this will help]

Microos
  • 1,728
  • 3
  • 17
  • 34
0
  1. [myTextView setContentSize:CGSizeMake(width, myTextView.frame.size.height)];

The width of the content extends past the width of the textView's frame or else it won't scroll.

  1. Turn off all the scroll options on the UITextView, then embed it in another UIScrollView. Reference:- DualScrollTextView
pkc456
  • 8,350
  • 38
  • 53
  • 109
0
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var textView: UITextView!

var yourText: String = "Whatever your text is going to be." 

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()
    self.scrollView.layoutIfNeeded()
    self.scrollView.contentSize = self.textView.bounds.size

}


override func viewDidLoad() {
    super.viewDidLoad()

textView.text = yourText

    textView.sizeThatFits(CGSizeMake(textView.frame.size.width, 80)) //height to equal the actual size of your text view.

}

I think this should plug and play, but I know for sure that textView.sizeThatFits works. You have to make sure that you constrain your text view to it's parent scrollview for it to work. (Leading, Trailing, Top, Bottom and the Height.)

Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
  • Thank you for your answer! I will try it soon, and I have to admit that your answer seems to be more efficient than mine. Thank you a lot! b.t.w I noticed that this is your first-time answering, wish you have a pretty journey in StackOverflow :D – Microos Jan 13 '16 at 02:56
  • Has anyone tried implementing this? Doesn't seem to work. – kemicofa ghost Nov 08 '16 at 08:32
0

The accepted answer didn't work with AutoLayout so I'll share my approach:

1. Add a UIScrollView with a UITextView inside it and pin all the edges for both of them

2. Add width and height constraints for your UITextView (doesn't matter what you set them to)

3. Create IBOutlets for the UITextView, the height constraint, and the width constraint

4. Uncheck 'Scrolling Enabled' on the TextView

5. When you update the text, calculate the bounding size of the text and update the height and width constraints with the bounding size

@IBOutlet weak var textView: UITextView!
@IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var textViewWidthConstraint: NSLayoutConstraint!

let displayText = "Your text here."

override func viewDidLoad() {
    super.viewDidLoad()

    let maxSize = CGSize(width: 10000, height: 30000)
    let textRect = displayText.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font : self.textView.font!], context: nil)

    self.textView.text = displayText
    self.textViewHeightConstraint.constant = textRect.height
    self.textViewWidthConstraint.constant = textRect.width
}

UPDATE: I discovered that this approach uses a lot of memory for large amounts of text (I was seeing over 1GB used). Here's how I reduced the memory impact from 1GB to 100MB:

1. Set the edge constraints just like step 1 above.

2. Add a width constraint to the TextView for the scrollable content width (I used 2000 but you can adjust it to your liking, the wider you go the more memory you'll use though).

3. Add a constraint to make the TextView and ScrollView have equal heights

That's it! The scrollable width will be constant and once you set the text for the TextView the scrollable height will automatically adjust.

Note: Some caveats of this approach:

  • The scrollable width will always be the width you set but you can use a hybrid approach with the first solution if you want to make it sized based on the text
  • You can't see the vertical scroll bar (unless you're scrolled all the way to the right) but it's possible to get it back by adjusting the scroll bar inset of the TextView.

Reference: https://www.ralfebert.de/ios-examples/auto-layout/uiscrollview-storyboard/

Lorenzo
  • 1,605
  • 14
  • 18