Как я должен обернуть пользовательский NSView в NSScrollView? - PullRequest
5 голосов
/ 26 августа 2010

Какао NSScrollView ужасно мало объяснено. Я надеюсь, что кто-то здесь знает, о чем все это, и может сэкономить мне несколько секунд.

Итак, у меня есть собственный NSView. Я реализую -drawRect: чтобы он что-то рисовал, заливал себя цветом, что угодно. Затем у меня есть NSScrollView, обертывающий его (настраиваемый через интерфейс Builder).

Теперь внутреннее, пользовательское представление должно иметь размер, превышающий размер, который умещается во внешнем представлении прокрутки - для его прокрутки. Это я понимаю. Я случайно настроил его так, чтобы представление прокрутки приспосабливалось к размеру окружающего окна, но это не должно иметь значения.

Я переопределил метод -frame моего внутреннего представления, чтобы получить кадр размером не менее 1000x1000.

- (NSRect)frame {
    CGFloat w = 1000;
    CGFloat h = 1000;
    if (self.superview.bounds.size.width > w)
        w = self.superview.bounds.size.width;
    if (self.superview.bounds.size.height > h)
        h = self.superview.bounds.size.height;
    return NSMakeRect(0, 0, w, h);
}

Вот результат, который мне трудно интерпретировать:

  • Я могу прокручивать, когда представление прокрутки охватывает область, меньшую, чем 1000x1000

НО

  • Единственная область, заполненная цветом (т. Е. My -drawRect: метод имеет какое-либо влияние) -

    • равный границам прокрутки
    • расположен в (0,0. Я использую перевернутый, так что вверху слева, и он оказывается за пределами видимой области после прокрутки.
  • Видимая область, которая находится за пределами этого нерелевантного прямоугольника, вообще не закрашивается.

Я не знаю ничего, кроме этого момента. Это кажется подобно тому, как прямоугольник для рисования обрезается до положения вида прокрутки в окне, размера или чего-то еще, но он не учитывает прокручиваемое «местоположение».

Следует отметить, что я действительно не ожидаю, что что-нибудь еще случится. Я чувствую, что пропускаю кусок, но не могу найти какой. Извините за стену текста, но я не могу объяснить лучше сейчас. Я надеюсь, что легче ответить, чем спросить.

С уважением и надеждой,

Не Рик Эстли

Ответы [ 3 ]

3 голосов
/ 26 августа 2010

Это очень-очень-очень плохая идея перезаписать -frame. Существует так много, что зависит от фактической переменной экземпляра, имеющей правильное значение. Вместо этого попробуйте установить кадр на тот, который вы хотите, используя setFrame:, который может решить все ваши проблемы, если вам повезет ...

2 голосов
/ 26 августа 2010

Использование NSScroller действительно основано на четком понимании парадигмы MVC.Документы Apple действительно фокусируются на показе фотографии и набора текста, но не более того. Использование NSScrollView - это то, с чем я боролся в прошлом.

Прежде всего, не переопределяют frame.Используйте setFrame, чтобы сообщить scrollView, насколько велика рабочая область, а затем просто нарисуйте область, охватываемую рамкой.Как я понимаю, обычай NSView и охватывающий NSScrollView позаботятся обо всем остальном, например, что рисовать, где, когда.Другими словами, игнорируйте границы rect, переданные в drawRect, и вместо этого рисуйте в границах кадра, который вы отправили на scrollView;не беспокойтесь о том, что видно, а что нет, потому что это работа фреймворка.

Вот здесь и возникает парадигма MVC: setFrame следует использовать при обновлении модели.Таким образом, если объект выходит за пределы текущих границ кадра, используйте setFrame, чтобы установить новые расширенные границы, а затем начертите в этой области.

2 голосов
/ 26 августа 2010

Я согласен с предупреждением Макса, что вы не должны переопределять -frame. Если вы хотите ограничить установленный кадр, переопределите его установщик (-setFrame:) и назначенный инициализатор (-initWithFrame:) и отрегулируйте предлагаемый кадр по желанию.

Что касается вашей общей проблемы, мне интересно, если ваша проблема концептуальная. Аргумент -drawRect: (грязный прямоугольник, который вас просят перерисовать) полезен, если вы рисуете что-то, что вы можете перерисовывать постепенно по частям (например, сетка - любые блоки сетки, пересекающие dirtyRect, могут быть перерисованы, а остальные игнорируются). Если вы делаете что-то, что должно быть полностью перерисовано, вы должны использовать [self bounds], а не грязный прямоугольник, переданный в drawRect.

Например, если у вас есть только стандартный градиентный фон, из dirtyRect трудно определить, какую часть градиента перерисовать, и бесконечно проще просто перерисовать весь вид с градиентом, полностью игнорируя dirtyRect.

Вы правы, предполагая, что при прокрутке обычно будет перерисовываться только область вашего изображения, видимая прямоугольником клипа вида прокрутки. Кроме того, необходимо учитывать взаимодействие с -copiesOnScroll представления прокрутки.

Надеюсь, это поможет.

...