3

I am using a UITextView to enter some rich text. I have created a button to change the paragraph alignment (left, center, right).

I am applying the alignment to the attributedText when the user selects some text and it works as expected.

However, when the user hit return and is in a new, zero-length paragraph (just after a newline and nothing following), I believe I should change the typingAttributes to reflect the attributes I want the new text to receive.

I used the following code:

if ((paragraphRange.length == 0) && (paragraphRange.location == [mutableText length])) {

    NSMutableParagraphStyle * mutableParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];

    [mutableParagraphStyle setAlignment:textAlignment];
    [mutableParagraphStyle setLineBreakMode:NSLineBreakByWordWrapping];

    NSMutableDictionary * attributes = [self.typingAttributes mutableCopy];
    [attributes setObject:mutableParagraphStyle forKey:NSParagraphStyleAttributeName];
    self.typingAttributes = attributes;

It does apply the paragraph alignment once the character is typed, but the cursor in the UITextView does not reflect the change until after the character is typed. I am looking for a mechanism to get the cursor into the right place before the text is typed. For example, if the user selects 'centered', I want the cursor to move to the center of the view to show where the text will do.

Anyone have any ideas on how to do this?

Thanks in advance,

Charlie

Charlie
  • 310
  • 2
  • 14

4 Answers4

1

Here is how I am doing it and this causes the cursor to move immediately. I think the key is to set the attribute on the whole paragraph. There does seem to be a bug where sometimes the cursor does not move but if you scroll the textview then that causes it to move. Seems to only occur near the top of the uitextview (lines 1 - 5) and if the two styles use the same font size.

There is a similar bug if you select text and change it to or from bold the selected area is not resized to reflect the new width of the changed text. Also if you programatically change the Font to bold for a paragraph then the cursor position is not updated to fit the changed width of the text. However if you also change the text point size the cursor is correctly repositioned for the next text width.

/*! Applies the Normal style to the range returned by [self rangeForUserParagraphAttributeChange]

    @param sender The id of the control sending the message.
 */
- (IBAction) styleNormal:(id)sender
{
    FLOG(@"styleNormal called");
    NSRange charRange = [self rangeForUserParagraphAttributeChange];
    if (charRange.location == NSNotFound) return;
    NSTextStorage *myTextStorage = [self textStorage];

    if ([self isEditable] && charRange.location != NSNotFound)
    {
        [myTextStorage beginEditing];
        [myTextStorage setAttributes:[self normalStyle] range:charRange];
        [myTextStorage endEditing];
    }
    [self setTypingAttributes:[self normalStyle]];
}
- (NSRange)rangeForUserParagraphAttributeChange {
    NSRange paragaphRange = [self.textStorage.string paragraphRangeForRange: self.selectedRange];
    return paragaphRange;
}
Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76
  • This does not really answer my question. I am looking at the case when the user has selected the end of the text input (or there is no text yet in the textfield). This creates a range that would cause an exception if applied using setAttributes. Perhaps your function 'rangeForUserParagraphAttributeChange' returns something different (NSNotFound) when at the end of the input. But if that is the case, then this code would do nothing based on the conditional return in the middle of the code. – Charlie Nov 30 '13 at 14:22
  • When I have a paragraph to apply the attribute to, I do ensure that I use the entire paragraph and that part works. It is when I don't have a paragraph to apply the change to, then I have a problem. Setting typingAttributes does not seem to cause the cursor to move but the next character typed does get the right position (causing a jump of the cursor when the character is entered). – Charlie Nov 30 '13 at 14:25
  • @Charlie, sorry, just added that method for you. – Duncan Groenewald Nov 30 '13 at 21:17
  • Can you confirm that the cursor moves to the middle of the view you have it at the end of the input (nothing selected) and change the paragraph alignment to 'centered'? I've used your code to try to address this but it does nothing until I enter the next character. I go to the end of a paragraph, hit return to be in a new paragraph with nothing in it, then hit the 'center' button. The cursor stays at the left side of the view. Type a space, and the cursor jumps to the middle of the view (plus one space). Adding in the [myTextStorage endEditing] did not have any effect for me. – Charlie Dec 04 '13 at 00:46
  • Yes @Charlie it works if the textView is empty - select All and delete so the view is empty, then set the style. Hit return key so at the beginning of a new paragraph with no text typed yet. Move cursor to last character in a paragraph. As I said there does appear to be a bug so try entering a few empty lines (say 5 or 6) and then try again - I found the cursor would not position correctly in the first few lines but below that seems to work OK. – Duncan Groenewald Dec 04 '13 at 00:58
  • Also check if you have the same issue when making text BOLD. I find the text selection area does not get adjusted correctly so my guess is these are bugs. – Duncan Groenewald Dec 04 '13 at 01:02
  • Also try scrolling the view (if you can) when the cursor has failed to move, I find that if I do this then the cursor jumps to the right spot even if no text has been entered. – Duncan Groenewald Dec 04 '13 at 01:03
  • BTW I use the exact same code on OS X in NSTextView and it works correctly all the time. I did submit a bug to Apple on this. – Duncan Groenewald Dec 04 '13 at 01:10
1

For those tracking this, it looks like this is a bug in iOS7. The renderer does not appear to take into account the state of the typingAttributes paragraph alignment when computing the location of the cursor.

Looks like this one needs a bug report to Apple ;-)

Charlie
  • 310
  • 2
  • 14
  • mitigate the problem by using [textView setNeedsLayout] as per Chen Lim pointed out. – Damo Sep 25 '14 at 07:46
1

Did you try resigning the textView as first responder, then making it first responder right after that.

[textView resignFirstResponder];
[textView becomeFirstResponder];
Peter Robert
  • 1,292
  • 11
  • 18
1

Calling [textView setNeedsLayout] seems to fix the cursor location.

Chen Lim
  • 738
  • 7
  • 10
  • thanks - it seems that changing some aspects of a UITextView are reflected correctly but justification isn't one of them and setNeedsLayout is required! Solved my problem +1 – Damo Sep 25 '14 at 07:45