ChatGPT解决这个技术问题 Extra ChatGPT

iOS:UIButton根据文本长度调整大小

在界面生成器中,按住 Command + = 将调整按钮的大小以适合其文本。我想知道在将按钮添加到视图之前是否可以通过编程方式执行此操作。

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12]];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
// I need to know the width needed to accomodate NSStringVariable
[button setTitle:NSStringVariable forState:UIControlStateNormal]; 
// So that I can set the width property of the button before addSubview
[button setFrame:CGRectMake(10, 0, width, fixedHeight)];
[subNavigation addSubview:button];
请注意这个非常古老的问题:如今(2017 年),只需将约束设置为“大于或等于”即可。 (请注意下面 Tad 的回答。)
@Fattie “大于或等于”约束不足以与 AutoLayout 兼容。如今(2017 年以上),应该将按钮包装在可以正确调整大小的东西中(Bartłomiej Semańczyk 回答),或者应该将 UIButton 子类化,如 stackoverflow.com/a/50575588/1033581
嗨@Cœur - 自动布局有很多微妙之处。您可能正在考虑稍微不同的情况?然而,幸运的是,你完全错了 - 试试吧!只需将 UIButton 放在视图控制器上。显然设置了水平和垂直中心。然后添加 >= 100 宽度约束。它在最新的 iOS 中完美运行。
(对于任何不熟悉自动布局谷歌搜索的人来说......只是TBC,你根本不需要添加任何东西,UIButton(还有UILabel等)会随着文本的变化自动调整宽度。只是正确约束 H/V 位置。)
@Fattie demonstration。特别是在运行时,它的行为如下:github.com/Coeur/autolayoutButton/blob/master/buttonSelfSizing/…

C
Cœur

在 UIKit 中,添加了 NSString 类以从给定的 NSString 对象获取以某种字体呈现时它将占用的大小。

文档是 here。现在它的 here 处于已弃用状态。

简而言之,如果你去:

CGSize stringsize = [myString sizeWithFont:[UIFont systemFontOfSize:14]]; 
//or whatever font you're using
[button setFrame:CGRectMake(10,0,stringsize.width, stringsize.height)];

...您将按钮的框架设置为您正在呈现的字符串的高度和宽度。

您可能希望在该 CGSize 周围试验一些缓冲区空间,但您将从正确的地方开始。


看起来iOS默认填充是12px,8px。
在 iOS 7.0 中不推荐使用 sizeWithFont。使用 sizeWithAttributes: 代替
我强烈建议不要再玩框架,而只能使用约束。
@GilSand 有没有办法为此使用界面构建器?
是的,谷歌搜索应该会给你很多有用的结果
D
Daniel Wood

在代码中执行此操作的方法是:

[button sizeToFit];

如果您是子类化并想要添加额外的规则,您可以覆盖:

- (CGSize)sizeThatFits:(CGSize)size;

sizeToFit 在 UIButton 或 UILabel 等标准控件上完美运行。如果您在自定义 UIView 上执行此操作,则需要实现 -(CGSize)sizeThatFits:(CGSize)size
它只有在设置文本之后才起作用,否则没有足够的信息来说明它应该有多大:[button setTitle:@"Your text here" forState:UIControlStateNormal]; [button sizeToFit]; 此外,如果您稍后更新文本,请不要忘记再次调用它。
确保仅以这种方式设置文本: [myButton setTitle:@"my title" forState:UIControlStateNormal];对我来说,直到我重复那句话才起作用。
sizeToFit() 不尊重标题边缘插图。
e
estemendoza

如果您的按钮是使用 Interface Builder 制作的,并且您正在更改代码中的标题,则可以执行以下操作:

[self.button setTitle:@"Button Title" forState:UIControlStateNormal];
[self.button sizeToFit];

即使您的按钮是用代码制作的,您也可以做到这一点。
J
Juan Boero

迅速:

这里重要的是 什么时候 你会调用 .sizeToFit() ,它应该在设置要显示的文本之后才能读取所需的大小,如果你稍后更新文本,然后再次调用它。

var button = UIButton()
button.setTitle("Length of this text determines size", forState: UIControlState.Normal)
button.sizeToFit()
self.view.addSubview(button)

F
Fattie

要使用自动布局完成此操作,请尝试设置可变宽度约束:

https://i.stack.imgur.com/iM1Vk.png

您可能还需要调整 Content Hugging PriorityContent Compression Resistance Priority 以获得所需的结果。

UILabel 完全自动调整大小:

这个 UILabel 被简单地设置为在屏幕上居中(只有两个约束,水平/垂直):

它完全自动改变宽度:

您不需要设置任何宽度或高度 - 它是完全自动的。

https://i.stack.imgur.com/Us3b2.png

https://i.stack.imgur.com/pVfMC.png

请注意,黄色小方块只是简单地附加(“间距”为零)。它们会随着 UILabel 调整大小而自动移动。

添加 ">=" 约束设置 UILabel 的最小宽度:

