重新定位/调整UIBezierPath大小

15

我有一个可拖动视图,其上有一个蒙版层。蒙版层上有一个UIBezierPath,它使视图上的某个区域变为透明(这是我想要的效果)。我的最终目标是通过传递一个CGRect来更改路径的位置和大小(而不是蒙版层!),该CGRect是根据我的视图和另一个矩形的交集计算出来的(基本上我想隐藏相交的区域)。

1)如何创建我的蒙版和路径(在我的视图上创建一个透明的矩形):

self.maskLayer = [CAShapeLayer layer];
self.maskLayer.frame = self.contentView.bounds;

//default path rect
CGRect const rect = CGRectMake(CGRectGetMidX(self.contentView.bounds) ,
                                     CGRectGetMidY(self.contentView.bounds),
                                     50,50);


path = [UIBezierPath bezierPathWithRect:rect];

[path appendPath:[UIBezierPath bezierPathWithRect:self.contentView.frame]];

self.maskLayer.path = path.CGPath;

self.maskLayer.fillRule = kCAFillRuleEvenOdd;

self.contentView.layer.mask = self.maskLayer;

我的问题是我找不到一种方法来调整/重新定位路径。我在网上搜索过,但找不到任何解决方案。

以下是我能想到的代码,但它并没有起作用:

//runs while the view is being dragged(using UIPanGestureRecognizer)
-(void)move{
 CGRect intersectedRect = CGRectIntersection(self.frame, self.productView.frame);
 path = [UIBezierPath bezierPathWithRect:intersectedRect];
[path appendPath:[UIBezierPath bezierPathWithRect:intersectedRect]];
[self.maskLayer setNeedsDisplay];
 }

如何在我的移动函数中仅操作masklayer的路径?谢谢!


第二个片段中你从哪里获取路径变量? 你在哪里设置遮罩层的路径? 为什么要将相同的矩形追加到路径中? - yurish
-(void)move{ CGRect intersectedRect = CGRectIntersection(self.frame, self.productView.frame); path = [UIBezierPath bezierPathWithRect:intersectedRect]; [path appendPath:[UIBezierPath bezierPathWithRect:self.contentView.frame]]; self.maskLayer.path = path.CGPath; self.maskLayer.fillRule = kCAFillRuleEvenOdd; self.contentView.layer.mask = self.maskLayer; } -(void)移动{ CGRect 相交矩形 = CGRectIntersection(self.frame, self.productView.frame); 路径 = [UIBezierPath bezierPathWithRect:相交矩形]; [路径 appendPath:[UIBezierPath bezierPathWithRect:self.contentView.frame]]; self.maskLayer.path = 路径.CGPath; self.maskLayer.fillRule = kCAFillRuleEvenOdd; self.contentView.layer.mask = self.maskLayer; } - Soc
现在它正在更新,但大约10秒后。你知道可能是为什么吗? - Soc
最好使用新代码更新您的问题。可能会有许多延迟发生。首先检查移动方法是否在没有延迟的情况下被调用。您是在主线程上调用move吗? - yurish
请打开另一个问题,其中包含更新的代码和有关如何以及为什么要为计算旋转新线程的详细信息。 - yurish
显示剩余4条评论
6个回答

18
// example path
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 100, 100) cornerRadius:4];

// scale it
CGFloat scale = 0.9;
[path applyTransform:CGAffineTransformMakeScale(scale, scale)];

// move it
CGSize translation = CGSizeMake(10, 5);
[path applyTransform:CGAffineTransformMakeTranslation(translation.width,
                                                      translation.height)];

// apply it
self.myLayer.path = path;

13

Swift版本

这是@hfossli的Swift代码:

// example path
let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 100, height: 100), cornerRadius: 4)

// scale it
let scale = CGFloat(0.9)
path.applyTransform(CGAffineTransformMakeScale(scale, scale))

// move it
let translation = CGSize(width: 10, height: 5)
path.applyTransform(CGAffineTransformMakeTranslation(translation.width,
    translation.height))

// apply it
self.myLayer.path = path

更新

在实际使用中,我发现创建 UIBezierPath 时使用不同的初始值比之后转换它更好。这可能取决于目的。


7

Swift 3扩展(如有需要,可使用factorX、factorY进行修改):

extension UIBezierPath
{
    
    func scaleAroundCenter(factor: CGFloat)
    {
        let beforeCenter = self.bounds.getCenter()
        
        // SCALE path by factor
        let scaleTransform = CGAffineTransform(scaleX: factor, y: factor)
        self.apply(scaleTransform)
        
        let afterCenter = self.bounds.getCenter()
        let diff = CGPoint(
            x: beforeCenter.x - afterCenter.x,
            y: beforeCenter.y - afterCenter.y)
        
        let translateTransform = CGAffineTransform(translationX: diff.x, y: diff.y)
        self.apply(translateTransform)
    }

SWIFT 5 UPDATE

extension UIBezierPath {

    func scaleAroundCenter(factor: CGFloat) {
        let beforeCenter = CGPoint(x: self.bounds.midX, y: self.bounds.midY)

        // SCALE path by factor
        let scaleTransform = CGAffineTransform(scaleX: factor, y: factor)
        self.apply(scaleTransform)

        let afterCenter = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
        let diff = CGPoint( x: beforeCenter.x - afterCenter.x, y: beforeCenter.y - afterCenter.y)

        let translateTransform = CGAffineTransform(translationX: diff.x, y: diff.y)
        self.apply(translateTransform)
    }

}

1
我不确定这是否解决了原帖作者的问题,但它确实解决了我的问题 :-) - Raj Kiran
1
顶级答案。谢谢。 - Hopreeeenjust

3
在您的移动方法中,您需要将更新后的路径分配给self.maskLayer.path

3

这是Swift 3或更高版本的代码。

func move(path: UIBezierPath, fromPoint: CGPoint, toPoint: CGPoint) {
    let moveX = toPoint.x - fromPoint.x
    let moveY = toPoint.y - fromPoint.y
    path.apply(CGAffineTransform(translationX: moveX, y: moveY))
}

func scale(path: UIBezierPath, fromSize: CGSize, toSize: CGSize) {
    if fromSize.width == 0 || fromSize.height == 0 {
        return
    }
    let scaleWidth = toSize.width / fromSize.width
    let scaleHeight = toSize.height / fromSize.height
    path.apply(CGAffineTransform(scaleX: scaleWidth, y: scaleHeight))
}

我该如何使用Swift4实现这个? - naohide_a
在我的情况下,它在Swift 5中运行。 - Md. Shofiulla

0

Swift 4

func tableView(_ tableView: UITableView, dragPreviewParametersForRowAt indexPath: IndexPath) -> UIDragPreviewParameters? {
    let cell = tableView.cellForRow(at: indexPath) as! ItemTableViewCell

    let previewParameters = UIDragPreviewParameters()
    let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height), cornerRadius: 4)
    let scale = CGFloat(0.85)
    path.apply(CGAffineTransform(scaleX: scale, y: scale))
    let translation = CGSize(width: 10, height: 5)
    path.apply(CGAffineTransform(translationX: translation.width, y: translation.height))
    previewParameters.visiblePath = path
    return previewParameters
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接