IOS text paging method example

Time:2021-9-22

preface

This article will be divided into two parts, one is static text paging, the other is dynamic text paging, that is, text paging while filling in the text

The scheme we adopt is: textkit for processing, and get the text range that can be accommodated in the text content view through the glyphrangefortextcontainer method to cut and page the text

// Returns the range of characters which have been laid into the given container.  This is a less efficient method than the similar -textContainerForGlyphAtIndex:effectiveRange:.
– (NSRange)glyphRangeForTextContainer:(NSTextContainer *)container;

Static text paging

1. Text view configuration

1.1 setting textcontainer

  • Set the size of textcontainer to the view size
  • Set linefragmentpadding to 0 so that the distance between both sides of the text and the view is 0, which makes the calculation more accurate
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, originY, kTextViewSize.width, kTextViewSize.height)];
 //The maximum height of textcontainer. The actual generated view height will be smaller than this value
 textView.textContainer.size = CGSizeMake(CGRectGetWidth(textView.bounds), CGRectGetHeight(textView.bounds));
 //Set the left and right spacing of text content to 0
 textView.textContainer.lineFragmentPadding = 0.f;

1.2 basic settings of text view

Set the space between the top and bottom of the text to 0, so that the text can fill the view


 textView.textContainerInset = UIEdgeInsetsZero;

Set continuous layout of text view

//Allow continuous layout
 textView.layoutManager.allowsNonContiguousLayout = NO;

1.3 complete configuration of text view

UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, originY, kTextViewSize.width, kTextViewSize.height)];
 textView.backgroundColor = [UIColor yellowColor];
 textView.textColor = [UIColor blackColor];
 //The maximum height of textcontainer. The actual generated view height will be smaller than this value
 textView.textContainer.size = CGSizeMake(CGRectGetWidth(textView.bounds), CGRectGetHeight(textView.bounds));
 //It is necessary to set the text content filling area to 0 for more accurate calculation
 textView.textContainerInset = UIEdgeInsetsZero;
 //Set the left and right spacing of text content to 0
 textView.textContainer.lineFragmentPadding = 0.f;
 textView.text = text;
 textView.font = [UIFont systemFontOfSize:16];
 //Allow continuous layout
 textView.layoutManager.allowsNonContiguousLayout = NO;
 textView.userInteractionEnabled = NO;
 textView.contentSize = textView.bounds.size;

2. Text view data configuration

Get the text range that can be accommodated through glyphrangefortextcontainer, and then cut out the text to obtain the content that can be displayed by the view

//Gets the range of text that the text view can accommodate
 NSRange textRange = [textView.layoutManager glyphRangeForTextContainer:textView.textContainer];
 NSString *textViewText = [text substringWithRange:textRange];
 textView.text = textViewText;

3. Key code display

Get text data and intercept the text section by section to achieve paging

