Làm thế nào để bạn thêm văn bản nhiều dòng vào một UIButton?


368

Tôi có đoạn mã sau ...

UILabel *buttonLabel = [[UILabel alloc] initWithFrame:targetButton.bounds];
buttonLabel.text = @"Long text string";
[targetButton addSubview:buttonLabel];
[targetButton bringSubviewToFront:buttonLabel];

... Ý tưởng là tôi có thể có văn bản nhiều dòng cho nút, nhưng văn bản luôn bị che khuất bởi hình nền của UIButton. Một cuộc gọi đăng nhập để hiển thị các lần xem lại của nút cho thấy UILabel đã được thêm, nhưng bản thân văn bản không thể nhìn thấy. Đây có phải là một lỗi trong UIButton hay tôi đang làm gì đó sai?


7
button.titleLabel?.numberOfLines = 0
ma11hew28

2
Lưu ý đối với QA rất cũ này, trong Xcode hiện đại RẤT ĐƠN GIẢN, CHỌN "VĂN BẢN GIỚI THIỆU" và sau đó là tầm thường, chọn "bọc ký tự".
Fattie

Cũng xem câu trả lời cập nhật cho một câu hỏi tương tự.
ToolmakerSteve

xem câu trả lời này (nhiều dòng, chiều rộng vừa vặn, chiều cao vừa vặn) cho văn bản nút stackoverflow.com/a/59211399/7523163
Hamid Reza Ansari

Câu trả lời:


676

Đối với iOS 6 trở lên, hãy sử dụng các cách sau để cho phép nhiều dòng:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
// you probably want to center it
button.titleLabel.textAlignment = NSTextAlignmentCenter; // if you want to 
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];

Đối với iOS 5 trở xuống, hãy sử dụng các cách sau để cho phép nhiều dòng:

button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
// you probably want to center it
button.titleLabel.textAlignment = UITextAlignmentCenter;
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];

2017, cho iOS9 chuyển tiếp ,

nói chung, chỉ cần làm hai điều sau:

  1. chọn "Văn bản quy kết"
  2. trên cửa sổ bật lên "Line Break", chọn "Word Wrap"

5
Vui lòng lưu ý các bài tập này không được chấp nhận trong iOS 6. Xem câu trả lời bên dưới của @NiKKi để biết cú pháp cập nhật.
Aaron Brager

6
Chỉ để mọi người biết: điều này không hoạt động nếu bạn đang sử dụng NSAttributionString
chàng

29
Trên thực tế, chỉ cần thêm button.titleLabel.numberOfLines = 0; Điều đó sẽ làm cho các dòng không giới hạn. Và button.titleLabel.textAlocation = NSTextAlocateLeft; nếu bạn muốn văn bản hợp lý bên trái làm tiêu đề được đặt ở giữa.
RyJ

4
Trong nhanh chóngbutton.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
Robert

1
Cảm ơn @Robert cho giải pháp nhanh chóng. Cũng có thể sử dụng suy luận và bỏ qua NSLineBreakMode, như vậy : button.titleLabel?.lineBreakMode = .ByWordWrapping.
mjswensen

145

Câu trả lời được chọn là chính xác nhưng nếu bạn thích làm điều này trong Trình tạo giao diện, bạn có thể làm điều này:

pic


58
Cảm ơn bản thân 24 tuổi của tôi đã viết câu trả lời này, từ bản thân 28 tuổi.
Adam Chờ đợi

5
Và để nghỉ với các thiết lập giao diện Builder chỉ, ta nên thiết lập titleLabel.textAlignmentvới Numbergiá trị cho 1trong User Defined Runtime Attributedđể làm cho văn bản làm trung tâm
AnthoPak

2
Cảm ơn bản thân 28 tuổi của bạn từ bản thân 24 tuổi của tôi!
Daniel Springer

59

Nếu bạn muốn thêm một nút có tiêu đề ở giữa với nhiều dòng, hãy đặt cài đặt Trình tạo giao diện cho nút:

[ đây]


