Программно создать NSScrollView в NSView - Какао

У меня есть класс NSView, который заботится о настраиваемом представлении, созданном в файле пера.

Теперь я хочу добавить NSScrollView в настраиваемое представление, но мне нужно сделать это программно, а не с помощью Interface Builder (Embed Into Scroll View).

Я нашел этот код:

NSView *windowContentView = [mainWindow contentView];
NSRect windowContentBounds = [windowContentView bounds];
scrollView = [[NSScrollView alloc] init];
[scrollView setBorderType:NSNoBorder];
[scrollView setHasVerticalScroller:YES];
[scrollView setBounds: windowContentBounds];
[windowContentView addSubview:scrollView];

Предполагая, что я объявил как IBOutlets указанные выше переменные mainWindow и scrollView, как мне подключить их к нужным компонентам в Interface Builder? Есть ли смысл делать так?

Или есть лучший способ программно добавить представление прокрутки?

P.S. Я не могу подключить их обычным способом, потому что я не могу создать объект NSObject из Interface Builder или использовать File Owner ..


person Kevin    schedule 04.04.2012    source источник
comment
Если вы создаете представления программно, они не подключаются к построителю интерфейса.   -  person Otium    schedule 04.04.2012
comment
Какие? Конечно, вы можете связать программные представления с представлениями, созданными конструктором интерфейсов.   -  person ctpenrose    schedule 05.04.2012


Ответы (4)


Этот фрагмент кода должен продемонстрировать, как программно создать NSScrollView и использовать его для отображения любого представления, будь то из пера или кода. В случае представления, созданного с помощью пера, вам просто нужно предварительно загрузить файл пера в свое пользовательское представление и иметь выход для вашего пользовательского представления (outputToCustomViewLoadedFromNib), созданный для владельца файла.

NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:[[mainWindow contentView] frame]];

// configure the scroll view
[scrollView setBorderType:NSNoBorder];
[scrollView setHasVerticalScroller:YES];

// embed your custom view in the scroll view
[scrollView setDocumentView:outletToCustomViewLoadedFromNib];

// set the scroll view as the content view of your window
[mainWindow setContentView:scrollView];

У Apple есть руководство по этому вопросу, на которое я не буду ссылаться, поскольку для этого требуется доступ Apple Developer Connection, а их ссылки часто ломаются. Он называется «Создание и настройка прокрутки», и в настоящее время его можно найти, выполнив поиск по названию с помощью Google.

person ctpenrose    schedule 05.04.2012

Мне сложно создать NSScrollView с AutoLayout программно, но, наконец, он заработал. Это Swift версия.

    // Initial scrollview
    let scrollView = NSScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.borderType = .noBorder
    scrollView.backgroundColor = NSColor.gray
    scrollView.hasVerticalScroller = true

    window.contentView?.addSubview(scrollView)
    window.contentView?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollView]))
    window.contentView?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollView]))

    // Initial clip view
    let clipView = NSClipView()
    clipView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.contentView = clipView
    scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .left, relatedBy: .equal, toItem: scrollView, attribute: .left, multiplier: 1.0, constant: 0))
    scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1.0, constant: 0))
    scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .right, relatedBy: .equal, toItem: scrollView, attribute: .right, multiplier: 1.0, constant: 0))
    scrollView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1.0, constant: 0))

    // Initial document view
    let documentView = NSView()
    documentView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.documentView = documentView
    clipView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .left, relatedBy: .equal, toItem: documentView, attribute: .left, multiplier: 1.0, constant: 0))
    clipView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .top, relatedBy: .equal, toItem: documentView, attribute: .top, multiplier: 1.0, constant: 0))
    clipView.addConstraint(NSLayoutConstraint(item: clipView, attribute: .right, relatedBy: .equal, toItem: documentView, attribute: .right, multiplier: 1.0, constant: 0))

    // Subview1
    let view1 = NSView()
    view1.translatesAutoresizingMaskIntoConstraints = false
    view1.wantsLayer = true
    view1.layer?.backgroundColor = NSColor.red.cgColor
    documentView.addSubview(view1)
    documentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view1]|", options: [], metrics: nil, views: ["view1": view1]))

    // Subview2
    let view2 = NSView()
    view2.translatesAutoresizingMaskIntoConstraints = false
    view2.wantsLayer = true
    view2.layer?.backgroundColor = NSColor.green.cgColor
    documentView.addSubview(view2)
    documentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view2]|", options: [], metrics: nil, views: ["view2": view2]))

    // Subview3
    let view3 = NSView()
    view3.translatesAutoresizingMaskIntoConstraints = false
    view3.wantsLayer = true
    view3.layer?.backgroundColor = NSColor.blue.cgColor
    documentView.addSubview(view3)
    documentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view3]|", options: [], metrics: nil, views: ["view3": view3]))

    // Vertical autolayout
    documentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view1(==100)][view2(==200)][view3(==300)]", options: [], metrics: nil, views: ["view1": view1, "view2": view2, "view3": view3]))
    documentView.addConstraint(NSLayoutConstraint(item: documentView, attribute: .bottom, relatedBy: .equal, toItem: view3, attribute: .bottom, multiplier: 1.0, constant: 0))

