2012-06-28 30 views
17

Ứng dụng của tôi bao gồm NSScrollView có chế độ xem tài liệu chứa số lượng được xếp chồng đứng NSTextViews - mỗi lần thay đổi kích thước theo hướng dọc khi văn bản được thêm vào.Sử dụng Autolayout với mở rộng NSTextViews

Hiện tại, tất cả được quản lý bằng mã. Các NSTextViews tự động thay đổi kích thước, nhưng tôi quan sát kích thước của chúng với một NSViewFrameDidChangeNotification, recalc tất cả nguồn gốc của chúng để chúng không chồng lên nhau, và thay đổi kích thước của người giám sát (chế độ xem tài liệu của chế độ xem cuộn) để chúng vừa vặn và có thể cuộn đến.

Điều này có vẻ như thể đó sẽ là ứng cử viên hoàn hảo cho autolayout! Tôi đặt NSLayoutConstraints giữa chế độ xem văn bản đầu tiên và vùng chứa, chế độ xem văn bản cuối cùng và vùng chứa của văn bản và mỗi chế độ xem văn bản giữa nhau. Sau đó, nếu bất kỳ chế độ xem văn bản nào phát triển, nó sẽ tự động "đẩy xuống" nguồn gốc của chế độ xem văn bản bên dưới để thỏa mãn các giới hạn, cuối cùng tăng kích thước của chế độ xem tài liệu và mọi người đều vui vẻ!

Ngoại trừ, có vẻ như không có cách nào để tự động phát triển NSTextView khi văn bản được thêm vào trong bố cục dựa trên ràng buộc? Sử dụng chính xác cùng một NSTextView tự động mở rộng khi văn bản được nhập trước đó, nếu tôi không chỉ định ràng buộc cho chiều cao của nó, nó sẽ tự động hủy 0 và không được hiển thị. Nếu tôi chỉ định một ràng buộc, ngay cả một sự bất bình đẳng như> = 20, nó vẫn bị mắc kẹt ở kích thước đó và không phát triển khi văn bản được thêm vào.

Tôi nghi ngờ việc này phải thực hiện với việc triển khai NSTextView là -intrinsicContentSize, theo mặc định trả về (NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric).

Vì vậy, câu hỏi của tôi: nếu tôi phân lớp NSTextView để trả lại một ý nghĩa hơn intrinsicContentSize dựa trên bố cục văn bản của tôi, thì tính năng tự động của tôi có hoạt động như mong đợi không?

Bất kỳ con trỏ nào khi triển khai intrinsicContentSize cho một NSTextView theo chiều dọc thay đổi kích thước?

+0

bạn có thể thêm một số đồ họa/ảnh chụp màn hình/wireframe để tạo điều kiện cho sự hiểu biết thiết lập xin vui lòng? Bạn đã cố gắng tính toán chiều cao văn bản và trả lại nó trong 'intrinsicContentSize'? – JJD

Trả lời

10

Tôi đã gặp sự cố tương tự với NSTextField, và hóa ra là do quan điểm muốn ôm chặt nội dung văn bản của nó dọc theo hướng thẳng đứng. Vì vậy, nếu bạn đặt nội dung ưu tiên ôm nội dung nào đó thấp hơn mức ưu tiên của các ràng buộc khác của bạn, nó có thể hoạt động. Ví dụ:

[textView setContentHuggingPriority:NSLayoutPriorityFittingSizeCompression-1.0 forOrientation:NSLayoutConstraintOrientationVertical]; 
+0

Rất vui khi tìm thấy điều này. Tôi thấy rằng tôi phải làm điều này cho 'NSTextField' theo chiều dọc trong' NSSplitView', nhưng chỉ khi chúng được chọn và không thể chỉnh sửa được! Thật lạ lùng khi các hiệu ứng hành vi chỉnh sửa bị hạn chế, nhưng có bạn đi. Tôi đã thay đổi mức độ ưu tiên nội dung ngang cho mỗi người trong số họ từ 250 đến 249 và vấn đề đã biến mất. – theory

+0

