2014-05-24 16 views
22

Tôi đã tạo ra một bộ điều khiển xem trông như thế này:Multiline UIButton và autolayout

enter image description here

Tôi muốn hai nút trên xuống luôn có 20 điểm giữa bản thân và những trái/cạnh bên phải của toàn cảnh . Chúng phải luôn luôn có cùng chiều rộng. Tôi đã tạo ra các ràng buộc cho tất cả điều này và nó hoạt động chính xác như thế nào tôi muốn nó. Vấn đề là các ràng buộc theo chiều dọc. Các nút phải luôn là 20 điểm bên dưới cạnh trên cùng. Họ nên có cùng chiều cao. Tuy nhiên, autolayout không tôn trọng điều đó nhãn trái cần hai dòng để phù hợp với tất cả các văn bản của nó, vì vậy kết quả sẽ như thế này:

enter image description here

Tôi muốn nó trông giống như trong hình đầu tiên. Tôi không thể thêm ràng buộc chiều cao liên tục vào các nút vì khi ứng dụng chạy trên iPad, chỉ cần một dòng là cần thiết và sẽ lãng phí khi có thêm dung lượng.

Trong viewDidLoad Tôi cố gắng này:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.leftButton.titleLabel.preferredMaxLayoutWidth = (self.view.frame.size.width - 20.0 * 3)/2.0; 
    self.rightButton.titleLabel.preferredMaxLayoutWidth = (self.view.frame.size.width - 20.0 * 3)/2.0; 
} 

Nhưng điều đó không thay đổi anyhting ở tất cả.

Câu hỏi: Làm thế nào để tôi thực hiện sự tôn trọng tự động mà nút bên trái cần hai dòng?

+0

nó có thể vì bạn có giới hạn "cùng chiều cao" trên nút bên trái. Điều đó sẽ làm cho nó có cùng chiều cao như các nút khác, thay đổi kích thước nội dung trong nút – user2277872

+0

Tôi đã cố gắng loại bỏ ràng buộc "cùng chiều cao" nhưng nó không hoạt động. –

+0

Bạn đã thử thêm> = ràng buộc vào nhãn để thiết lập số inset tối thiểu chưa? – jaggedcow

Trả lời

1

Bạn đã cố gắng sử dụng này:

self.leftButton.titleLabel.textAlignment = NSTextAlignmentCenter; 
self.leftButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail; 
self.leftButton.titleLabel.numberOfLines = 0; 
26

tôi đã cùng một vấn đề mà tôi muốn nút của tôi để phát triển cùng với tiêu đề của nó. Tôi đã phải sublcass các UIButtonintrinsicContentSize của nó để nó trả về kích thước nội tại của nhãn.

- (CGSize)intrinsicContentSize 
{ 
    return self.titleLabel.intrinsicContentSize; 
} 

Kể từ khi UILabel là multiline, intrinsicContentSize của nó là không rõ và bạn phải thiết lập nó preferredMaxLayoutWidthSee objc.io article about that

- (void)layoutSubviews 
{ 
    [super layoutSubviews]; 
    self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width; 
    [super layoutSubviews]; 
} 

Phần còn lại của bố cục nên làm việc. Nếu bạn đặt cả hai nút có chiều cao bằng nhau, nút kia sẽ phát triển thành. Nút hoàn toàn trông giống như

@implementation TAButton 

- (instancetype)initWithCoder:(NSCoder *)coder 
{ 
    self = [super initWithCoder:coder]; 
    if (self) { 
     self.titleLabel.numberOfLines = 0; 
     self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; 
    } 
    return self; 
} 

- (CGSize)intrinsicContentSize 
{ 
    return self.titleLabel.intrinsicContentSize; 
} 

- (void)layoutSubviews 
{ 
    [super layoutSubviews]; 
    self.titleLabel.preferredMaxLayoutWidth = self.titleLabel.frame.size.width; 
    [super layoutSubviews]; 
} 

@end 
+0

Làm việc hoàn hảo cho tôi, cảm ơn! Tôi không cần phải đặt 'numberOfLines' và gọi lệnh' [super layoutSubviews] 'thứ hai. – DMan

+2

TÔI MUỐN HÃY CÙNG BẠN !!! Tôi đã bị mắc kẹt trong thời gian này rất nhiều !! – Yitzchak

+0

Thực sự khéo léo. – matt

8

Swift phiên bản này dựa trên câu trả lời @Jan.