https://i.stack.imgur.com/raRNQ.png


E
Erik van der Neut

如果要调整文本而不是按钮的大小,可以使用...

button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = .5;
// The .5 value means that I will let it go down to half the original font size 
// before the texts gets truncated

// note, if using anything pre ios6, you would use I think
button.titleLabel.minimumFontSize = 8;

* 调整FontSizeToFitWidth
H
Hashem Aboonajmi

sizeToFit 无法正常工作。反而:

myButton.size = myButton.sizeThatFits(CGSize.zero)

您还可以将 contentInset 添加到按钮:

myButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 4, 8)


来自关于 sizeToFit 的 Apple 文档:// 使用当前视图边界调用 sizeThatFits: 并更改边界大小。因此它可以正常工作,您只需在设置文本之后进行设置。
它只是工作。 :) 谢谢
n
nator333

斯威夫特 4.2

感谢上帝,这解决了。为按钮设置文本后,您可以从 UIView 中检索作为自然大小的intrinsicContentSize(官方文档为here)。对于 UIButton,您可以像下面这样使用它。

button.intrinsicContentSize.width

为了您的信息,我调整了宽度以使其看起来正确。

button.frame = CGRect(fx: xOffset, y: 0.0, width: button.intrinsicContentSize.width + 18, height: 40)

模拟器

UIButtons with intrinsicContentSize

来源:https://riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-based-on-its-text-and-font


您能否提供更多背景信息?您的代码行与问题中的代码有何关系?您能否总结一下您建议的代码的作用?仅提供链接作为解释不是本网站的正确格式(请参阅 meta.stackexchange.com/a/8259/266197 了解原因),但如果您添加一些解释和上下文,您的答案将变得更有价值!
B
Bartłomiej Semańczyk

简单地:

创建 UIView 作为具有自动布局的包装器到周围的视图。将 UILabel 放入该包装器中。添加将标签粘贴到包装边缘的约束。将 UIButton 放入包装器中,然后简单地添加与 UILabel 相同的约束。享受自动调整大小的按钮和文本。


这在可访问性方面表现良好吗?
M
MobileDev

出于某种原因,func sizeToFit() 对我不起作用。我的设置是我在 UITableViewCell 中使用一个按钮,并且我正在使用自动布局。

对我有用的是:

获取宽度约束获取intrinsicContentSize 宽度,因为根据此文档自动布局不知道intrinsicContentSize。将宽度约束设置为 intrinsicContentSize 宽度

https://i.stack.imgur.com/IoblM.png

https://i.stack.imgur.com/Jo445.png

https://i.stack.imgur.com/D8UKk.png


荣誉,这对我来说很有吸引力,可以在堆栈视图中调整按钮的大小
D
Dhaval Bhadania

我有一些与这篇文章相关的额外需求,sizeToFit 无法解决。无论文本如何,我都需要将按钮保持在其原始位置的中心。我也不希望按钮大于其原始大小。

因此,我将按钮布局为其最大尺寸,将该尺寸保存在控制器中,并在文本更改时使用以下方法来调整按钮的大小:

+ (void) sizeButtonToText:(UIButton *)button availableSize:(CGSize)availableSize padding:(UIEdgeInsets)padding {    

     CGRect boundsForText = button.frame;

    // Measures string
    CGSize stringSize = [button.titleLabel.text sizeWithFont:button.titleLabel.font];
    stringSize.width = MIN(stringSize.width + padding.left + padding.right, availableSize.width);

    // Center's location of button
    boundsForText.origin.x += (boundsForText.size.width - stringSize.width) / 2;
    boundsForText.size.width = stringSize.width;
    [button setFrame:boundsForText];
 }

F
Felipe Augusto

此按钮类具有文本高度自动调整大小(适用于 Xamarin,但可以重写为其他语言)

[Register(nameof(ResizableButton))]
public class ResizableButton : UIButton
{
    NSLayoutConstraint _heightConstraint;
    public bool NeedsUpdateHeightConstraint { get; private set; } = true;

    public ResizableButton(){}

    public ResizableButton(UIButtonType type) : base(type){}

    public ResizableButton(NSCoder coder) : base(coder){}

    public ResizableButton(CGRect frame) : base(frame){}

    protected ResizableButton(NSObjectFlag t) : base(t){}

    protected internal ResizableButton(IntPtr handle) : base(handle){}

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        UpdateHeightConstraint();
        InvalidateIntrinsicContentSize();
    }

    public override void SetTitle(string title, UIControlState forState)
    {
        NeedsUpdateHeightConstraint = true;
        base.SetTitle(title, forState);
    }

    private void UpdateHeightConstraint()
    {
        if (!NeedsUpdateHeightConstraint)
            return;
        NeedsUpdateHeightConstraint = false;
        var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));

        var rect = new CGRect(Frame.X, Frame.Y, Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);

        if (_heightConstraint != null)
            RemoveConstraint(_heightConstraint);

        _heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, rect.Height);
        AddConstraint(_heightConstraint);
    }

     public override CGSize IntrinsicContentSize
     {
         get
         {
             var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));
             return new CGSize(Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);
         }
     }
}

