iOS: UIButton thay đổi kích thước theo độ dài văn bản


134

Trong trình tạo giao diện, giữ Command+ =sẽ thay đổi kích thước một nút để phù hợp với văn bản của nó. Tôi đã tự hỏi nếu điều này là có thể làm lập trình trước khi nút được thêm vào chế độ xem.

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];

1
Lưu ý cho câu hỏi rất cũ này: ngày nay (2017), chỉ cần đặt ràng buộc là "lớn hơn hoặc bằng" và nó thực hiện tất cả. (Thông báo câu trả lời dưới đây của Tad.)
Fattie

@Fattie Một ràng buộc " lớn hơn hoặc bằng " là không đủ để tương thích với AutoLayout. Ngày nay (2017+) người ta nên quấn nút bên trong thứ gì đó thay đổi kích thước chính xác (câu trả lời Bartłomiej Semańchot), hoặc người ta nên phân lớp UIButton, như trong stackoverflow.com/a/50575588/1033581
Cur

hi @ Cœur - có rất nhiều sự tinh tế để tự động thanh toán. Có thể bạn đang nghĩ về một tình huống hơi khác nhau? Tuy nhiên, may mắn thay, bạn hoàn toàn sai lầm - hãy thử nó !! Chỉ cần đặt một UIButton trên một bộ điều khiển xem. rõ ràng đặt trung tâm ngang và dọc. Và sau đó thêm một ràng buộc> = 100 chiều rộng. Nó hoạt động hoàn hảo trong iOS mới nhất.
Fattie

1
. ràng buộc đúng vị trí H / V.)
Fattie

@Fattie trình diễn . Đặc biệt, trong thời gian chạy, nó hoạt động như vậy: github.com/Coeur/autolayoutButton/blob/master/buttonSelfSizing/ trộm
Cœur

Câu trả lời:


1

Trong Xcode 4.5 trở lên, giờ đây có thể được thực hiện bằng cách sử dụng ' Tự động bố trí / ràng buộc '.

Ưu điểm chính là:

  1. Bạn không cần phải thiết lập các khung theo chương trình!
  2. Nếu được thực hiện đúng, bạn không cần bận tâm về việc đặt lại các khung để thay đổi hướng.
  3. Ngoài ra, các thay đổi thiết bị không cần phải làm phiền bạn (đọc, không cần mã riêng cho các kích thước màn hình khác nhau).

Một vài nhược điểm:

  1. Không tương thích ngược - chỉ hoạt động cho iOS 6 trở lên.
  2. Cần làm quen (nhưng sẽ tiết kiệm thời gian sau này).

Điều thú vị nhất là chúng ta tập trung vào việc tuyên bố một ý định như:

  • Tôi muốn hai nút này có cùng chiều rộng; hoặc là
  • Tôi cần quan điểm này được căn giữa theo chiều dọc và mở rộng đến mức tối đa 10 điểm từ cạnh của giám sát; hoặc thậm chí,
  • Tôi muốn nút / nhãn này thay đổi kích thước theo nhãn mà nó đang hiển thị!

Đây là một hướng dẫn đơn giản để làm quen với cách bố trí tự động.

Để biết thêm chi tiết .

Nó mất một chút thời gian lúc đầu, nhưng có vẻ như nó sẽ rất đáng để nỗ lực.


3
Tôi gần như đã bỏ lỡ câu trả lời này - nó thực sự cần nhiều phiếu bầu hơn. Với giải pháp này, người ta có thể tránh nhúng các tên và kích thước phông chữ hoặc các cuộc gọi chỉ dành cho iOS 7. Tôi chỉ đơn giản là đặt ràng buộc của phía mà tôi muốn UIButton của mình mở rộng và đó là điều đó.
Carl

Gần như là một giải pháp hoàn hảo, thật không may, nó không hoạt động nếu bạn sử dụng titleEdgeInsets: /
Zoltán

130
Đây là một câu trả lời kém - nó nêu chi tiết giá trị của AutoLayout, thay vì cách AutoLayout có thể được áp dụng trong tình huống này để giải quyết vấn đề của người hỏi.
mattsven

4
Tôi đã tự hỏi nếu điều này có thể được lập trình nói câu trả lời ...
Juan Boero

@JuanPabloBoeroAlvarez Các ràng buộc Bố cục tự động có thể được chỉ định trong Trình tạo giao diện và / hoặc lập trình.
Slipp D. Thompson

130

Trong UIKit, có các bổ sung cho lớp NSString để lấy từ một đối tượng NSString đã cho, kích thước mà nó sẽ chiếm khi được hiển thị trong một phông chữ nhất định.

