56

I have a UITextView for text editing. By default, it has a small margin around the text. I want to increase that margin by a few pixels.

The contentInset property gives me margins, but it does not change the text "wrap width". The text is wrapped at the same width, and the extra "margin" just causes the view to scroll horizontally.

Is there a way to make a UITextView of a certain width display the text with a narrower "wrap width"?

Peter Hosey
  • 93,914
  • 14
  • 203
  • 366
strawtarget
  • 1,029
  • 2
  • 9
  • 18
  • For more detailed answer of this question refer this answer https://stackoverflow.com/questions/3727068/set-padding-for-uitextfield-with-uitextborderstylenone?page=2&tab=oldest#tab-top – Bhavin_m Jul 31 '18 at 10:46

9 Answers9

116

Starting from iOS 7 you can use textContainerInset property:

Objective-C

textView.textContainerInset = UIEdgeInsetsMake(0, 20, 0, 20);

Swift

textView.textContainerInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
Karlis
  • 1,580
  • 1
  • 12
  • 12
  • 3
    Also possible to add only left and right _textContainerInsets_. `textView.textContainerInset.left = 20 textView.textContainerInset.right = 20` – Abduhafiz Apr 29 '18 at 10:18
34

After fiddling around with this for a while I found another solution if you're only developing for iOS 6. Set the top and bottom margins with contentInset:

textView = [[UITextView alloc] init];
textView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 20.0, 0.0);

For the left and right margins don't add your plain text right away but use an NSAttributedString instead with properly set left and right indents with an NSMutableParagraphStyle:

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.headIndent = 20.0;
paragraphStyle.firstLineHeadIndent = 20.0;
paragraphStyle.tailIndent = -20.0;

NSDictionary *attrsDictionary = @{NSFontAttributeName: [UIFont fontWithName:@"TrebuchetMS" size:12.0], NSParagraphStyleAttributeName: paragraphStyle};
textView.attributedText = [[NSAttributedString alloc] initWithString:myText attributes:attrsDictionary];

This gives you a UITextView with your text (in my case from the variable myText) with 20 pixels padding that properly scrolls.

10

Try this

UIBezierPath* aObjBezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 20, 20)];
txtView.textContainer.exclusionPaths  = @[aObjBezierPath];
Rajesh
  • 948
  • 7
  • 13
7

You could just use a smaller UITextView, and place a UIView in the background to simulate the padding.

+----------+
|          | <-- UIView (as background)
|   +--+   |
|   |  | <---- UITextView
|   |  |   |
|   +--+   |
|          |
+----------+
kennytm
  • 469,458
  • 94
  • 1,022
  • 977
  • 1
    Yeah, that's what I'm doing now. Works okay for the side margins, but the top margin has issues. From the user's perspective, text gets "cut off" at the top while scrolling because text only renders in the UITextView. – strawtarget Jul 14 '10 at 16:31
  • 5
    And you can not properly show the vertical scroll bar this way. – an0 Jan 04 '12 at 14:16
  • Setting `textView.clipsToBounds = NO` will "fix" the cutting off at the top, sort of. Of course, this will not help with showing the vertical scroll bar correctly. – villapossu Sep 17 '13 at 00:11
3

if you want to set padding from one side, you can use below code:

 textView.contentInset.left = 5 //For left padding
 textView.contentInset.right = 5 //For right padding
 textView.contentInset.top = 5 //For top padding
 textView.contentInset.bottom = 5 //For bottom padding
Pankaj Jangid
  • 626
  • 7
  • 17
1

This is working for me. Changing the textView contentInset and frame inset/position to get the correct padding and word wrap. Then changing the textView bounds to prevent horizontal scrolling. You also need to reset the padding each time the text is selected and changed.

- (void)setPadding
{
    UIEdgeInsets padding = UIEdgeInsetsMake(30, 20, 15, 50);

    textView.contentInset = padding;

    CGRect frame = textView.frame;

    // must change frame before bounds because the text wrap is reformatted based on frame, don't include the top and bottom insets
    CGRect insetFrame = UIEdgeInsetsInsetRect(frame, UIEdgeInsetsMake(0, padding.left, 0, padding.right));

    // offset frame back to original x
    CGFloat offsetX = frame.origin.x - (insetFrame.origin.x - ( padding.left + padding.right ) / 2);
    insetFrame = CGRectApplyAffineTransform(insetFrame, CGAffineTransformMakeTranslation(offsetX, 0));

    textView.frame = insetFrame;

    textView.bounds = UIEdgeInsetsInsetRect(textView.bounds, UIEdgeInsetsMake(0, -padding.left, 0, -padding.right));

    [textView scrollRectToVisible:CGRectMake(0,0,1,1) animated:NO];
}

-(void)textViewDidChangeSelection:(UITextView *)textView
{
    [self setPadding];
}

-(void)textViewDidChange:(UITextView *)textView
{
    [self setPadding];
}
Nate Potter
  • 3,170
  • 2
  • 19
  • 24
  • @Nate this doesn't work for me. The textview still scrolls horizontally and the content inset flushes outside of the frame of the text view – GoGreen Mar 24 '14 at 06:44
1

Thanks for the suggestions. I had this problem when developing a macOS / OSX app and ended up with this:

textView.textContainerInset = NSSize(width: 20, height: 20); //Sets margins
1

Try below code

For iOS7 use textContainerInset

textView.textContainerInset = UIEdgeInsetsMake(0, 20, 0, 20);

Check below link it might be useful to you

https://stackoverflow.com/a/22935404/5184217

Rajesh Dharani
  • 277
  • 4
  • 19
0

Swift + iOS 12: A different approach

Setting padding to the left + right side of our UITextView did let the text disappear when entered more that 9 lines of text. Using the solution of @rajesh helped to solve this issue:

Make sure to invoke the method whenever text did change + the device rotates.

    /// Updates the left + right padding of the current text view.
    /// -> leftRightPadding value = 11.0
    func updateLeftRightPadding() {
        let leftPadding = UIBezierPath(rect: .init(x: 0.0, y: 0.0,
                                       width: leftRightPadding, height: contentSize.height))
        let rightPadding = UIBezierPath(rect: .init(x: frame.width - leftRightPadding, y: 0.0,
                                        width: 11, height: contentSize.height))
        textContainer.exclusionPaths = [leftPadding, rightPadding]
    }
Baran Emre
  • 2,296
  • 1
  • 17
  • 20