Dưới Swift 4, điều này có vẻ là 'setContentHuggingPriority (NSLayoutConstraint.Priority.fittingSizeCompression, cho: NSLayoutConstraint.Orientation.vertical)' không chắc ý nghĩa của -1 là gì nhưng nó có vẻ hoạt động mà không có. Cảm ơn, Marc! –

18

Tôi đang làm việc trên một thiết lập rất giống nhau - một chồng xem theo chiều dọc chứa chế độ xem văn bản mở rộng để vừa với nội dung văn bản và sử dụng tự động hoàn thành.

Cho đến nay tôi đã phải phân lớp NSTextView, đó là không có cảm giác sạch sẽ, nhưng hoạt động tuyệt vời trong thực tế:

- (NSSize) intrinsicContentSize { 
    NSTextContainer* textContainer = [self textContainer]; 
    NSLayoutManager* layoutManager = [self layoutManager]; 
    [layoutManager ensureLayoutForTextContainer: textContainer]; 
    return [layoutManager usedRectForTextContainer: textContainer].size; 
} 

- (void) didChangeText { 
    [super didChangeText]; 
    [self invalidateIntrinsicContentSize]; 
} 

Kích thước ban đầu của độ xem văn bản khi được bổ sung với addSubview là, một cách tò mò, không phải là kích thước nội tại; Tôi vẫn chưa tìm ra cách phát hành hiệu lực đầu tiên (hooking viewDidMoveToSuperview không giúp ích gì), nhưng tôi chắc chắn rằng cuối cùng tôi sẽ tìm ra nó.

+2

Rất hữu ích! Cảm ơn bạn đã chia sẻ những phát hiện của bạn! – jemmons

+1

Lưu ý: Tôi hiện đang cố gắng để có được kích thước để hoạt hình trơn tru, và thử nghiệm xem tôi có thể sử dụng autolayouts để kiểm soát chiều cao thay thế (hoặc bổ sung kích thước nội tại). Nó chỉ ra rằng bạn có thể sửa đổi một ràng buộc bằng cách gọi nó là một chiều cao mới bằng cách gọi '[constraint setConstant: newHeight]', trong đó 'constraint' là một ràng buộc duy nhất cung cấp thiết lập chiều cao. Nó hoạt động vào lúc này, nhưng xung đột với việc thay đổi kích thước tự động của 'NSTextContainer', dẫn đến nhấp nháy. –

3

Dưới đây là làm thế nào để thực hiện một NSTextView mở rộng sử dụng Auto Layout, trong Swift 3 enter image description here

  • tôi đã sử dụng Anchors cho Auto Layout
  • Sử dụng textDidChange từ NSTextDelegate.NSTextViewDelegate phù hợp với NSTextDelegate
  • Ý tưởng là textViewedges hạn chế, có nghĩa là bất cứ khi nào intrinsicContentSize thay đổi của nó, nó sẽ mở rộng mẹ của nó, đó là scrollView

    import Cocoa 
    import Anchors 
    
    class TextView: NSTextView { 
        override var intrinsicContentSize: NSSize { 
        guard let manager = textContainer?.layoutManager else { 
         return .zero 
        } 
    
        manager.ensureLayout(for: textContainer!) 
    
        return manager.usedRect(for: textContainer!).size 
        } 
    } 
    
    class ViewController: NSViewController, NSTextViewDelegate { 
    
        @IBOutlet var textView: NSTextView! 
        @IBOutlet weak var scrollView: NSScrollView! 
        override func viewDidLoad() { 
        super.viewDidLoad() 
    
        textView.delegate = self 
    
        activate(
         scrollView.anchor.top.constant(100), 
         scrollView.anchor.paddingHorizontally(30) 
        ) 
    
        activate(
         textView.anchor.edges 
        ) 
        } 
    
        // MARK: - NSTextDelegate 
        func textDidChange(_ notification: Notification) { 
        guard let textView = notification.object as? NSTextView else { return } 
    
        print(textView.intrinsicContentSize) 
        textView.invalidateIntrinsicContentSize() 
        } 
    } 
    
Các vấn đề liên quan