Эффект инерции ScrollView вручную, iOS, Swift - PullRequest
1 голос
/ 07 марта 2020

У меня есть UICollectionView, который я перетаскиваю из кода (не спрашивайте меня, почему это очень длинная история :)). И мой код работает довольно хорошо:

func move(prevPoint: CGPoint, curPoint: CGPoint) {
    let xDiff = curPoint.x - prevPoint.x
    let yDiff = curPoint.y - prevPoint.y
    let xSign =  xDiff == 0 ? 1 : (xDiff / abs(xDiff))
    let ySign = yDiff == 0 ? 1 : (yDiff / abs(yDiff))

    let x = max(min(abs(xDiff), maxPickerStep), minPickerStep) * -xSign * xMultiplier
    let y = max(min(abs(yDiff), maxPickerStep), minPickerStep) * -ySign

    let offset = CGPoint(x: collectionView.contentOffset.x + x, y: collectionView.contentOffset.y)
    let cell = (collectionView.visibleCells.first as? ColorsCollectionViewCell)
    let innerOffset = cell?.colorCollectionView.contentOffset ?? .zero
    let inset = (cell?.colorCollectionView.contentInset.top ?? 0) * 2
    let innerYContentOffset = min(max(innerOffset.y + y, -inset), (cell?.colorCollectionView.contentSize.height ?? 0) - inset)

    cell?.colorCollectionView.contentOffset = CGPoint(x: innerOffset.x, y: innerYContentOffset)
    collectionView.contentOffset = offset
}

Но в дополнение к прокрутке я хочу добиться того же эффекта, что и в UICollectionView, когда scrollView движется по инерции после того, как пользователь убирает палец. Спасибо.

Ответы [ 2 ]

1 голос
/ 22 марта 2020

Первым делом, я думаю, что ручное перемещение вида прокрутки - это то, чего я бы избегал. Вероятно, есть нечто гораздо более простое, чтобы выполнить необходимое вам поведение. Поэтому я настоятельно рекомендую вам и любому другому читателю не читать далее go далее при прочтении этого поста и вместо этого go вперед и попытаться решить проблему, которая в первую очередь направляла вас сюда.

Вы также можете задать еще один вопрос здесь о переполнении стека, чтобы, возможно, получить помощь, чтобы избежать ручного обновления позиции scrollView.


Так что, если вы все еще читаете, эту статью - это, вероятно, путь к go с реализацией чего-то, что действительно похоже на UIScrollView. Выполнение чего-либо еще, вероятно, действительно будет выглядеть и ощущаться ужасно.

По сути, оно состоит из использования UIKit Dynamics для управления инерцией.

Таким образом, вы можете создать объект, который соответствует UIDynamicItem (с ненулевым CGRect) и измените его центр вместо scrollView contentOffset, чем используйте UIDynamicAnimator и его UIDynamicBehavior, чтобы установить инерцию и соединить изменения во время анимации с соответствующим contentOffset в scrollView, используя UIDynamicBehavior's блок действия .

При условии, что у вас есть элемент, который является UIDynamicItem, и аниматором, который является UIDynamicAnimator, обработка распознавателя panGesture будет выглядеть примерно так:

func handlGestureRecognizer(panGesture: UIPanGestureRecognizer) {

    switch panGesture.state {
    case .began:
        self.animator.removeAllBehaviors()
    case .changed:
        // Update scroll view position
        break
    case .ended:
        var velocity = panGesture.velocity(in: panGesture.view!)
        velocity.x = -velocity.x
        velocity.y = -velocity.y   
        // You probably need to check for out of bound velocity too, and also put velocity.x to 0 if the scroll is only scrolling vertically

        // This is done to just save the current content offset and then change it alongside the animation from this starting point         
        item.center = scrollView.contentOffset

        let decelerationBehavior = UIDynamicItemBehavior(items: [item])
        decelerationBehavior.addLinearVelocity(velocity, for: item)
        decelerationBehavior.resistance = 2.0


        decelerationBehavior.action = {
            // Connect the item center to the scroll contentOffset. Probably something like this:
            scrollView.contentOffset = item.center
        }
        self.animator.addBehavior(decelerationBehavior)
    default:
        break
    }
}

Вам нужно просто поиграть со значениями поведения и быть осторожным со скоростью, которую вы вкладываете в поведение, с особой тщательностью при взгляде на крайние случаи (если вы, например, прокручиваете мин / макс)

PS: В конце концов я написано, я все еще верю, что вам настоятельно следует не делать этого и вместо этого go со стандартной прокруткой scrollView, избегая ручных обновлений.

0 голосов
/ 21 марта 2020

Вы можете попробовать поиграть с decelerationRate и посмотреть, удовлетворяет ли он вашим потребностям.

 collectionView.decelerationRate = UIScrollView.DecelerationRate(rawValue: 1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...