Row: minimum borders for maximum height

I want to calculate the minimum borders of the rectangle needed to set a line (multi-line line) with a specific font.

It should look something like this:

FROM: ---------------------------------- |Sent when the application is about| |to move from active to inactive | |state. | ---------------------------------- TO: ------------------------- |Sent when the application| |is about to move from | |active to inactive state.| ------------------------- 

As you can see, the height remains the same, the width changes to the minimum value.

Initially, I could use boundingRectWithSize (limit to the maximum width) to first get the required minimum height, and then call boundingRectWithSize (limit to the estimated height) to get the width. But this leads to incorrect results when calculating the width in the second step. It does not take into account the maximum height, but just calculates the width for one line.

After that, I found a way to get the correct result, but the execution of this code takes a very long time, which makes it useless for me:

First calculate the required rectangle for the width of the constraint:

 var objectFrame = Class.sizeOfString(string, font: objectFont, width: Double(width), height: DBL_MAX) 

then width:

 objectFrame.size.width = Class.minWidthForHeight(string, font: objectFont, objectFrame.size.height) 

via:

 class func minWidthForHeight(string: NSString, font: UIFont, height: CGFloat) -> CGFloat { let deltaWidth: CGFloat = 5.0 let neededHeight: CGFloat = rect.size.height var testingWidth: CGFloat = rect.size.width var done = false while (done == false) { testingWidth -= deltaWidth var newSize = Class.sizeOfString(string, font: font, width: Double(testingWidth), height: DBL_MAX) if (newSize.height > neededHeight) { testingWidth += deltaWidth done = true } } return testingWidth } class func sizeOfString(string: NSString, font: UIFont, width: Double, height: Double) -> CGRect { return string.boundingRectWithSize(CGSize(width: width, height: height), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) } 

It gradually calculates the height for the given width (- 5.0 pixels for each new step) and checks if the height remains. As soon as the height changes, it returns the width of the previous step. So now we have a bounding box where the line for a particular font fits perfectly without any wasted space.

But, as I said, it takes a very long time to calculate, especially when you do this for many different lines at the same time.

Is there a better and faster way to do this?

+6
source share
1 answer

So, this code below is my last approach to the question. This is pretty fast and works well for me. Thanks @Nero for being on the right track.

 class func minFrameWidthForHeight(string: NSString, font: UIFont, rect: CGRect) -> CGFloat { if (string.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).count <= 1) { return rect.size.width } var minValue: CGFloat = rect.size.width / 2 var maxValue: CGFloat = rect.size.width var testingWidth: CGFloat = rect.size.width var lastTestingWidth: CGFloat = testingWidth let neededHeight: CGFloat = rect.size.height var newSize = rect while (newSize.height <= neededHeight) { lastTestingWidth = testingWidth testingWidth = (maxValue + minValue) / 2 newSize = CalculationHelper.sizeOfString(string, font: font, width: Double(testingWidth), height: DBL_MAX) if (newSize.height <= neededHeight) { maxValue = testingWidth } else { minValue = testingWidth } } return lastTestingWidth } 
-1
source

Source: https://habr.com/ru/post/979709/


All Articles