введите описание изображения здесь

person brianLikeApple    schedule 26.09.2017
comment
Я так долго это искал! Большое спасибо за то, что предоставили это, это было именно то, что я искал, и сэкономил мне часы! - person chl; 22.01.2018

Ответ Брайана правильный, вот как создать NSStackView внутри NSScrollView в Swift 4.2.

См. https://github.com/onmyway133/blog/issues/173.

Возможно, вам придется перевернуть NSClipView

final class FlippedClipView: NSClipView {
  override var isFlipped: Bool {
    return true
  }
}


private func setup() {
  setupScrollView()
  setupStackView()
}

private func setupScrollView() {
  view.addSubview(scrollView)
  scrollView.translatesAutoresizingMaskIntoConstraints = false
  scrollView.hasVerticalScroller = true
  scrollView.drawsBackground = false

  NSLayoutConstraint.activate([
    scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
    scrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
    scrollView.topAnchor.constraint(equalTo: view.topAnchor),
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -30),

    scrollView.heightAnchor.constraint(equalToConstant: 400)
  ])

  let clipView = FlippedClipView()
  clipView.drawsBackground = false
  scrollView.contentView = clipView
  clipView.translatesAutoresizingMaskIntoConstraints = false
  NSLayoutConstraint.activate([
    clipView.leftAnchor.constraint(equalTo: scrollView.leftAnchor),
    clipView.rightAnchor.constraint(equalTo: scrollView.rightAnchor),
    clipView.topAnchor.constraint(equalTo: scrollView.topAnchor),
    clipView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
  ]
  scrollView.documentView = stackView

  stackView.translatesAutoresizingMaskIntoConstraints = false
  NSLayoutConstraint.activate([
    stackView.leftAnchor.constraint(equalTo: clipView.leftAnchor),
    stackView.topAnchor.constraint(equalTo: clipView.topAnchor),
    stackView.rightAnchor.constraint(equalTo: clipView.rightAnchor),
    // NOTE: No need for bottomAnchor
  ])
}

private func setupStackView() {
  stackView.orientation = .vertical
  stackView.edgeInsets = NSEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)

  NSLayoutConstraint.activate([
    myRowView.heightAnchor.constraint(equalToConstant: 40)
  ])

  myRowView.onPress = { [weak self] in
    self?.doSomething()
  }

  stackView.addArrangedSubview(myRowView)
}
person onmyway133    schedule 18.03.2019

Вот пример NSStackView внутри NSScrollView программно.

Я использую snapkit, чтобы он был кратким

// Create NSScrollView and add it as a subview in desired location
let scrollView = NSScrollView()
scrollView.borderType = .noBorder
scrollView.verticalScrollElasticity = .none
addSubview(scrollView)
scrollView.snp.makeConstraints { $0.edges.equalToSuperview() }

// Assign an instance of NSClipView to `contentView` property of `NSScrollView`
let clipView = NSClipView()
scrollView.contentView = clipView
clipView.snp.makeConstraints { $0.edges.equalTo(scrollView) }

// Assign whatever view you want to put inside scroll view
// to the `documentView` property. All note the constraints added.
// I have added just 3 constraints
scrollView.documentView = stackView
stackView.snp.makeConstraints { $0.top.bottom.left.equalTo(clipView) }

Обратите внимание, что я не использую translatesAutoresizingMaskIntoConstraints после добавления представления в качестве подпредставления, потому что snapkit обрабатывает его внутренне.

Если вы не используете snapkit, вам нужно будет выполнить translatesAutoresizingMaskIntoConstraints в подпредставлении

person Kaunteya    schedule 05.04.2020