Bạn có thể thêm một mô tả văn bản về cách để đạt được điều này. Một hình ảnh là tuyệt vời, nhưng nếu nó không có sẵn, câu trả lời của bạn sẽ vô ích.
Rory McCrossan

1
@RoryMcCrossan Xin chào, tôi đã thêm một hình ảnh ở trên. Bạn có thể xem nó? Xin lưu ý, Xcode 7 vẫn còn lỗi nên tiêu đề nút có thể biến mất. Tuy nhiên, một khi bạn chạy ứng dụng, bạn sẽ nhận được kết quả mong muốn.
dùng5440039

2
Đây là câu trả lời tốt nhất trong chủ đề này, thực sự. Hoạt động ngay lập tức và hiển thị văn bản trung tâm từ IB. Cảm ơn!
RainCast

@ user5440039 Cảm ơn câu trả lời tuyệt vời. Không cần thêm một mô tả văn bản.
Fattie

54

Dành cho iOS 6:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;

Như

UILineBreakModeWordWrap and UITextAlignmentCenter

không được dùng trong iOS 6 trở đi ..


Bên NSText.htrong Foundationkhông có thêm phản đối. Nó có sẵn từ 6.0 nhưng không được dùng nữa.
Alex Cio

Trong swift: button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center
jcity

30

Để phục hồi đề xuất của Roger Nolan, nhưng với mã rõ ràng, đây là giải pháp chung:

button.titleLabel?.numberOfLines = 0

21

Chuyển 3

button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center  
button.setTitle("Button\nTitle",for: .normal)

13

Trong Xcode 9.3, bạn có thể làm điều đó bằng cách sử dụng bảng phân cảnh như bên dưới,

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

Bạn cần đặt tiêu đề nút văn bản Sắp xếp thành trung tâm

button.titleLabel?.textAlignment = .center

Bạn không cần đặt văn bản tiêu đề với dòng mới (\ n) như bên dưới,

button.setTitle("Good\nAnswer",for: .normal)

Đơn giản chỉ cần đặt tiêu đề,

button.setTitle("Good Answer",for: .normal)

Đây là kết quả,

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


myButton.titleLabel.textAlignment = NSTextAlignmentCentertuyên bố cũng là cần thiết.
tounaobun

11

Có một cách dễ dàng hơn nhiều:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(Chỉnh sửa cho iOS 3 trở lên :)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;

4
UIButton.lineBreakMode không được dùng trong 3.0, vì vậy đó không còn là một lựa chọn tốt.
Christopher Pickslay

2
lineBreakMode không được dùng nữa như một thuộc tính trực tiếp của UIButton. Chúng tôi được hướng đến "Sử dụng thuộc tính lineBreakMode của titleLabel thay thế." Tôi đã chỉnh sửa câu trả lời của Valerii cho phù hợp. Nó vẫn là một lựa chọn tốt.
Wienke

11

Căn trái trên iOS7 với tính năng tự động thanh toán:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

9