Tài liệu đã ở đây . Bây giờ nó ở đây dưới tán thành.

Tóm lại, nếu bạn đi:

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

... bạn sẽ đặt khung của nút thành chiều cao và chiều rộng của chuỗi bạn đang kết xuất.

Có thể bạn sẽ muốn thử nghiệm một số không gian bộ đệm xung quanh CGSize đó, nhưng bạn sẽ bắt đầu ở đúng nơi.


4
Hình như phần đệm mặc định của iOS là 12px, 8px.
Ben Lachman

19
sizeWithFont không được dùng trong iOS 7.0. Sử dụng sizeWithAttribut: thay vào đó
carmen_munich

6
Tôi thực sự khuyên bạn không nên chơi với khung hình nữa mà thay vào đó là các ràng buộc.
Gil Sand

@GilSand Có cách nào để sử dụng trình xây dựng giao diện cho việc này không?
huggie

Có, một tìm kiếm google sẽ cung cấp cho bạn nhiều kết quả hữu ích
Gil Sand

101

Cách để làm điều này trong mã là:

[button sizeToFit];

Nếu bạn đang phân lớp và muốn thêm quy tắc bổ sung, bạn có thể ghi đè:

- (CGSize)sizeThatFits:(CGSize)size;

5
sizeToFit hoạt động hoàn hảo trên các điều khiển tiêu chuẩn như UIButton hoặc UILabel. Nếu bạn đang thực hiện nó trên một UIView tùy chỉnh, bạn sẽ cần phải thực hiện -(CGSize)sizeThatFits:(CGSize)size.
Cameron Lowell Palmer

4
Nó chỉ hoạt động nếu bạn đặt nó sau khi đặt văn bản, nếu không thì không có đủ thông tin về mức độ lớn của nó: [button setTitle:@"Your text here" forState:UIControlStateNormal]; [button sizeToFit]; Ngoài ra nếu bạn cập nhật văn bản sau, đừng quên gọi lại.
Juan Boero

Đảm bảo rằng bạn chỉ đặt văn bản theo cách đó: [myButton setTitle: @ "tiêu đề của tôi" forState: UIControlStateN normal]; Đối với tôi nó không hoạt động cho đến khi tôi lặp lại câu nói đó.
Darius Miliauskas

7
sizeToFit()không tôn trọng chèn cạnh tiêu đề.
kelin

32

Nếu nút của bạn được tạo bằng Trình tạo giao diện và bạn đang thay đổi tiêu đề trong mã, bạn có thể thực hiện việc này:

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

1
Và bạn có thể làm điều đó ngay cả khi nút của bạn được tạo bằng mã.
Markus

22

Nhanh:

Điều quan trọng ở đây là khi nào bạn sẽ gọi .sizeToFit(), nó sẽ là sau khi cài đặt văn bản để hiển thị để nó có thể đọc kích thước cần thiết, nếu sau này bạn cập nhật văn bản, sau đó gọi lại.

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

18

Để thực hiện điều này bằng cách sử dụng tự động thanh toán, hãy thử đặt một ràng buộc về chiều rộng thay đổi:

Ràng buộc chiều rộng

Bạn cũng có thể cần phải điều chỉnh Content Hugging PriorityContent Compression Resistance Priorityđể có được kết quả bạn cần.


UILabel hoàn toàn tự động tự định cỡ :

Nhãn UIL này chỉ đơn giản được đặt ở giữa màn hình (chỉ có hai ràng buộc, ngang / dọc):

Nó thay đổi độ rộng hoàn toàn tự động:

Bạn không cần đặt bất kỳ chiều rộng hoặc chiều cao nào - nó hoàn toàn tự động.

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Lưu ý các ô vuông nhỏ màu vàng được đính kèm đơn giản ("khoảng cách" bằng 0). Chúng tự động di chuyển khi UILabel thay đổi kích thước.

Thêm ràng buộc "> =" đặt chiều rộng tối thiểu cho UILabel:

nhập mô tả hình ảnh ở đây


16

Nếu bạn muốn thay đổi kích thước văn bản trái ngược với nút, bạn có thể sử dụng ...

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;

3
* điều chỉnhFontSizeToFitWidth
Daniel Bang

8

sizeToFit không hoạt động chính xác. thay thế:

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

bạn cũng có thể thêm contentInsetvào nút:

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


Từ các tài liệu của Apple liên quan đến sizeToFit: // gọi sizeThatFits: với giới hạn chế độ xem hiện tại và thay đổi kích thước giới hạn. Vì vậy, nó hoạt động chính xác, bạn chỉ cần đặt nó sau khi bạn đặt văn bản.
Markus