NSString *text = @ "Once, at a party I attended, the host asked a little boy: what kind of person do you want to be when you grow up? Children look at us entrepreneurs and say: be an entrepreneur. The people present suddenly laughed and clapped. I clapped my hands too, but it didn't sound comfortable. I think, how much does this child know about the enterprise? Did he say he wanted to be an entrepreneur in front of us? Is he influenced by adults to think that entrepreneurs are beautiful and rich people who want to be entrepreneurs? Of course, all this is a mystery. But anyway, as a person's life ambition, I don't think what to be is important; No matter who it is, the most important thing is to be a hardworking person when I was a child \ n when I was a child, someone asked the same question. My answer was nothing more than being a teacher, the people's Liberation Army and a scientist. Time has passed for more than 20 years. The children of those years are now adults in their early 40s. But when you think about it carefully, none of the aspirations I expressed in front of adults have actually come true. The others around me are almost the same. Some want to be teachers, but later they become self-employed; Someone who wants to be a PLA prisoner. When I was in college, I had two classmates and friends. They are now talented people in China's electronics industry. One is the boss of Konka Group and the other is leading TCL group. The three of us unexpectedly became the operators of China's color TV backbone enterprises, but when we graduated from college, no matter how much imagination we had, we didn't dare to think that we would be what we are now in more than ten years. Everything is achieved through our efforts step by step. We are not so much people with ideals as people who have been working hard\ N it's not that we don't pay attention to ideals, but because it's easy to set ambitions and difficult to work for them. Life has been like this since ancient times. Who would have thought that today, more than ten years ago, I was a person who wandered in the streets and worried about survival? At that time, I had nothing and had no future. I really didn't know where the road was. However, I was not discouraged and disappointed. In retrospect, it was my will and character that supported me through these rough years. When many people think I can't and should not, I still try to get up from the ground. I firmly believe that life is like Maradona playing football. I often get vitality by "scoring" when I'm about to fall. In fact, just when "mountains and rivers have no way out", the collapse of an enterprise in Hong Kong gave me the opportunity to make a comeback, enabling me to cooperate with British scientific and technological personnel who master the latest technology in the world to develop technologically advanced color TV sets, and then get out of the dilemma at one fell swoop\ N some people say that "effort" and "possession" are two landscapes of life. But I think the most beautiful scenery in life should be hard work. Effort is a kind of spiritual state of life and a kind of love for life. Effort is the mother of possession, and possession is the son of effort. All roads lead to Rome with one heart and one mind. All one wants is narrow roads and narrow heaven and earth. Therefore, instead of stipulating what kind of person you must become and what things you get, it's better to train yourself to be an hardworking person. No matter how high the ambition is, it is difficult to stick to it without effort; There is no great goal, because efforts will eventually find the direction of struggle. It can be said that being a hard worker is the most practical goal and the greatest realm of life\ N many people become disheartened because their goals are too high and utilitarian, and they are finally discouraged and disappointed because they are difficult to succeed. The reason is often that people pay too much attention to ownership and neglect to make efforts. For today's children, if we only focus on what kind of people they should be in the future and do not put forward the will quality as a goal of life, we can only cultivate narrow, selfish, fragile and low-level people in the end. Unfortunately, we have not done so satisfactorily in this regard. ";
 while (text.length > 0) {
  //Add a text view display and get the remaining text
  text = [self addTextViewWithText:text originY:originY];
 }
- (NSString *)addTextViewWithText:(NSString *)text originY:(CGFloat)originY {
 UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, originY, kTextViewSize.width, kTextViewSize.height)];
 ......
 
 ......
 ......
 //Gets the range of text that the text view can accommodate
 NSRange textRange = [textView.layoutManager glyphRangeForTextContainer:textView.textContainer];
 NSString *textViewText = [text substringWithRange:textRange];
 textView.text = textViewText;
 [self.scView addSubview:textView];
 
 //Gets the remaining text that cannot be accommodated
 NSString *remainText = [text substringFromIndex:NSMaxRange(textRange)];
 return remainText;
}

Effect display

Dynamic text paging

The content we want to achieve here is: fill in the content in the text box, and the content will be paged dynamically with the increase of text. In fact, most of the content here is consistent with the static text paging. The difference is that multiple text boxes can be edited, That is, the previous text box will affect the content display of the next text box, as well as the processing of marktext text when there is special processing for writing Pinyin

1. Initial state

We will have a text box that can be filled in. We will fill in the text box and add the redundant text to the new text box for display

2. Completion status

3. Key code display

Let’s do the following in the proxy method of textviewdidchange

3.1 obtain the actual height of the text to judge whether to page

CGFloat realHeight = [textView sizeThatFits:CGSizeMake(CGRectGetWidth(textView.bounds), MAXFLOAT)].height;
 
 //Determine whether paging is required
 if (realHeight <= textViewSize.height) {
  return;
 }
 
 //Paging
 ......
 ......

3.2 there is a special processing for writing Pinyin, which is the processing of marktext text