Tôi gặp vấn đề với bố cục tự động, sau khi bật nhiều dòng kết quả như sau: vì vậy kích thước không ảnh hưởng đến kích thước nút tôi đã thêm dựa trên (trong trường hợp này là contentEdgeInsets là (10, 10, 10, 10 ) sau khi gọi : hy vọng nó sẽ giúp bạn (swift 5.0):
nhập mô tả hình ảnh ở đây
titleLabel
ConstraintscontentEdgeInsets
makeMultiLineSupport()
nhập mô tả hình ảnh ở đây

extension UIButton {

    func makeMultiLineSupport() {
        guard let titleLabel = titleLabel else {
            return
        }
        titleLabel.numberOfLines = 0
        titleLabel.setContentHuggingPriority(.required, for: .vertical)
        titleLabel.setContentHuggingPriority(.required, for: .horizontal)
        addConstraints([
            .init(item: titleLabel,
                  attribute: .top,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .top,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.top),
            .init(item: titleLabel,
                  attribute: .bottom,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .bottom,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.bottom),
            .init(item: titleLabel,
                  attribute: .left,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .left,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.left),
            .init(item: titleLabel,
                  attribute: .right,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .right,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.right)
            ])
    }

}

Hoạt động hoàn hảo trong swift 5. Tôi cũng đã thêm chức năng của mình vào văn bản trung tâm trong nút. Func centerTextInButton () {bảo vệ chúng ta hãy titleLabel = titleLabel else {} trở titleLabel.textAlignment = .center}
ShadeToD

Cảm ơn bạn. Đó là một giải pháp tốt.
Echelon

Tôi thấy việc thêm ràng buộc là không cần thiết, chỉ cần đặt văn bản sau khi lineBreakMode / textAlocation / numberOfLines được đặt. Và cũng đặt titleEdgeInsets cho phần trên và dưới.
Bill Chan

@BillChan thật không may, nó không hoạt động trong mọi trường hợp
Amir Khorsandi

7

Trước hết, bạn nên biết rằng UIButton đã có UILabel bên trong nó. Bạn có thể thiết lập nó bằng cách sử dụng –setTitle:forState:.

Vấn đề với ví dụ của bạn là bạn cần đặt thuộc numberOfLinestính của UILabel thành giá trị khác với giá trị mặc định là 1. Bạn cũng nên xem lại thuộc lineBreakModetính.


Tôi biết về thuộc tính tiêu đề, nhưng theo như tôi có thể nói thì không thể thiết lập nó để sử dụng nhiều hơn một dòng, do đó cách tiếp cận này. Nếu tôi vô hiệu hóa hình nền, UILabel của tôi sẽ xuất hiện, điều này với tôi gợi ý một lỗi trong cả bringSubviewToFront hoặc chính UIButton.
Owain Hunt

4

Đối với những người đang sử dụng bảng phân cảnh của Xcode 4, bạn có thể nhấp vào nút và ở bên phải Ngăn tiện ích bên dưới Trình theo dõi thuộc tính, bạn sẽ thấy tùy chọn cho Line Break. Chọn Word Wrap, và bạn nên đi.


4

Câu trả lời ở đây cho bạn biết làm thế nào để đạt được tiêu đề nút đa dòng theo chương trình.

Tôi chỉ muốn thêm rằng nếu bạn đang sử dụng bảng phân cảnh, bạn có thể nhập [Ctrl + Enter] để buộc một dòng mới trên trường tiêu đề nút.

HTH



3

Đối với ý tưởng của Brent về việc đặt tiêu đề UILabel làm quan điểm anh chị em, có vẻ như đó không phải là một ý tưởng hay. Tôi tiếp tục suy nghĩ về các vấn đề tương tác với UILabel do các sự kiện chạm của nó không vượt qua được quan điểm của UIButton.

Mặt khác, với một UILabel là phần phụ của UIButton, tôi khá khó hiểu khi biết rằng các sự kiện chạm sẽ luôn được truyền tới giám sát của UILabel.

Tôi đã thực hiện phương pháp này và không nhận thấy bất kỳ vấn đề nào được báo cáo với backgroundImage. Tôi đã thêm mã này vào -titleRectForContentRect: của lớp con UIButton nhưng mã cũng có thể được đặt trong thói quen vẽ của giám sát UIButton, trong trường hợp đó, bạn sẽ thay thế tất cả các tham chiếu thành biến bằng UIButton.

#define TITLE_LABEL_TAG 1234

- (CGRect)titleRectForContentRect:(CGRect)rect
{   
    // define the desired title inset margins based on the whole rect and its padding
    UIEdgeInsets padding = [self titleEdgeInsets];
    CGRect titleRect = CGRectMake(rect.origin.x    + padding.left, 
                                  rect.origin.x    + padding.top, 
                                  rect.size.width  - (padding.right + padding.left), 
                                  rect.size.height - (padding.bottom + padding].top));

    // save the current title view appearance
    NSString *title = [self currentTitle];
    UIColor  *titleColor = [self currentTitleColor];
    UIColor  *titleShadowColor = [self currentTitleShadowColor];

    // we only want to add our custom label once; only 1st pass shall return nil
    UILabel  *titleLabel = (UILabel*)[self viewWithTag:TITLE_LABEL_TAG];


    if (!titleLabel) 
    {
        // no custom label found (1st pass), we will be creating & adding it as subview
        titleLabel = [[UILabel alloc] initWithFrame:titleRect];
        [titleLabel setTag:TITLE_LABEL_TAG];

        // make it multi-line
        [titleLabel setNumberOfLines:0];
        [titleLabel setLineBreakMode:UILineBreakModeWordWrap];

        // title appearance setup; be at will to modify
        [titleLabel setBackgroundColor:[UIColor clearColor]];
        [titleLabel setFont:[self font]];
        [titleLabel setShadowOffset:CGSizeMake(0, 1)];
        [titleLabel setTextAlignment:UITextAlignmentCenter];

        [self addSubview:titleLabel];
        [titleLabel release];
    }

    // finally, put our label in original title view's state
    [titleLabel setText:title];
    [titleLabel setTextColor:titleColor];
    [titleLabel setShadowColor:titleShadowColor];

    // and return empty rect so that the original title view is hidden
    return CGRectZero;
}

