Индикатор межэлементного разрыва NSCollectionView имеет неправильную высоту

Я реализую приложение для macOS, в котором использую NSCollectionView как своего рода шкалу времени. Для этого я использую собственный подкласс NSCollectionViewFlowLayout по следующим причинам:

  1. Я хочу, чтобы элементы прокручивались только по горизонтали без перехода к следующей строке
  2. Только NSCollectionViewFlowLayout, похоже, может указать NSCollectionView не прокручивать по вертикали (вдохновение из здесь)

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

override func layoutAttributesForInterItemGap(before indexPath: IndexPath) -> NSCollectionViewLayoutAttributes?
{
    var result: NSCollectionViewLayoutAttributes? = nil

    // The itemLayoutAttributes dictionary is created in prepare() and contains
    // the layout attributes for every item in the collection view
    if indexPath.item < itemLayoutAttributes.count
    {
        if let itemLayout = itemLayoutAttributes[indexPath]
        {
            result = NSCollectionViewLayoutAttributes(forInterItemGapBefore: indexPath)
            result?.frame = NSRect(x: itemLayout.frame.origin.x - 4, y: itemLayout.frame.origin.y, width: 3, height: itemLayout.size.height)
        }
    }
    else
    {
        if let itemLayout = itemLayoutAttributes.reversed().first
        {
            result = NSCollectionViewLayoutAttributes(forInterItemGapBefore: indexPath)
            result?.frame = NSRect(x: itemLayout.value.frame.origin.x + itemLayout.value.frame.size.width + 4, y: itemLayout.value.frame.origin.y, width: 3, height: itemLayout.value.size.height)
        }
    }

    return result
}

Согласно документации indexPath, переданный методу, может находиться в диапазоне от 0 до количества элементов в представлении коллекции включая, если мы пытаемся отбросить после последнего элемента. Как видите, я возвращаю прямоугольник для индикатора промежутка между элементами, который должен иметь ширину 3 пикселя и такую ​​же высоту, как и элемент.

Хотя индикатор отображается в правильном x-положении с правильной шириной, его высота составляет всего 2 пикселя, независимо от того, какую высоту я перехожу.

Как это исправить?

NB: Если я временно изменил раскладку на NSCollectionViewFlowLayout, индикатор отобразится правильно.

Я отменяю следующие методы / свойства в NSCollectionViewFlowLayout:

  • подготовить()
  • collectionViewContentSize
  • layoutAttributesForElements (in rect: NSRect) -> [NSCollectionViewLayoutAttributes]
  • layoutAttributesForItem (в indexPath: IndexPath) -> NSCollectionViewLayoutAttributes?
  • shouldInvalidateLayout (forBoundsChange newBounds: NSRect) -> Bool
  • layoutAttributesForInterItemGap (перед indexPath: IndexPath) -> NSCollectionViewLayoutAttributes?

person Thorsten Dittmar    schedule 28.11.2019    source источник


Ответы (1)


Вам также может потребоваться переопределить layoutAttributesForDropTarget(at pointInCollectionView: NSPoint) -> NSCollectionViewLayoutAttributes.

В документации упоминается, что фрейм атрибутов, возвращаемых этим методом provides a bounding box for the gap, that will be used to position and size a drop target indicator (view).

Вы можете установить точку останова в своем коде перетаскивания после рисования индикатора перетаскивания (например, collectionView(:acceptDrop:indexPath:dropOperation:), а затем, когда точка останова будет достигнута во время сеанса перетаскивания, запустите отладчик представления Xcode, чтобы проверить представление индикатора перетаскивания после его добавления в представление коллекции.Таким образом вы можете быть уверены, что иерархия представлений верна и любые проблемы визуально очевидны.

person Andrew    schedule 04.08.2020