Pregunta

I have a horizontal UICollectionView with a custom UICollectionViewFlowLayout that has a UIAttachmentBehavior set on each cell to give it a bouncy feel when scrolling left and right. The behavior has the following properties:

attachmentBehavior.length = 1.0f;
attachmentBehavior.damping = 0.5f;
attachmentBehavior.frequency = 1.9f;

When a new cell is added to the collection view it's added at the bottom and then animated to its position also using a UIAttachmentBehavior. Naturally it bounces up and down a bit till it rests in its position. Everything is working as expected till now.

enter image description here

The problem I have starts appearing when the collection view is scrolled left or right before the newly added cell has come to rest. The adds left and right bounciness to the up and down one the cell already has from being added. This results in a very weird circular motion in the cell.

enter image description here

My question is, is it possible to stop the vertical motion of a UIAttachmentBehavior while the collection view is being scrolled? I've tried different approaches like using multiple attachment behaviors and disabling scrolling in the collection view till the newly added cell has come to rest, but non of them seem to stop this.

¿Fue útil?

Solución 6

I've resorted to disabling scrolling in the collection view for a specific amount of time after a new cell is added, then removing the attachment behavior after that time has passed using its action property, then adding a new attachment behavior again immediately.

That way I make sure the upwards animation stops before the collection view is scrolled left or right, but also the left/right bounciness is still there when scrolling.

Certainly not the most elegant solution but it works.

Otros consejos

One way to solve this is to use the inherited .action property of the attachment behavior.

You will need to set up a couple of variables first, something like (going from memory, untested code):

BOOL limitVerticalMovement = TRUE;
CGFloat staticCenterY = CGRectGetHeight(self.collectionView.frame) / 2;

Set these as properties of your custom UICollectionViewFlowLayout

When you create your attachment behavior:

UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:item attachedToAnchor:center];
attachment.damping = 1.0f;
attachment.frequency = 1.5f;
attachment.action = ^{
    if (!limitVerticalMovement) return;

    CGPoint center = item.center;
    center.y = staticCenterY;
    item.center = center;
};

Then you can turn the limiting function on and off by setting limitVerticalMovement as appropriate.

Have you tried manually removing animations from cells with CALayer's removeAllAnimations?

You'll want to remove the behaviour when the collection view starts scrolling, or perhaps greatly reduce the springiness so that it comes to rest smoothly, but quickly. If you think about it, what you're seeing is a realistic movement for the attachment behaviour you've described.

To keep the vertical bouncing at the same rate but prevent horizontal bouncing, you'd need to add other behaviours - like a collision behaviour with boundaries to the left and right of each added cell. This is going to increase the complexity of the physics a little, and may affect scrolling performance, but it would be worth a try.

Here's how I managed to do it. The FloatRange limits the range of the attachment, so if you want it to go all the way up and down the screen you just set really large numbers.

This goes inside func recognizePanGesture(sender: UIPanGestureRecognizer) {}

let location = sender.location(in: yourView.superview)
var direction = "Y"

var center = CGPoint(x: 0, y: 0)
if self.direction == "Y" {center.y = 1}
if self.direction == "X" {center.x = 1}

let sliding = UIAttachmentBehavior.slidingAttachment(with: youView, attachmentAnchor: location, axisOfTranslation: CGVector(dx: center.x, dy: center.y))

sliding.attachmentRange = UIFloatRange(minimum: -2000, maximum: 2000)
animator = UIDynamicAnimator(referenceView: self.superview!)
animator.addBehavior(sliding)

If you're using iOS 9 and above then sliding function within attachment class will work perfectly for that job:

class func slidingAttachmentWithItem(_ item: UIDynamicItem,
                attachmentAnchor point: CGPoint,
               axisOfTranslation axis: CGVector) -> Self

it can be used easily, and it's very effective for sliding Apple documentation

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top