Tôi đã dành thời gian và viết thêm một chút về điều này ở đây . Ở đó, tôi cũng chỉ ra một giải pháp ngắn hơn, mặc dù nó không hoàn toàn phù hợp với tất cả các kịch bản và liên quan đến việc hack một số lượt xem riêng tư. Ngoài ra, bạn có thể tải xuống một lớp con UIButton sẵn sàng để sử dụng.


3

Nếu bạn sử dụng bố cục tự động trên iOS 6, bạn cũng có thể cần đặt thuộc preferredMaxLayoutWidthtính:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;

3

Đặt lineBreakMode thành NSLineBreakByWordWrapping (bằng IB hoặc mã) làm cho nhãn nút đa dòng, nhưng không ảnh hưởng đến khung của nút.

Nếu nút có tiêu đề động, có một mẹo: đặt UILabel ẩn với cùng một phông chữ và buộc chiều cao của nó với chiều cao của nút với bố cục; khi đặt văn bản thành nút và nhãn và tự động thanh toán sẽ làm cho tất cả công việc.

Ghi chú

Chiều cao kích thước nội tại của nút một dòng lớn hơn nhãn, do đó, để ngăn chiều cao của nhãn bị thu hẹp, Ưu tiên ôm nội dung theo chiều dọc phải lớn hơn Độ bền nén nội dung dọc của nút.


3

Trong Swift 5.0Xcode 10.2

//UIButton extension
extension UIButton {
     //UIButton properties
     func btnMultipleLines() {
         titleLabel?.numberOfLines = 0
         titleLabel?.lineBreakMode = .byWordWrapping
         titleLabel?.textAlignment = .center        
     }
}

Trong cuộc gọi ViewContoder của bạn như thế này

button.btnMultipleLines()//This is your button

3

Swift 5, Đối với văn bản nhiều dòng trong UIButton

  let button = UIButton()
  button.titleLabel?.lineBreakMode = .byWordWrapping
  button.titleLabel?.textAlignment = .center
  button.titleLabel?.numberOfLines = 0 // for Multi line text

2

Nó hoạt động hoàn hảo.

Thêm vào để sử dụng tệp này với tệp cấu hình như Plist, bạn cần sử dụng CDATA để viết tiêu đề đa biến, như thế này:

<string><![CDATA[Line1
Line2]]></string>

2

Nếu bạn sử dụng bố trí tự động.

button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2

2

nhanh 4.0

btn.titleLabel?.lineBreakMode = .byWordWrapping
btn.titleLabel?.textAlignment = .center
btn.setTitle( "Line1\nLine2", for: .normal)

2

Ngày nay, nếu bạn thực sự cần loại điều này có thể truy cập được trong trình xây dựng giao diện trên cơ sở từng trường hợp, bạn có thể thực hiện với một tiện ích mở rộng đơn giản như thế này:

