SoFunction
Updated on 2025-04-11

Swift instance code to set UILabel margins

summary

Although it is quite efficient to use it in a short time, it is impossible to use it easily without digesting the things you brought.

The idea of ​​exploration this time is to query the official documents, set different values ​​to test the changes in parameters in a single method, then test the execution order of the two methods, the processing ideas, and finally think about the summary.

When summarizing the processing logic of the method, use pseudo-code to sort out the execution ideas of the method. Avoid too much explanation of text and increase the cost of understanding.

Recently, I am learning about mini program development and have come into contact with flex layout. I like this fast and convenient way. So when you encounter a need to center text on a page, you want to process it directly on the UIlabel, and then set its inner margin on the UIlabel (similar to flex layout). Instead of putting a View first. Then place a UILabel control on this view, which is achieved by setting the distance of the UILabel control to the parent view.

Let’s look at the code implementation first. The following code is the solution after searching. If you just use it, just copy it to the project. You need to set textInsets before setting text

class SHLabel: UILabel {
​
   var textInsets: UIEdgeInsets = .zero
​
   override func drawText(in rect: CGRect) {
       (in: (by: textInsets))
   }
   
   override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
       
       let insets = textInsets
       var rect = (forBounds: (by: insets), limitedToNumberOfLines: numberOfLines)
       
        -= 
        -= 
        += ( + )
        += ( + )
       return rect
   }
}

Why can this method achieve inner margins?

Next, let’s sort out why this is achieved. First, check the developer documentation and see what these two methods do in the code block

function drawText(in rect: CGRect) textRect(forBounds bounds:, limitedToNumberOfLines numberOfLines) -> CGRect
title Draw text or shadow in rect area Returns the drawn rect area of ​​the text
detailed If you need to modify the drawing behavior in label, you need to rewrite this method. This method has been configured with the default environment and text color for drawing. In the rewritten method, you can customize the drawing method, then call super or draw it yourself. Rewrite this method before the system performs other text calculations (this is too difficult to understand). If you call sizeToFit() and sizeThatFits(_:) will trigger this method
Link /documentation/uikit/uilabel/1620527-drawtext /documentation/uikit/uilabel/1620545-textrect

After that, when verifying the execution order of these two methods and their respective functions, it is found that when the text of UILabel is assigned, the textRect method will be called first, and then the drawText method will be called.

textRect will be called again when the actual width of text rect is greater than the actual width of set UILabel. Of course, drawText is also called after two calls to textRect.

The role of textRect

Seeing this, it seems that you can understand the developer's documentation that rewrites this method before the system performs other text calculations. The purpose of this method is to first obtain the bounds of UILabel and the number of rows of text, calculate the rect area of ​​text by calling the super method, and return it to the system.

After multiple tests and verification, the execution logic (pseudocode) was discovered:

  // frame is the frame when setting UIlabel  if numberOfLines == 1 {
      textRect Being called
      return retc of width = text of widht
  } else {
      if text 文本of width < frame of width {
          text Rect Being called
          return retc of width = text of widht
      } else {
          text Rect Being called两次后
   
          by frame of wdith For limitations,Calculated text of height
          return rect of size = (frame of width,text of height)
      }
  }

The function of drawText

Look at the rect parameter in drawText, which is the rect returned by the textRect method. The actual drawing area of ​​the text text is implemented by overwriting the drawText method and calling its super method there.

After multiple verifications, the rect here is not exactly the rect returned in the textRect method. The relationship between them is (pseudocode):

  // frame is the frame that sets UILabel  // rect is returned by `textRect`  dx = 
  dy = 
  if  Confirm unchanged {
      dwidth = 
  } else {
      dwidth = 
  }
  if  Confirm unchanged {
      dheight = 
  } else {
      dheight = 
  }
   
  return drawText In-house rect(dx,dy,dwidth,dheight)

Question again: Why use this method to achieve inner margins?

After reading these two methods patiently, I have some ideas about the problems in the question. Then straighten out this idea.

First, determine a consensus, which is to set the inner margin of UILabel, determine the frame area of ​​UILabel and adjust the display area of ​​text. With this consensus, it will be easier to do next.

  • The first step is to use the textRect method to obtain the display area of ​​the text. The default display area of ​​the text is the same as the bounds area of ​​the UILabel.
  • Then we need to calculate the margin value we set ourselves to get the rect area of ​​the new text text.
  • Finally, use the drawText method to re-draw the rect area of ​​the text.

So why do we need to implement this method? Because at present, only these two methods are directly related to text text.

optimization

After doing so much theory, it’s time to output some real information.

If the UILabel's frame has been determined, it is important that width and height are determined. Then the textRect method does not need to be rewrite.

class SHLabel: UILabel {
​
   var textInsets: UIEdgeInsets = .zero
   override func drawText(in rect: CGRect) {
       (in: (by: textInsets))
   }
}

It can be seen here that when the height of the UILabel is uncertain, rewrite textRect to help determine the height of the UILabel. After verification, x and y in this method also do not need to be processed. When will it be used? I haven't encountered it yet.

class SHLabel: UILabel {
​
   var textInsets: UIEdgeInsets = .zero
​
   override func drawText(in rect: CGRect) {
       (in: (by: textInsets))
   }
   
   override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
       let insets = textInsets
       var rect = (forBounds: (by: insets), limitedToNumberOfLines: numberOfLines)
​
//        -= 
//        -= 
        += ( + )
        += ( + )
       return rect
   }
}

Extended

The article ends here. If you are a detailed control, you feel that textRect is called when it is needed or not. The drawText method is always called regardless of whether it is set or not to set the inner margin. Will it affect performance?

Here are two methods to solve:

  1. The operationality is to try to consider the needs and use it when you have to
  2. The psychological comfort nature is to let go. Think about it carefully, these two methods are both rewriting methods. What is the essence of rewriting? That is, do not execute your own method, but execute the rewrite method. In other words, even if the system does not follow the rewrite method, it must follow its own method. The impact of these codes on performance is not worth mentioning.

New discoveries

Suddenly, did you find out that we also seem to understand why UILabel can determine its height by itself and fully display the text text without fixing its height? You want to. Think about it carefully...

Summarize

This is the article about Swift setting UILabel margins. For more related content on Swift setting UILabel margins, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!