UIDynamics stick together like SKNode

I'm trying to do Apple-Music floating bubbles animation with UIView's like below:

enter image description here

I found this code that does it with SceneKit: https://github.com/BellAppLab/BLBubbleFilters

It works fine. However, I want to write my own so I decided to port it to UIDynamics on iOS.

I have the following:

@interface PhysicsWorld : NSObject
@property (nonatomic, strong, readonly) UIFieldBehavior *gravityField;
@property (nonatomic, strong, readonly) UIFieldBehavior *magneticField;
@property (nonatomic, strong, readonly) UIDynamicItemBehavior *itemBehaviour;

- (instancetype)initWithView:(UIView *)view;
- (void)setCollisionBoundaryInsets:(UIEdgeInsets)insets;

- (void)addView:(PhysicsView *)view;
- (void)addBehaviour:(UIDynamicBehavior *)behaviour;
- (void)reset;
@end

@interface PhysicsWorld()
@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, strong) UICollisionBehavior *physicsBody;
@property (nonatomic, strong) NSMutableArray *behaviours;
@end

@implementation PhysicsWorld
- (instancetype)initWithView:(UIView *)view {
    if ((self = [super init])) {
        //Create gravity field.
        _gravityField = [UIFieldBehavior linearGravityFieldWithVector:CGVectorMake(0.0, 0.0)];

        //Create magnetic field.
        _magneticField = [UIFieldBehavior radialGravityFieldWithPosition:CGPointZero];
        _magneticField.region = [[UIRegion alloc] initWithRadius:10000];
        _magneticField.minimumRadius = 10000;
        _magneticField.strength = 8000;
        _magneticField.position = CGPointZero;

        //Create collision boundaries.
        _physicsBody = [[UICollisionBehavior alloc] init];
        [_physicsBody setCollisionMode:UICollisionBehaviorModeEverything];
        [_physicsBody setTranslatesReferenceBoundsIntoBoundary:YES];

        //Create item behaviour.
        _itemBehaviour = [[UIDynamicItemBehavior alloc] init];
        _itemBehaviour.allowsRotation = NO;
        _itemBehaviour.friction = 0.0;
        _itemBehaviour.resistance = 0.0;

        self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:view];

        [self.animator addBehavior:_gravityField];
        [self.animator addBehavior:_magneticField];
        [self.animator addBehavior:_itemBehaviour];
        [self.animator addBehavior:_physicsBody];

        self.behaviours = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)setCollisionBoundaryInsets:(UIEdgeInsets)insets {
    [self.physicsBody setTranslatesReferenceBoundsIntoBoundaryWithInsets:insets];
}

- (void)addView:(PhysicsView *)view {
    [self.gravityField addItem:view];
    [self.magneticField addItem:view];
    [self.itemBehaviour addItem:view];
    [self.physicsBody addItem:view];
}

- (void)addBehaviour:(UIDynamicBehavior *)behaviour {
    [self.animator addBehavior:behaviour];
    [self.behaviours addObject:behaviour];
}

- (void)reset {
    for (UIDynamicBehavior *behaviour in self.behaviours) {
        [self.animator removeBehavior:behaviour];
    }
    [self.behaviours removeAllObjects];
}
@end

and my world:

//Math:
CGFloat CGPointDistance(CGPoint a, CGPoint b) {
    return hypot(b.x - a.x, b.y - a.y);
}

CGFloat randomRange(CGFloat min, CGFloat max) {
    return ((CGFloat)arc4random()) / ((CGFloat)UINT32_MAX) * (max - min) + min;
}


@interface ContainerView()
@property (nonatomic, assign) CGFloat pushStrength;
@property (nonatomic, strong) PhysicsWorld *physicsWorld;
@property (nonatomic, strong) NSMutableArray<PhysicsView *> *views;

@property (nonatomic, assign) bool isDragging;
@property (nonatomic, assign) bool isTapping;

@property (nonatomic, assign) CGPoint touchPoint;
@end