extension UIButton {
    @IBInspectable var numberOfLines: Int {
        get { return titleLabel?.numberOfLines ?? 1 }
        set { titleLabel?.numberOfLines = newValue }
    }
}

Sau đó, bạn có thể chỉ cần đặt numberOfLines làm thuộc tính trên bất kỳ lớp con UIButton hoặc UIButton nào như thể nó là nhãn. Điều tương tự cũng xảy ra với một loạt các giá trị thường không thể truy cập khác, chẳng hạn như bán kính góc của lớp của khung nhìn hoặc các thuộc tính của bóng mà nó tạo ra.


0

Cuộn lớp nút của riêng bạn. Đó là giải pháp tốt nhất về lâu dài. UIButton và các lớp UIKit khác rất hạn chế trong cách bạn có thể tùy chỉnh chúng.


0
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping

self.btnError.titleLabel?.textAlignment = .center

self.btnError.setTitle("Title", for: .normal)

0

Tôi đã kết hợp câu trả lời của jessecurry trong STAButton , một phần của thư viện mã nguồn mở STAControls của tôi . Tôi hiện đang sử dụng nó trong một trong những ứng dụng tôi đang phát triển và nó hoạt động cho nhu cầu của tôi. Vui lòng mở các vấn đề về cách cải thiện nó hoặc gửi cho tôi các yêu cầu kéo.


0

Để sửa khoảng cách nhãn của tiêu đề thành nút, hãy đặt titleEdgeInsets và các thuộc tính khác trước setTitle:

    let set = UIButton()
    sut.titleLabel?.lineBreakMode = .byWordWrapping
    sut.titleLabel?.numberOfLines = 0
    sut.titleEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 20, right: 20)
    sut.setTitle("Dummy button with long long long long long long long long title", for: .normal)

PS Tôi đã kiểm tra cài đặt titleLabel? .TextAlocation là không cần thiết và tiêu đề sẽ thẳng hàng .natural.


-4

Mặc dù việc thêm một khung nhìn vào điều khiển là không sao, nhưng không có gì đảm bảo nó sẽ thực sự hoạt động, bởi vì điều khiển có thể không mong đợi nó ở đó và do đó có thể hoạt động kém. Nếu bạn có thể thoát khỏi nó, chỉ cần thêm nhãn dưới dạng xem anh chị em của nút và đặt khung của nó để nó chồng lên nút; miễn là nó được thiết lập để xuất hiện trên đầu nút, không có gì nút có thể làm sẽ che khuất nó.

Nói cách khác:

[button.superview addSubview:myLabel];
myLabel.center = button.center;

2
Xin vui lòng, nếu bạn đề xuất cách tiếp cận xấu xí này ít nhất đừng mắc lỗi trong ví dụ mã của bạn :). Nhãn không nên có cùng tâm với nút nếu đó là một khung nhìn phụ. Sử dụng myLabel.frame = button.bound; hoặc myLabel.center = cgPointMake (button.frame.size.with * 0.5, button.frame.size.height * 0.5)
JakubKnejzlik

1
@GrizzlyNetch Tôi đặc biệt khuyên bạn không nên thêm nó dưới dạng một khung nhìn phụ của nút. addSubview:ở đây thêm nó vào giám sát buttoncủa nó, do đó làm cho nó trở thành anh chị em của nút, do đó, khớp với trung tâm của họ là chính xác.
Brent Royal-Gordon

À, lỗi của tôi! Bạn nói đúng, tôi đã bỏ lỡ sự thật "nhỏ" đó là trong giám sát: D ... xin lỗi :)
JakubKnejzlik

Đó không phải là chính xác những gì được hỏi, giải pháp này sẽ là một cách tồi để thực hiện câu hỏi vì nút phần tử có tiêu đề.
Pablo Blanco

Đây là lời khuyên hợp lý trong iPhone OS 2.0. Có nhiều cách tốt hơn để làm điều đó ngay bây giờ. : ^)
Brent Royal-Gordon
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.