Skip to main content
added 223 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
extension String {
    
    static let blanks: [Character] = [" ", "\n", "\t"]
    
    func splitToFit (size: CGSize, using font: UIFont) -> [String] {
        var output: [String] = []
        var (fitted, remaining) = fit(self, in: size, using: font)
        var lastCount = fitted.count
        output.append(fitted)
        
        while remaining != "" {
            (fitted, remaining) = fit(remaining,
                                      in: size,
                                      using: font,
                                      lastCount: lastCount)
            lastCount = fitted.count
            output.append(fitted)
        }
        
        //Trim white spaces if needed
        //return output.map { $0.trimmingCharacters(in: .whitespacesAndNewlines)}
        return output
    }
    
    private func fit(
        _ str: String,
        in size: CGSize,
        using font: UIFont,
        lastCount: Int = 0) -> (String, String) {
        
        if !str.isTruncated(in: size, using: font) {
            return (str, "")
        }
        
        var low = 0
        var high = str.count - 1
        let lastValidIndex = high
        var substr = ""
        let step = lastCount/10  //Could be adjusted
        
        
        if lastCount != 0 {
            high = min(lastCount, lastValidIndex)
            while !str[0..<high].isTruncated(in: size, using: font) {
                low = high
                high = min(high + step, lastValidIndex)
            }
        }
        
        while low < high - 1 {
            let mid = (low + (high - low)/2 
            //Or more efficiently 
            //let mid = Int((UInt(low) + UInt(high)) >> 1)
            //Have a look here https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html
            
            substr = str[0..<mid]
            
            let substrTruncated = substr.isTruncated(in: size, using: font)
            
            if substrTruncated {
                high = mid
            } else  {
                low = mid
            }
        }
        
        substr = str[0..<low]
        
        while !String.blanks.contains(substr.last!) {
            substr.removeLast()
            low -= 1
        }
        
        let remains = str[low..<str.count]
        return (substr, remains)
    }
}
extension String {
    
    static let blanks: [Character] = [" ", "\n", "\t"]
    
    func splitToFit (size: CGSize, using font: UIFont) -> [String] {
        var output: [String] = []
        var (fitted, remaining) = fit(self, in: size, using: font)
        var lastCount = fitted.count
        output.append(fitted)
        
        while remaining != "" {
            (fitted, remaining) = fit(remaining,
                                      in: size,
                                      using: font,
                                      lastCount: lastCount)
            lastCount = fitted.count
            output.append(fitted)
        }
        
        //Trim white spaces if needed
        //return output.map { $0.trimmingCharacters(in: .whitespacesAndNewlines)}
        return output
    }
    
    private func fit(
        _ str: String,
        in size: CGSize,
        using font: UIFont,
        lastCount: Int = 0) -> (String, String) {
        
        if !str.isTruncated(in: size, using: font) {
            return (str, "")
        }
        
        var low = 0
        var high = str.count - 1
        let lastValidIndex = high
        var substr = ""
        let step = lastCount/10  //Could be adjusted
        
        
        if lastCount != 0 {
            high = min(lastCount, lastValidIndex)
            while !str[0..<high].isTruncated(in: size, using: font) {
                low = high
                high = min(high + step, lastValidIndex)
            }
        }
        
        while low < high - 1 {
            let mid = (low + high)/2
            
            substr = str[0..<mid]
            
            let substrTruncated = substr.isTruncated(in: size, using: font)
            
            if substrTruncated {
                high = mid
            } else  {
                low = mid
            }
        }
        
        substr = str[0..<low]
        
        while !String.blanks.contains(substr.last!) {
            substr.removeLast()
            low -= 1
        }
        
        let remains = str[low..<str.count]
        return (substr, remains)
    }
}
extension String {
    
    static let blanks: [Character] = [" ", "\n", "\t"]
    
    func splitToFit (size: CGSize, using font: UIFont) -> [String] {
        var output: [String] = []
        var (fitted, remaining) = fit(self, in: size, using: font)
        var lastCount = fitted.count
        output.append(fitted)
        
        while remaining != "" {
            (fitted, remaining) = fit(remaining,
                                      in: size,
                                      using: font,
                                      lastCount: lastCount)
            lastCount = fitted.count
            output.append(fitted)
        }
        
        //Trim white spaces if needed
        //return output.map { $0.trimmingCharacters(in: .whitespacesAndNewlines)}
        return output
    }
    
    private func fit(
        _ str: String,
        in size: CGSize,
        using font: UIFont,
        lastCount: Int = 0) -> (String, String) {
        
        if !str.isTruncated(in: size, using: font) {
            return (str, "")
        }
        
        var low = 0
        var high = str.count - 1
        let lastValidIndex = high
        var substr = ""
        let step = lastCount/10  //Could be adjusted
        
        
        if lastCount != 0 {
            high = min(lastCount, lastValidIndex)
            while !str[0..<high].isTruncated(in: size, using: font) {
                low = high
                high = min(high + step, lastValidIndex)
            }
        }
        
        while low < high - 1 {
            let mid = low + (high - low)/2 
            //Or more efficiently 
            //let mid = Int((UInt(low) + UInt(high)) >> 1)
            //Have a look here https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html
            
            substr = str[0..<mid]
            
            let substrTruncated = substr.isTruncated(in: size, using: font)
            
            if substrTruncated {
                high = mid
            } else  {
                low = mid
            }
        }
        
        substr = str[0..<low]
        
        while !String.blanks.contains(substr.last!) {
            substr.removeLast()
            low -= 1
        }
        
        let remains = str[low..<str.count]
        return (substr, remains)
    }
}
added 2 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18

Here is an alternative solution to split a string into a given size using a certain font :

If the story wasis too long, and to avoid blocking the main thread I would recommend adding subviews asynchronously to the UIScrollView as the fitted strings are calculated one by one.

Here an alternative solution to split a string into a given size using a certain font :

If the story was too long, and to avoid blocking the main thread I would recommend adding subviews asynchronously to the UIScrollView as the fitted strings are calculated one by one.

Here is an alternative solution to split a string into a given size using a certain font :

If the story is too long, and to avoid blocking the main thread I would recommend adding subviews asynchronously to the UIScrollView as the fitted strings are calculated one by one.

added 15 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18

If the story was too long, and to avoid blocking the main thread I would recommend adding subviews asynchronously to the UIScrollView as the fitted strings are calculated one by one.

If the story was too long, and to avoid blocking the main thread I would recommend adding subviews to the UIScrollView as the fitted strings are calculated one by one.

If the story was too long, and to avoid blocking the main thread I would recommend adding subviews asynchronously to the UIScrollView as the fitted strings are calculated one by one.

deleted 3 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 65 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 34 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 34 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 265 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 23 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
deleted 8 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 30 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 19 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 201 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 3390 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 3390 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
added 115 characters in body
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading
Source Link
ielyamani
  • 879
  • 1
  • 5
  • 18
Loading