5

Đơn giản:

  1. Tạo UIViewnhư một trình bao bọc với bố cục tự động để xem xung quanh.
  2. Đặt UILabelbên trong cái bọc đó. Thêm các ràng buộc sẽ dán nhãn tyour vào các cạnh của trình bao bọc.
  3. Đặt UIButtonbên trong trình bao bọc của bạn, sau đó đơn giản thêm các ràng buộc giống như bạn đã làm UILabel.
  4. Thưởng thức nút tự động của bạn cùng với văn bản.

1
Điều này chơi tốt với khả năng tiếp cận?
jasonszhao 17/12/18

4

Swift 4.2

Cảm ơn chúa, điều này đã giải quyết. Sau khi đặt văn bản cho nút, bạn có thể truy xuất intinsicContentSize có kích thước tự nhiên từ một UIView (tài liệu chính thức có ở đây ). Đối với UIButton, bạn có thể sử dụng nó như dưới đây.

button.intrinsicContentSize.width

Đối với thông tin của bạn, tôi điều chỉnh chiều rộng để làm cho nó trông chính xác.

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

Giả lập

UIButtons với intinsicContentSize

Nguồn: https://riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-basing-on-its-text-and-font


1
Bạn có thể cho thêm một chút bối cảnh? Làm thế nào để dòng mã của bạn liên quan đến mã trong câu hỏi? Bạn cũng có thể tóm tắt những gì mã bạn đề nghị không? Chỉ cung cấp liên kết dưới dạng giải thích không phải là định dạng phù hợp cho trang web này (xem meta.stackexchange.com/a/8259/266197 vì lý do), nhưng nếu bạn thêm một số giải thích và ngữ cảnh, câu trả lời của bạn sẽ trở nên có giá trị hơn!
NOh

3

Tôi có một số nhu cầu bổ sung liên quan đến bài đăng này mà sizeToFitkhông giải quyết được. Tôi cần giữ nút ở giữa ở vị trí ban đầu, bất kể văn bản. Tôi cũng không bao giờ muốn nút lớn hơn kích thước ban đầu của nó.

Vì vậy, tôi bố trí nút cho kích thước tối đa của nó, lưu kích thước đó trong Bộ điều khiển và sử dụng phương pháp sau để định cỡ nút khi văn bản thay đổi:

+ (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];
 }

1

Lớp nút này với độ cao tự động hóa cho văn bản (đối với Xamarin nhưng có thể được viết lại cho ngôn ngữ khác)

[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);
         }
     }
}

1

Vì một số lý do, func sizeToFit()không làm việc cho tôi. Thiết lập của tôi là tôi đang sử dụng một nút bên trong a UITableViewCellvà tôi đang sử dụng bố trí tự động.

Những gì làm việc cho tôi là:

  1. có được giới hạn chiều rộng
  2. có được intrinsicContentSizechiều rộng vì theo tài liệu này bố trí tự động không nhận thức được intrinsicContentSize. Đặt giới hạn intrinsicContentSizechiều rộng thành chiều rộng

nhập mô tả hình ảnh ở đây

Đây là hai danh hiệu từ Debug View Hierachry nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


0

Thành thật mà nói tôi nghĩ rằng thật xấu hổ khi không có hộp kiểm đơn giản trong bảng phân cảnh để nói rằng bạn muốn thay đổi kích thước các nút để chứa văn bản. Sao cũng được.

Đây là giải pháp đơn giản nhất bằng cách sử dụng bảng phân cảnh.

  1. Đặt UIView và đặt các ràng buộc cho nó. Thí dụ: nhập mô tả hình ảnh ở đây
  2. Đặt UILabel bên trong UIView. Đặt các ràng buộc để gắn nó vào các cạnh của UIView.

  3. Đặt UIButton của bạn bên trong UIView. Đặt các ràng buộc tương tự để gắn nó vào các cạnh của UIView.

  4. Đặt 0 cho số dòng của UILabel. nhập mô tả hình ảnh ở đây

  5. Thiết lập các cửa hàng.

    @IBOutlet var button: UIButton!
    @IBOutlet var textOnTheButton: UILabel!
  1. Nhận một số tiêu đề dài, dài, dài.

    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."
  1. Trên viewDidLoad, đặt tiêu đề cho cả UILabel và UIButton.

    override func viewDidLoad() {
        super.viewDidLoad()
        textOnTheButton.text = someTitle
        button.setTitle(someTitle, for: .normal)
        button.titleLabel?.numberOfLines = 0
    }
  1. Chạy nó để đảm bảo rằng nút đó được thay đổi kích thước và có thể được nhấn.

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.