简体   繁体   English

Autolayout - UIButton的内在大小不包括标题插入

[英]Autolayout - intrinsic size of UIButton does not include title insets

If I have a UIButton arranged using autolayout, its size adjusts nicely to fit its content. 如果我使用autolayout安排了UIButton,它的大小可以很好地调整以适应其内容。

If I set an image as button.image , the instrinsic size again seems to account for this. 如果我将图像设置为button.image ,则内在大小似乎再次考虑到这一点。

However, if I tweak the titleEdgeInsets of the button, the layout does not account for this and instead truncates the button title. 但是,如果我调整按钮的titleEdgeInsets ,布局不会考虑到这一点,而是截断按钮标题。

How can I ensure that the intrinsic width of the button accounts for the inset? 如何确保按钮的固有宽度占据插入?

在此输入图像描述

Edit: 编辑:

I am using the following: 我使用以下内容:

[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

The goal is to add some separation between the image and the text. 目标是在图像和文本之间添加一些分隔。

You can get this to work in Interface Builder (without writing any code), by using a combination of negative and positive Title and Content Insets. 您可以通过使用负面和正面标题和内容插入的组合,使其在Interface Builder中工作(无需编写任何代码)。

在此输入图像描述

Update : Xcode 7 has a bug where you cannot enter negative values in the Right Inset field, but you can use the stepper control next to it to decrease the value. 更新 :Xcode 7有一个错误,您无法在Right插入字段中输入负值,但您可以使用旁边的步进控制来减小值。 (Thanks Stuart) (谢谢斯图尔特)

Doing this will add 8pt of spacing between the image and the title and will increase the intrinsic width of the button by the same amount. 这样做会在图像和标题之间增加8pt的间距,并且会增加按钮的固有宽度相同的量。 Like this: 像这样:

在此输入图像描述

You can solve this without having to override any methods or set an arbitrary width constraint. 您可以解决此问题,而无需覆盖任何方法或设置任意宽度约束。 You can do it all in Interface Builder as follows. 您可以在Interface Builder中完成所有操作,如下所示。

  • Intrinsic button width is derived from the title width plus the icon width plus the left and right content edge insets. 内部按钮宽度源自标题宽度加上图标宽度加上左右内容边缘插入。

  • If a button has both an image and text, they're centered as a group, with no padding between. 如果按钮同时具有图像和文本,则它们作为一组居中,两者之间没有填充。

  • If you add a left content inset, it's calculated relative to the text, not the text + icon. 如果添加左侧内容插入,则相对于文本计算,而不是文本+图标。

  • If you set a negative left image inset, the image is pulled out to the left but the overall button width is unaffected. 如果设置负左图像插入,则图像将向左拉出,但整体按钮宽度不受影响。

  • If you set a negative left image inset, the actual layout uses half that value. 如果设置负左图像插入,则实际布局使用该值的一半。 So to get a -20 point left inset, you must use a -40 point left inset value in Interface Builder. 因此,要保持-20点左边的插入,必须在Interface Builder中使用-40点左边的插入值。

So you provide a big enough left content inset to create space for both the desired left inset and the inner padding between the icon and the text, and then shift the icon left by doubling the amount of padding you want between the icon and the text. 因此,您提供了足够大的左侧内容插图,以便为所需的左侧插图图标与文本之间的内部填充创建空间,然后通过将图标和文本之间所需的填充量加倍来向左移动图标。 The result is a button with equal left and right content insets, and a text and icon pair that are centered as a group, with a specific amount of padding between them. 结果是具有相等左右内容插入的按钮,以及作为一组居中的文本和图标对,以及它们之间具有特定数量的填充。

Some example values: 一些示例值:

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)

Why not override the intrinsicContentSize method on UIView? 为什么不在UIView上覆盖intrinsicContentSize方法? For example: 例如:

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
                      s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}

This should tell the autolayout system that it should increase the size of the button to allow for the insets and show the full text. 这应该告诉autolayout系统它应该增加按钮的大小以允许插入并显示全文。 I'm not at my own computer, so I haven't tested this. 我不是在自己的电脑上,所以我没有测试过这个。