S
Shalugin

老实说,我认为情节提要中没有简单的复选框来表示您想要调整按钮大小以适应文本,这真的很可惜。嗯……随便。

这是使用故事板的最简单的解决方案。

放置 UIView 并为其设置约束。示例:将 UILabel 放在 UIView 中。设置约束以将其附加到 UIView 的边缘。将您的 UIButton 放在 UIView 中。设置相同的约束以将其附加到 UIView 的边缘。将 UILabel 的行数设置为 0。设置网点。

    @IBOutlet var button: UIButton!
    @IBOutlet var textOnTheButton: UILabel!

得到一些很长很长的标题。


    let someTitle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

在 viewDidLoad 上为 UILabel 和 UIButton 设置标题。


    override func viewDidLoad() {
        super.viewDidLoad()
        textOnTheButton.text = someTitle
        button.setTitle(someTitle, for: .normal)
        button.titleLabel?.numberOfLines = 0
    }

运行它以确保按钮已调整大小并且可以按下。

https://i.stack.imgur.com/9qjfz.png


C
ChuckZHB

因为 sizeToFit 将忽略 titleEdgeInsets 设置。在我的例子中,按钮标题是固定文本,所以我使用自动布局给每个按钮一个宽度约束。

而且我认为如果是动态文本长度,您需要先获取字符串大小并更新 viewDidLayoutSubview 中的按钮约束。

    lazy var importButton: UIButton = {
        let btn = UIButton()
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.setTitle("Import", for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 18, weight: .bold)
        btn.setTitleColor(.white, for: .normal)
        btn.titleEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        btn.backgroundColor = .myBlue
        btn.layer.cornerRadius = 8
        btn.clipsToBounds = true
        btn.addTarget(self, action: #selector(importButtonTapped), for: .touchUpInside)
        return btn
    }()
    
    lazy var stitchButton: UIButton = {
        let btn = UIButton()
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.setTitle("Stitch", for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 18, weight: .bold)
        btn.setTitleColor(.white, for: .normal)
        btn.titleEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        btn.backgroundColor = .myGreen
        btn.layer.cornerRadius = 8
        btn.clipsToBounds = true
        btn.addTarget(self, action: #selector(stitchButtonTapped), for: .touchUpInside)
        return btn
    }()

    func setViews() {
        title = "Image Stitcher"
        view.backgroundColor = .systemBackground
        
        view.addSubview(importButton)
        view.addSubview(stitchButton)

        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            NSLayoutConstraint(item: importButton, attribute: .centerX, relatedBy: .equal, toItem: g, attribute: .trailing, multiplier: 0.3, constant: 0),
            importButton.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -50),
            importButton.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.25),
            importButton.heightAnchor.constraint(equalTo: importButton.widthAnchor, multiplier: 0.5),
            
            NSLayoutConstraint(item: stitchButton, attribute: .centerX, relatedBy: .equal, toItem: g, attribute: .trailing, multiplier: 0.7, constant: 0),
            stitchButton.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -50),
            stitchButton.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.25),
            stitchButton.heightAnchor.constraint(equalTo: stitchButton.widthAnchor, multiplier: 0.5),
        ])
    }

https://i.stack.imgur.com/AJfza.jpg


C
Cœur

在 Xcode 4.5 及更高版本中,现在可以使用“自动布局/约束”来完成。

主要优点是:

您根本不需要以编程方式设置框架!如果操作正确,您无需为改变方向而重新设置框架。此外,设备更改不必打扰您(阅读,无需为不同的屏幕尺寸单独编码)。

几个缺点:

不向后兼容 - 仅适用于 iOS 6 及更高版本。需要熟悉(但以后会节省时间)。

最酷的事情是我们可以专注于声明一个意图,例如:

我希望这两个按钮的宽度相同;或者

我需要这个视图垂直居中并从超级视图的边缘扩展到最大 10 pts;甚至,

我希望这个按钮/标签根据它显示的标签调整大小!

Here 是介绍自动布局的简单教程。

对于 more details

一开始需要一些时间,但看起来确实值得付出努力。


我几乎错过了这个答案——它真的需要更多的赞成票。使用此解决方案可以避免嵌入字体名称和大小或仅适用于 iOS 7 的调用。我只是设置了我希望 UIButton 扩展的一侧的约束,仅此而已。
几乎是一个完美的解决方案,不幸的是,如果您使用 titleEdgeInsets 它将不起作用:/
这是一个糟糕的答案 - 它详细说明了 AutoLayout 本身的优点,而不是在这种情况下如何应用 AutoLayout 来解决提问者的问题。
我想知道这是否有可能以编程方式说答案......
@JuanPabloBoeroAlvarez 自动布局约束可以在 Interface Builder 中和/或以编程方式指定。