【问题标题】:iOS UILabel autoresize text to frame no matter the font无论字体如何,iOS UILabel 都会将文本自动调整为框架
【发布时间】:2015-11-20 12:18:14
【问题描述】:

我有一件不寻常的事情需要完成,但不知道该怎么做。

我有一个 UILabel 并希望将其设置为特定高度,然后调整其中的文本大小,使第一个字符等于该特定高度,其余字符仅获取计算出的字体大小。

我曾尝试使用myLabel.adjustsFontSizeToFitWidth = YES;,但它并没有真正解决我的问题,因为它在文本中使用了greates 字符,并且仍然添加了字体可能具有的垂直填充/间距。

图片应该描述我想要完成的事情。您可以看到高度应该是 200 像素,并且第一个字符正好是 200 像素,而没有垂直添加任何填充/间距。

有人知道如何解决这个问题吗?

提前致谢 瓦坦

【问题讨论】:

    标签: ios swift uilabel font-size


    【解决方案1】:

    一种基于渲染图像的解决方案,其中标签以字体大小显示,我们可以得到字符的开始位置和结束位置。有了这个,我们可以确定当前字符的高度(以像素为单位)。下一部分是给标签一个新的字体大小,然后通过渲染图像重复上一步。无论字体如何,这都会给出相同大小的字符。

    要使用它,您需要将以下代码添加到您的控制器,然后只需调用方法 setSizeFont (sizeFont: CGFloat, center:CGPoint) 其中 sizeFont 是字符所需的大​​小,而 center 是放置标签的位置(我需要在我的程序,它可能对其他人没有用)

    如果解决方案可以改进,请随时编辑

    extension UIImage {
        func getPixelColor(pos: CGPoint) -> UIColor {
    
            var pixelData = CGDataProviderCopyData(CGImageGetDataProvider(self.CGImage))
            var data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
    
            var pixelInfo: Int = ((Int(self.size.width) * Int(pos.y)) + Int(pos.x)) * 4
    
            var r = CGFloat(data[pixelInfo]) / CGFloat(255.0)
            var g = CGFloat(data[pixelInfo+1]) / CGFloat(255.0)
            var b = CGFloat(data[pixelInfo+2]) / CGFloat(255.0)
            var a = CGFloat(data[pixelInfo+3]) / CGFloat(255.0)
    
            return UIColor(red: r, green: g, blue: b, alpha: a)
        }
    
        private func getHeight() -> Int {
            var startHeight = 0
            var endHeight = Int(round(self.size.height))
            outerLoop: for var index = 0; index < Int(round(self.size.height)); index++ {
                for var j = 0; j < Int(round(self.size.width)); j++ {
                    if(self.getPixelColor(CGPoint(x:j, y:index)) == UIColor(red: 0, green: 0, blue: 0, alpha: 1)) {
                        startHeight = index
                        break outerLoop
                    }
                }
            }
    
            outerLoop: for var index = Int(round(self.size.height))-1; index >= 0; index -= 1 {
                for var j = 0; j < Int(round(self.size.width)); j++ {
                    if(self.getPixelColor(CGPoint(x:j, y:index)) == UIColor(red: 0, green: 0, blue: 0, alpha: 1)) {
                        endHeight = index
    
                        break outerLoop
                    }
                }
            }
    
            return endHeight-startHeight
        }
    }
    
    extension UILabel {
        func setSizeFont (sizeFont: CGFloat, center:CGPoint) {
    
            var str = self.text!
            str = str.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    
            var tempLabel = UILabel(frame: self.frame)
            //Set text to only be the first char
            tempLabel.text = str.substringWithRange(Range<String.Index>(start: advance(str.startIndex, 0), end: advance(str.startIndex, 1)))
            tempLabel.font = UIFont(name: self.font.fontName, size: sizeFont)!
            tempLabel.backgroundColor = UIColor.whiteColor()
            tempLabel.textColor = UIColor.blackColor()
            tempLabel.sizeToFit()
    
    
            self.font =  UIFont(name: self.font.fontName, size: sizeFont)!
    
    
            var height = tempLabel.generateImg().getHeight()
            var sizeF = Int(round(sizeFont))
            var currSize = sizeF
    
            while( height < sizeF ) {
                var diff = sizeF - height
                if(diff<=5){
                    currSize++
                } else {
                    currSize += diff-5
                }
                tempLabel.font = UIFont(name: tempLabel.font.fontName, size: CGFloat(currSize))!
                tempLabel.sizeToFit()
                height = tempLabel.generateImg().getHeight()
            }
    
            self.font = UIFont(name: self.font.fontName, size: CGFloat(currSize))
    
            self.sizeToFit()
    
            self.center = center
    
        }
        private func generateImg() -> UIImage{
    
            UIGraphicsBeginImageContext(self.bounds.size);
    
            // Make the CALayer to draw in our "canvas".
            self.layer.renderInContext(UIGraphicsGetCurrentContext())
    
            // Fetch an UIImage of our "canvas".
            var image = UIGraphicsGetImageFromCurrentImageContext();
    
            // Stop the "canvas" from accepting any input.
            UIGraphicsEndImageContext();
    
            return image
        }
    
    }
    

    【讨论】:

      【解决方案2】:
      [labelAutoResizeCheck setFont:[UIFont fontWithName:labelAutoResizeCheck.font.fontName size:90]];
      

      设置字体后,执行此操作..

      CGSize sizeAsPerText = [labelAutoResizeCheck.text sizeWithFont:labelAutoResizeCheck.font];
      [labelAutoResizeCheck setFrame:CGRectMake(labelAutoResizeCheck.frame.origin.x, labelAutoResizeCheck.frame.origin.y, sizeAsPerText.width, sizeAsPerText.height)];
      

      【讨论】:

      • 嗨,由于某些函数不存在,我该如何使用 swift 和 xcode 6 编写此代码?
      • @VatanBytyqi 在我的 Xcode 6.4 上,为了快速,在将文本和字体设置为标签后,我只需执行 label.sizeToFit() 。它运作良好
      • 如果您更详细地检查它,您会发现 char 并不是首选大小,因为字体对于不同类型的 och 字符有一些间距。
      【解决方案3】:

      如果您希望 UILabel 的高度始终与第一个字符的高度匹配,您可以使用 sizeToFit 但不要包含整个字符串,只包含第一个字符。然后,在 UILabel 的框架已经计算好之后,仅根据第一个字母,您可以添加其余的文本,标签仍将在所需的高度。

      我希望这会有所帮助。祝你好运!

      编辑:您可以根据这些 UIFont 特征获得所需角色的确切高度。图片很好地解释了这一点。根据您当前处理的角色,您可能需要稍微不同的计算,但是,正如您在图像中看到的,您拥有计算所需的所有数据:A great visualization of UIFont properties

      【讨论】:

      • 如果我将字体设置为 200 像素,则字符不会完全为 200 像素,因为它在顶部和底部会有一些间距,我需要在使用 sizeToFit 之前删除这个间距
      • 查看我添加到原始答案的链接。我希望它能为您提供解决问题所需的一切。
      • 谢谢,我会检查一下,稍后再回复您
      • 嗨,我一直在试图找出我应该为第一个字符使用哪个值。是否有可能找出一个字符是否有上升、下降等?
      • 我认为您应该基于用作第一个字符的特定字符。第一个字符为“x”的情况与第一个字符为“p”的情况下的计算不同。例如,如果字符是“a”,那么您要查找的高度就是 xHeight。但是,如果字符是 'k',高度将是 capHeight。对于“q”,您将使用 xHeight-descender。我希望这会有所帮助...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-09
      • 2012-11-07
      • 1970-01-01
      • 2016-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多