gpt4 book ai didi

ios - UIKit 动态 : recognize rounded Shapes and Boundaries

转载 作者:可可西里 更新时间:2023-11-01 06:24:35 24 4
gpt4 key购买 nike

我正在编写一个应用程序,我在其中使用 UIKit Dynamics 来模拟不同圈子之间的交互。

我使用以下代码创建我的圈子:

self = [super initWithFrame:CGRectMake(location.x - radius/2.0, location.y - radius/2, radius, radius)];
if (self) {
[self.layer setCornerRadius: radius /2.0f];
self.clipsToBounds = YES;
self.layer.masksToBounds = YES;
self.backgroundColor = color;
self.userInteractionEnabled = NO;
}
return self;

其中 location 表示圆的所需位置,radius 表示其半径。

然后我将这些圆圈添加到不同的 UIBehaviours,方法是:

[_collision addItem:circle];
[_gravity addItem:circle];
[_itemBehaviour addItem:circle];

itemBaviour 定义如下:

_itemBehaviour = [[UIDynamicItemBehavior alloc] initWithItems:@[square]];
_itemBehaviour.elasticity = 1;
_itemBehaviour.friction = 0;
_itemBehaviour.resistance = 0;
_itemBehaviour.angularResistance = 0;
_itemBehaviour.allowsRotation = NO;

我遇到的问题是,我的圆圈表现得像正方形。当以某种方式被击中时,它们会获得角动量并失去速度。如果它们再次碰撞,有时角动量会再次恢复为速度。这对于正方形来说看起来很正常,但是当 View 是圆形时,就像我的情况一样,这种行为看起来很奇怪而且不自然。

打开一些调试选项,我做了这个截图: small circle is actually a square

如您所见,圆圈看起来是正方形。

所以我的问题是,我怎样才能创建一个真正的圆形 UIVIew,并且在 UIKit Dynamics 中表现如此?

最佳答案

我知道这个问题早于 iOS 9,但为了 future 读者的利益,您现在可以使用 collisionBoundsType 定义 View UIDynamicItemCollisionBoundsTypePath 和一个循环 collisionBoundingPath .

因此,虽然您不能“创建一个真正的圆形 UIView”,但您可以定义一个路径来定义在 View 内呈现的形状以及动画师,产生圆形 View 的效果(即使 View 本身显然仍然是矩形,因为所有 View 都是):

@interface CircleView: UIView

@property (nonatomic) CGFloat lineWidth;
@property (nonatomic, strong) CAShapeLayer *shapeLayer;

@end

@implementation CircleView

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self configure];
}
return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self configure];
}
return self;
}

- (instancetype)init {
return [self initWithFrame:CGRectZero];
}

- (void)configure {
self.translatesAutoresizingMaskIntoConstraints = false;

// create shape layer for circle

self.shapeLayer = [CAShapeLayer layer];
self.shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
self.shapeLayer.fillColor = [[[UIColor blueColor] colorWithAlphaComponent:0.5] CGColor];
self.lineWidth = 3;
[self.layer addSublayer:self.shapeLayer];
}

- (void)layoutSubviews {
[super layoutSubviews];

// path of shape layer is with respect to center of the `bounds`

CGPoint center = CGPointMake(self.bounds.origin.x + self.bounds.size.width / 2, self.bounds.origin.y + self.bounds.size.height / 2);
self.shapeLayer.path = [[self circularPathWithLineWidth:self.lineWidth center:center] CGPath];
}

- (UIDynamicItemCollisionBoundsType)collisionBoundsType {
return UIDynamicItemCollisionBoundsTypePath;
}

- (UIBezierPath *)collisionBoundingPath {
// path of collision bounding path is with respect to center of the dynamic item, so center of this path will be CGPointZero

return [self circularPathWithLineWidth:0 center:CGPointZero];
}

- (UIBezierPath *)circularPathWithLineWidth:(CGFloat)lineWidth center:(CGPoint)center {
CGFloat radius = (MIN(self.bounds.size.width, self.bounds.size.height) - self.lineWidth) / 2;
return [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:true];
}

@end

然后,当您进行碰撞时,它将遵循 collisionBoundingPath 值:

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

// create circle views

CircleView *circle1 = [[CircleView alloc] initWithFrame:CGRectMake(60, 100, 80, 80)];
[self.view addSubview:circle1];

CircleView *circle2 = [[CircleView alloc] initWithFrame:CGRectMake(250, 150, 120, 120)];
[self.view addSubview:circle2];

// have them collide with each other

UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[circle1, circle2]];
[self.animator addBehavior:collision];

// with perfect elasticity

UIDynamicItemBehavior *behavior = [[UIDynamicItemBehavior alloc] initWithItems:@[circle1, circle2]];
behavior.elasticity = 1;
[self.animator addBehavior:behavior];

// and push one of the circles

UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[circle1] mode:UIPushBehaviorModeInstantaneous];
[push setAngle:0 magnitude:1];

[self.animator addBehavior:push];

产生:

enter image description here

顺便提一下,the documentation概述了路径的一些限制:

The path object you create must represent a convex polygon with counter-clockwise or clockwise winding, and the path must not intersect itself. The (0, 0) point of the path must be located at the center point of the corresponding dynamic item. If the center point does not match the path’s origin, collision behaviors may not work as expected.

但是一个简单的圆形路径很容易满足这些标准。


或者,对于 Swift 用户:

class CircleView: UIView {
var lineWidth: CGFloat = 3

var shapeLayer: CAShapeLayer = {
let _shapeLayer = CAShapeLayer()
_shapeLayer.strokeColor = UIColor.blue.cgColor
_shapeLayer.fillColor = UIColor.blue.withAlphaComponent(0.5).cgColor
return _shapeLayer
}()

override func layoutSubviews() {
super.layoutSubviews()

layer.addSublayer(shapeLayer)
shapeLayer.lineWidth = lineWidth
let center = CGPoint(x: bounds.midX, y: bounds.midY)
shapeLayer.path = circularPath(lineWidth: lineWidth, center: center).cgPath
}

private func circularPath(lineWidth: CGFloat = 0, center: CGPoint = .zero) -> UIBezierPath {
let radius = (min(bounds.width, bounds.height) - lineWidth) / 2
return UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
}

override var collisionBoundsType: UIDynamicItemCollisionBoundsType { return .path }

override var collisionBoundingPath: UIBezierPath { return circularPath() }
}

class ViewController: UIViewController {

let animator = UIDynamicAnimator()

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

let circle1 = CircleView(frame: CGRect(x: 60, y: 100, width: 80, height: 80))
view.addSubview(circle1)

let circle2 = CircleView(frame: CGRect(x: 250, y: 150, width: 120, height: 120))
view.addSubview(circle2)

animator.addBehavior(UICollisionBehavior(items: [circle1, circle2]))

let behavior = UIDynamicItemBehavior(items: [circle1, circle2])
behavior.elasticity = 1
animator.addBehavior(behavior)

let push = UIPushBehavior(items: [circle1], mode: .instantaneous)
push.setAngle(0, magnitude: 1)
animator.addBehavior(push)
}

}

关于ios - UIKit 动态 : recognize rounded Shapes and Boundaries,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23347466/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com