Đệm a UILabel
, giải pháp đầy đủ. Cập nhật năm 2020.
Hóa ra có ba điều phải được thực hiện.
1. Phải gọi textRect # forBound với kích thước mới nhỏ hơn
2. Phải ghi đè drawText với kích thước nhỏ hơn mới
3. Nếu một ô có kích thước động, phải điều chỉnh intinsicContentSize
Trong ví dụ điển hình dưới đây, đơn vị văn bản nằm trong chế độ xem bảng, chế độ xem ngăn xếp hoặc cấu trúc tương tự, cung cấp cho nó một chiều rộng cố định . Trong ví dụ này, chúng tôi muốn phần đệm là 60,20,20,24.
Vì vậy, chúng tôi lấy "intinsicContentSize" hiện có và thực sự thêm 80 vào chiều cao .
Lặp lại ...
Bạn phải "lấy" chiều cao tính theo "cho đến nay" của động cơ và thay đổi giá trị đó.
Tôi thấy quá trình đó khó hiểu, nhưng, đó là cách nó hoạt động. Đối với tôi, Apple nên trưng ra một cuộc gọi có tên như "tính toán chiều cao sơ bộ".
Thứ hai, chúng ta phải thực sự sử dụng lệnh gọi textRect # forBound với kích thước nhỏ hơn mới của chúng tôi .
Vì vậy, trong textRect # forBound, trước tiên chúng ta làm cho kích thước nhỏ hơn và sau đó gọi siêu.
Thông báo! Bạn phải gọi siêu sau chứ không phải trước!
Nếu bạn điều tra cẩn thận tất cả các nỗ lực và thảo luận trên trang này, đó là vấn đề chính xác. Lưu ý một số giải pháp "dường như gần như hoạt động" nhưng sau đó sẽ có người báo cáo rằng trong một số tình huống nhất định, nó sẽ không hoạt động. Đây thực sự là lý do chính xác - thật khó hiểu là bạn phải "gọi siêu sau", chứ không phải trước đó.
Vì vậy, nếu bạn gọi siêu nó là "theo thứ tự sai", nó thường hoạt động, nhưng không cho độ dài văn bản cụ thể .
Dưới đây là một ví dụ trực quan chính xác về "làm sai trước tiên":
Lưu ý rằng các lề 60,20,20,24 là chính xác NHƯNG tính toán kích thước thực sự sai, bởi vì nó được thực hiện với mẫu "siêu đầu tiên" trong textRect # forBound.
Đã sửa:
Lưu ý rằng chỉ bây giờ công cụ textRect # forBound mới biết cách thực hiện phép tính đúng :
Cuối cùng!
Một lần nữa, trong ví dụ này, UILabel đang được sử dụng trong tình huống điển hình là độ rộng được cố định. Vì vậy, trong intinsicContentSize, chúng ta phải "thêm" chiều cao tổng thể thêm mà chúng ta muốn. (Bạn không cần phải "thêm" theo bất kỳ cách nào vào chiều rộng, điều đó sẽ vô nghĩa vì nó đã được sửa.)
Sau đó, trong textRect # forBound, bạn nhận được các giới hạn "được đề xuất cho đến nay" bằng cách tự động thanh toán, bạn trừ đi các lề của mình và chỉ sau đó gọi lại cho công cụ textRect # forBound, nghĩa là siêu, sẽ cho bạn kết quả.
Cuối cùng và đơn giản là trong drawText, bạn tất nhiên vẽ trong cùng một hộp nhỏ hơn.
Phù!
let UIEI = UIEdgeInsets(top: 60, left: 20, bottom: 20, right: 24) // as desired
override var intrinsicContentSize:CGSize {
numberOfLines = 0 // don't forget!
var s = super.intrinsicContentSize
s.height = s.height + UIEI.top + UIEI.bottom
s.width = s.width + UIEI.left + UIEI.right
return s
}
override func drawText(in rect:CGRect) {
let r = rect.inset(by: UIEI)
super.drawText(in: r)
}
override func textRect(forBounds bounds:CGRect,
limitedToNumberOfLines n:Int) -> CGRect {
let b = bounds
let tr = b.inset(by: UIEI)
let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
// that line of code MUST be LAST in this function, NOT first
return ctr
}
Một lần nữa. Lưu ý rằng các câu trả lời về điều này và QA khác "gần như" đúng là có vấn đề trong hình ảnh đầu tiên ở trên - "siêu ở sai vị trí" . Bạn phải buộc kích thước lớn hơn trong intinsicContentSize và sau đó trong textRect # forBound, trước tiên bạn phải thu nhỏ các giới hạn gợi ý đầu tiên và sau đó gọi siêu.
Tóm tắt: bạn phải "gọi siêu cuối " trong textRect # forBound
Đó là bí mật.
Lưu ý rằng bạn không cần và không cần phải gọi thêm không hợp lệ, sizeThatFits, cầnLayout hoặc bất kỳ cuộc gọi bắt buộc nào khác. Một giải pháp chính xác sẽ hoạt động đúng trong chu kỳ rút thăm tự động bình thường.
Tiền boa:
Nếu bạn đang làm việc với phông chữ đơn cách, đây là một mẹo hay: https://stackoverflow.com/a/59813420/294884