import UIKit 

class MultiLineButton: UIButton { 

    // MARK: - Init 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     self.commonInit() 
    } 

    private func commonInit() { 
     self.titleLabel?.numberOfLines = 0 
     self.titleLabel?.lineBreakMode = .ByWordWrapping 
    } 

    // MARK: - Overrides 

    override func intrinsicContentSize() -> CGSize { 
     return titleLabel?.intrinsicContentSize() ?? CGSizeZero 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     titleLabel?.preferredMaxLayoutWidth = titleLabel?.frame.size.width ?? 0 
     super.layoutSubviews() 
    } 

} 
1

CẬP NHẬT Swift/Swift 2.0 phiên bản một lần nữa dựa trên @ Jan của câu trả lời

@IBDesignable 
class MultiLineButton:UIButton { 

    //MARK: - 
    //MARK: Setup 
    func setup() { 
    self.titleLabel?.numberOfLines = 0 

    //The next two lines are essential in making sure autolayout sizes us correctly 
    self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, forAxis: .Vertical) 
    self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, forAxis: .Horizontal) 
    } 

    //MARK:- 
    //MARK: Method overrides 
    required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    setup() 
    } 

    override init(frame: CGRect) { 
    super.init(frame: frame) 
    setup() 
    } 

    override func intrinsicContentSize() -> CGSize { 
    return self.titleLabel!.intrinsicContentSize() 
    } 

    override func layoutSubviews() { 
    super.layoutSubviews() 
    titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width 
    } 
} 
1

chỉnh cho Swift 3.1

intrisicContentSize là một tài sản thay vì một hàm

override var intrinsicContentSize: CGSize { 
    return self.titleLabel!.intrinsicContentSize 
} 
1

Toàn bộ lớp trong Swift 3 - dựa trên @Jan, @Quantaliinuxite và @ Matt bezark:

@IBDesignable 
class MultiLineButton:UIButton { 

    //MARK: - 
    //MARK: Setup 
    func setup() { 
     self.titleLabel?.numberOfLines = 0 

     //The next two lines are essential in making sure autolayout sizes us correctly 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, for: .vertical) 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow+1, for: .horizontal) 
    } 

    //MARK:- 
    //MARK: Method overrides 
    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     setup() 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     setup() 
    } 

    override var intrinsicContentSize: CGSize { 
     return self.titleLabel!.intrinsicContentSize 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width 
    } 
} 
0

@ câu trả lời của Jan doesn' t làm việc cho tôi trong (ít nhất) iOS 8.1, 9.0 với Xcode 9.1. Vấn đề: titleLabel 's -intrinsicContentSize trả về chiều rộng rất lớn và chiều cao nhỏ vì không có giới hạn chiều rộng nào cả (titleLabel.frame trên cuộc gọi có kích thước bằng không dẫn đến vấn đề đo lường). Hơn nữa, nó không đưa vào tài khoản có thể insets và/hoặc hình ảnh.

Vì vậy, đây là thực hiện của tôi rằng nên sửa chữa tất cả các công cụ (phương pháp duy nhất là thực sự cần thiết):

@implementation PRButton 

- (CGSize)intrinsicContentSize 
{ 
    CGRect titleFrameMax = UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(
     self.bounds, self.alignmentRectInsets), self.contentEdgeInsets), self.titleEdgeInsets 
    ); 
    CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake(titleFrameMax.size.width, CGFLOAT_MAX)]; 

    CGSize superSize = [super intrinsicContentSize]; 
    return CGSizeMake(
     titleSize.width + (self.bounds.size.width - titleFrameMax.size.width), 
     MAX(superSize.height, titleSize.height + (self.bounds.size.height - titleFrameMax.size.height)) 
    ); 
} 

@end 
+0

Điều này không có tác dụng đối với tôi, trong khi giải pháp của Jan thực hiện. –

2

này tôn trọng insets cạnh nội dung và làm việc cho tôi:

class MultilineButton: UIButton { 

    func setup() { 
     self.titleLabel?.numberOfLines = 0 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow + 1, for: .vertical) 
     self.setContentHuggingPriority(UILayoutPriorityDefaultLow + 1, for: .horizontal) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     setup() 
    } 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     setup() 
    } 

    override var intrinsicContentSize: CGSize { 
     let size = self.titleLabel!.intrinsicContentSize 
     return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom) 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width 
    } 
}