@implementation ContainerView
- (instancetype)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        self.physicsWorld = [[PhysicsWorld alloc] initWithView:self];
        self.views = [[NSMutableArray alloc] init];
        [self configure];
    }
    return self;
}

- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];

    [self configure];
}

- (UIView *)viewAtPoint:(CGPoint)point {
    return [self.views filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {

        return CGRectContainsPoint([evaluatedObject frame], point);

    }]].firstObject;
}

- (void)configure {
//    CGFloat strength = MAX(self.bounds.size.width, self.bounds.size.height);
//    CGFloat radius = sqrt(strength) * 100.0;

    self.pushStrength = 5.0;
    CGFloat strength = 8000;
    CGFloat radius = 10000;

    self.physicsWorld.magneticField.region = [[UIRegion alloc] initWithRadius:radius];
    self.physicsWorld.magneticField.minimumRadius = radius;
    self.physicsWorld.magneticField.strength = strength;
    self.physicsWorld.magneticField.position = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0);
    self.physicsWorld.magneticField.falloff = 2.0;

    [self.physicsWorld setCollisionBoundaryInsets:UIEdgeInsetsZero];

}

- (void)addView:(PhysicsView *)view {
    CGFloat x = randomRange(view.bounds.size.width, self.bounds.size.width - view.bounds.size.width);
    CGFloat y = randomRange(view.bounds.size.height, self.bounds.size.height - view.bounds.size.height);
    view.center = CGPointMake(x, y);


    [self addSubview:view];
    [self.views addObject:view];
    [self.physicsWorld addView:view];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (self.isTapping) return;

    UITouch *touch = [touches anyObject];
    if (!touch) return;

    [self reset];

    self.touchPoint = [touch locationInView:self];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    if (!touch) return;

    CGPoint plin = [touch previousLocationInView:self];
    CGPoint lin = [touch locationInView:self];
    CGFloat dx = lin.x - plin.x;
    CGFloat dy = lin.y - plin.y;
    CGFloat b = sqrt(pow(lin.x, 2) + pow(lin.y, 2));
    dx = b == 0 ? 0 : (dx / b);
    dy = b == 0 ? 0 : (dy / b);

    if (dx == 0 && dy == 0) {
        return;
    }

    CGFloat tx = dx < 0 ? -dx : dx;
    CGFloat ty = dy < 0 ? -dy : dy;
    if (tx < 0.001 && ty < 0.001) {
        return;
    }

    self.isDragging = YES;

    CGFloat w, h;
    CGVector direction;
    for (PhysicsView *view in self.views) {
        w = view.bounds.size.width;
        h = view.bounds.size.height;
        direction = CGVectorMake(self.pushStrength * dx, self.pushStrength * dy);

        if ((-w >= view.center.x || self.bounds.size.width + w <= view.center.x) && (view.center.x * dx > 0)) {
            direction.dx = 0;
        }
        if ((-h >= view.center.y || self.bounds.size.width + h <= view.center.y) && (view.center.y * dy > 0)) {
            direction.dy = 0;
        }

        UIPushBehavior *force = [[UIPushBehavior alloc] initWithItems:@[view] mode:UIPushBehaviorModeInstantaneous];
        force.pushDirection = direction;

        [self.physicsWorld addBehaviour:force];
    }
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (!self.isDragging || !self.isTapping) {
        UIView *view = [self.views filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {

            return evaluatedObject == [touches anyObject].view;
        }]].firstObject;

        if (view) {
            self.isDragging = false;
        }

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.physicsWorld reset];
        });
    }
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.isDragging = false;
    [self reset];
}

- (void)reset {
    self.touchPoint = CGPointZero;
    self.isDragging = NO;
    self.isTapping = NO;
}
@end

But then the views do NOT stick together! Instead I get:

enter image description here enter image description here

Any ideas what I'm doing wrong??? I wasn't able to port SKPhysicsBody to UIDynamics.. My smaller views go flying when I push them and the larger views move slower (I need to somehow make them all move at the same speed together).. Any ideas how I can get them to stick to each other and when not pushing them, they snap back to original positons?