13

UIViewに適合するようにCGPathをスケールダウンまたはスケールアップする方法を知る必要がありますか?

背景色を黄色に設定します。ビューをはっきりと見るには

self.frame = CGRectMake(0, 0, 181, 154);
self.backgroundColor = [UIColor yellowColor];

CAShapeLayerを描画します

CAShapeLayer *shape = [CAShapeLayer layer];
shape.path = aPath;

shape.strokeColor = [[UIColor blueColor] CGColor];
shape.lineWidth = 5;
shape.fillColor = [[UIColor clearColor] CGColor];

[self.layer addSublayer:shape];

それから私はこれを手に入れます: ここに画像の説明を入力してください

私が欲しいのはこれです: ここに画像の説明を入力してください

開発者に感謝します:)

4

3 に答える 3

35

私はあなたがあなたの視界に合うように形を(歪ませることなく)完全に塗りつぶしたいと思っていると仮定しています。また、質問にはCAShapeLayerのタグが付けられているため、パスを含むシェイプレイヤーが既にあると想定しています。


この場合、シェイプレイヤーパスのバウンディングボックスを取得し、パスに適用する適切な倍率を計算します。

形状とそれが適合すると思われるビューのアスペクト比に応じて、倍率を決定する幅または高さのいずれかになります。

スケール係数を取得したら、パスに適用する変換を作成します。パスは(0,0)から始まらない可能性があるため、変換内のパスをバウンディングボックスの原点に変換(移動)することもできます。

新しいパスをビューの中央に配置する場合は、移動する量を計算する必要があります。必要がなければそのコードをコメントアウトできますが、この回答を読んでいる他の人にも含めました。

最後に、新しいパスがあるので、新しいシェイプレイヤーを作成し、パスを割り当て、適切にスタイルを設定して、ビューに追加するだけです。

// I'm assuming that the view and original shape layer is already created
CGRect boundingBox = CGPathGetBoundingBox(shapeLayer.path);

CGFloat boundingBoxAspectRatio = CGRectGetWidth(boundingBox)/CGRectGetHeight(boundingBox);
CGFloat viewAspectRatio = CGRectGetWidth(viewToFitIn.frame)/CGRectGetHeight(viewToFitIn.frame);

CGFloat scaleFactor = 1.0;
if (boundingBoxAspectRatio > viewAspectRatio) {
    // Width is limiting factor
    scaleFactor = CGRectGetWidth(viewToFitIn.frame)/CGRectGetWidth(boundingBox);
} else {
    // Height is limiting factor
    scaleFactor = CGRectGetHeight(viewToFitIn.frame)/CGRectGetHeight(boundingBox);
}


// Scaling the path ...
CGAffineTransform scaleTransform = CGAffineTransformIdentity;
// Scale down the path first
scaleTransform = CGAffineTransformScale(scaleTransform, scaleFactor, scaleFactor);
// Then translate the path to the upper left corner
scaleTransform = CGAffineTransformTranslate(scaleTransform, -CGRectGetMinX(boundingBox), -CGRectGetMinY(boundingBox));

// If you want to be fancy you could also center the path in the view
// i.e. if you don't want it to stick to the top.
// It is done by calculating the heigth and width difference and translating
// half the scaled value of that in both x and y (the scaled side will be 0)
CGSize scaledSize = CGSizeApplyAffineTransform(boundingBox.size, CGAffineTransformMakeScale(scaleFactor, scaleFactor));
CGSize centerOffset = CGSizeMake((CGRectGetWidth(viewToFitIn.frame)-scaledSize.width)/(scaleFactor*2.0),
                                 (CGRectGetHeight(viewToFitIn.frame)-scaledSize.height)/(scaleFactor*2.0));
scaleTransform = CGAffineTransformTranslate(scaleTransform, centerOffset.width, centerOffset.height);
// End of "center in view" transformation code

CGPathRef scaledPath = CGPathCreateCopyByTransformingPath(shapeLayer.path,
                                                          &scaleTransform);

// Create a new shape layer and assign the new path
CAShapeLayer *scaledShapeLayer = [CAShapeLayer layer];
scaledShapeLayer.path = scaledPath;
scaledShapeLayer.fillColor = [UIColor blueColor].CGColor;
[viewToFitIn.layer addSublayer:scaledShapeLayer];

CGPathRelease(scaledPath); // release the copied path

私のサンプルコード(および形状)では、次のようになりました

ここに画像の説明を入力してください

于 2013-04-10T21:30:46.850 に答える
8

DavidRönnqvistの回答の迅速な4.0バージョン

 func resizepath(Fitin frame : CGRect , path : CGPath) -> CGPath{


            let boundingBox = path.boundingBox
            let boundingBoxAspectRatio = boundingBox.width / boundingBox.height
            let viewAspectRatio = frame.width  / frame.height
            var scaleFactor : CGFloat = 1.0
            if (boundingBoxAspectRatio > viewAspectRatio) {
                // Width is limiting factor

                scaleFactor = frame.width / boundingBox.width
            } else {
                // Height is limiting factor
                scaleFactor = frame.height / boundingBox.height
            }


            var scaleTransform = CGAffineTransform.identity
            scaleTransform = scaleTransform.scaledBy(x: scaleFactor, y: scaleFactor)
            scaleTransform.translatedBy(x: -boundingBox.minX, y: -boundingBox.minY)

        let scaledSize = boundingBox.size.applying(CGAffineTransform (scaleX: scaleFactor, y: scaleFactor))
       let centerOffset = CGSize(width: (frame.width - scaledSize.width ) / scaleFactor * 2.0, height: (frame.height - scaledSize.height) /  scaleFactor * 2.0 )
        scaleTransform = scaleTransform.translatedBy(x: centerOffset.width, y: centerOffset.height)
        //CGPathCreateCopyByTransformingPath(path, &scaleTransform)
        let  scaledPath = path.copy(using: &scaleTransform)


        return scaledPath!
    }
于 2017-12-25T12:55:45.183 に答える
2

scaleFactor * 2Tarekの回答に基づいていますが、リファクタリングされ、バグが修正された、DavidRönnqvistのSwift5バージョン:

extension CGPath {
    func resized(to rect: CGRect) -> CGPath {
        let boundingBox = self.boundingBox
        let boundingBoxAspectRatio = boundingBox.width / boundingBox.height
        let viewAspectRatio = rect.width / rect.height
        let scaleFactor = boundingBoxAspectRatio > viewAspectRatio ?
            rect.width / boundingBox.width :
            rect.height / boundingBox.height

        let scaledSize = boundingBox.size.applying(CGAffineTransform(scaleX: scaleFactor, y: scaleFactor))
        let centerOffset = CGSize(
            width: (rect.width - scaledSize.width) / (scaleFactor * 2),
            height: (rect.height - scaledSize.height) / (scaleFactor * 2)
        )

        var transform = CGAffineTransform.identity
            .scaledBy(x: scaleFactor, y: scaleFactor)
            .translatedBy(x: -boundingBox.minX + centerOffset.width, y: -boundingBox.minY + centerOffset.height)

        return copy(using: &transform)!
    }
}
于 2021-07-07T07:51:20.813 に答える