Here we can see that there is marktext when the text box is Pinyin. At this time, we need to deal with this special case

We temporarily increase the height of textcontainer to accommodate marktext text, and then adjust it back to the original height

//Get the mark text and related position size
  NSString *markText = [textView textInRange:textView.markedTextRange];
  NSInteger location = [textView offsetFromPosition:textView.beginningOfDocument toPosition:textView.markedTextRange.start];
  NSRange markTextRange = NSMakeRange(location, markText.length);
  NSString *primaryLang = [[textView textInputMode] primaryLanguage];
  
  BOOL isZHHans = [primaryLang isEqualToString:@"zh-Hans"];
  
    //Judge whether it is in pinyin
  if (isZHHans && markTextRange.length != 0) {
    //Temporarily raise the container height
    textView.textContainer.size = CGSizeMake(textViewSize.width, realHeight);
    BOOL isContainENCharacter = NO;
    for (int i = 0; i < markText.length; ++i) {
      unichar character = [markText characterAtIndex:i];
      NSString *string = [NSString stringWithCharacters:&character length:1];
      if ([string isLetter]) {
        isContainENCharacter = YES;
        break;
      }
    }
    
    if (isContainENCharacter) {
      return;
    }
  }
  
  //Return to original size
  textView.textContainer.size = textViewSize;

3.3 pagination of text


NSRange range = [textView.layoutManager glyphRangeForTextContainer:textView.textContainer];
textView.text = [textViewText substringWithRange:range];

[self handleBelowTextViewWithAboveTextView:textView totalText:[textViewText substringFromIndex:textView.text.length]];

Here, we cannot determine whether the text only affects the next text box, so we will recursively execute this method until the last text is no longer redundant

- (void)handleBelowTextViewWithAboveTextView:(UITextView *)textView totalText:(NSString *)textViewText {
  NSInteger sectionIndex = textView.tag - kMarkTag;
  //Determine whether the next view already exists
  UITextView *belowTextView = [self.scView viewWithTag:kMarkTag + sectionIndex + 1];
  if (belowTextView) {
    //Add the original text to the back
    NSString *oriText = belowTextView.text;
    NSMutableString *mString = [[NSMutableString alloc] initWithString:textViewText];
    [mString appendString:oriText];
    belowTextView.text = mString.copy;
  } else {
    belowTextView = [self contentTextViewWithIndex:++sectionIndex];
    belowTextView.text = textViewText;
  }
  
  [self.scView addSubview:belowTextView];
  self.scView.contentSize = CGSizeMake(self.scView.bounds.size.width, CGRectGetMaxY(belowTextView.frame));
  
  CGFloat realBelowHeight = [belowTextView sizeThatFits:CGSizeMake(CGRectGetWidth(belowTextView.bounds), MAXFLOAT)].height;
  if (realBelowHeight <= belowTextView.bounds.size.height) {
    [belowTextView becomeFirstResponder];
    return;
  }
  
  belowTextView.textContainer.size = belowTextView.bounds.size;
  NSRange range = [belowTextView.layoutManager glyphRangeForTextContainer:belowTextView.textContainer];
  NSString *currentTmpBelowText = belowTextView.text;
  belowTextView.text = [currentTmpBelowText substringWithRange:range];
  NSString *remainText = [currentTmpBelowText substringFromIndex:belowTextView.text.length];
  
  //Execute the method again until there is no extra text
  [self handleBelowTextViewWithAboveTextView:belowTextView totalText:remainText];
}

summary

In general, our steps for text pagination:

  1. Judge whether the height of the text is higher than the height of the current text box. If not, pagination is not required
  2. Get the range position that the text box can hold through the method glyphrangefortextcontainer provided by textkit
  3. Intercept the text and perform the operation in step 2 again for the remaining text until paging is no longer possible

Well, the above is the whole content of this article. I hope the content of this article has a certain reference value for your study or work. Thank you for your support for developpaer.