You haven't specified how you're setting the insets, so I'm guessing that you're using titleEdgeInsets because I see the same effect you're getting. 你没有指定你如何设置插图,所以我猜你正在使用titleEdgeInsets,因为我看到你得到的效果相同。 If I use contentEdgeInsets instead it works properly. 如果我使用contentEdgeInsets它可以正常工作。

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}

And for Swift worked this: 而对于Swift的工作:

extension UIButton {
    override open var intrinsicContentSize: CGSize {
        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}

Love U Swift 爱你斯威夫特

This thread is a bit old, but I just ran into this myself and was able to solve it by using a negative inset. 这个线程有点旧,但我自己遇到了这个并且能够通过使用负插入来解决它。 For example, substitute your desired padding values here: 例如,在此处替换所需的填充值:

UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
                                            -desiredRightPadding,
                                            -desiredTopPadding,
                                            -desiredLeftPadding);

Combined with the right autolayout constraints, you end up with an auto-resizing button which contains an image and text! 结合正确的自动布局约束,您最终会得到一个包含图像和文本的自动调整大小按钮! Seen below with desiredLeftPadding set to 10. 如下所示,将desiredLeftPadding设置为10。

带图像和短文本的按钮

带图像和长文本的按钮

You can see that the actual frame of the button doesn't encompass the label (since the label is shifted 10 points to the right, outside the bounds), but we've achieved 10 points of padding between the text and the picture. 您可以看到按钮的实际框架不包含标签(因为标签在边界外向右移动10个点),但我们在文本和图片之间实现了10个填充点。

For Swift 3 based on pegpeg 's answer: 对于基于pegpeg答案的Swift 3

extension UIButton {

    override open var intrinsicContentSize: CGSize {

        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)

    }

}

All above did not work for iOS 9+ , what i did is: 以上所有内容都不适用于iOS 9+ ,我所做的是:

  • Add a width constraint (for a minimum width when the button doesn't have any text. The button will auto scale if text is provided) 添加宽度约束(当按钮没有任何文本时,为最小宽度。如果提供文本,该按钮将自动缩放)
  • set the relation to Greater Than or Equal 将关系设置为大于或等于

在此输入图像描述

Now to add a border around the button just use the method: 现在要在按钮周围添加边框,只需使用以下方法:

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);

I wanted to add a 5pt space between my UIButton icon and the label. 我想在我的UIButton图标和标签之间添加一个5pt的空间。 This is how I achieved it: 这就是我实现它的方式:

UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);

The way contentEdgeInsets, titleEdgeInsets and imageEdgeInsets relate to each other requires a little give and take from each inset. contentEdgeInsets,titleEdgeInsets和imageEdgeInsets彼此相关的方式需要从每个插图中获取一些东西。 So if you add some insets to the title's left you have to add negative inset on the right and provide some more space (via a positive inset) on the content right. 因此,如果您在标题左侧添加一些插入内容,则必须在右侧添加负插入,并在内容右侧提供更多空间(通过正插入)。

By adding a right content inset to match the shift of the title insets my text doesn't go outside the bounds of the button. 通过添加正确的内容插入来匹配标题插入的移位,我的文本不会超出按钮的范围。

The option is also available in interface builder. 该选项也可在界面构建器中使用。 See the Inset. 见插图。 I set left and right to 3. Works like a charm. 我向左和向右设置为3.工作就像一个魅力。

界面生成器截图

The solution I use is to add a width constraint on the button. 我使用的解决方案是在按钮上添加宽度约束。 Then somewhere in initialization, after your text is set, update the width constraint like so: 然后在初始化的某个地方,在设置文本后,更新宽度约束,如下所示:

self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;

Where 8 is whatever your inset is. 8是你的插图是什么。

calling sizeToFit() makes sure that contentEdgeInset is taken into effect 调用sizeToFit()可确保使contentEdgeInset生效

extension UIButton {

   open override func draw(_ rect: CGRect) { 
       self.contentEdgeInsets = UIEdgeInsets(top: 10, left: 40, bottom: 10, right: 40)
       self.sizeToFit()
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM