正方形の画像を角の丸い画像にマスクするにはどうすればよいですか?
8 に答える
CoreGraphicsを使用して、次のコードスニペットで長方形のパスを作成できます。
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight)
{
float fw, fh;
if (ovalWidth == 0 || ovalHeight == 0) {
CGContextAddRect(context, rect);
return;
}
CGContextSaveGState(context);
CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextScaleCTM (context, ovalWidth, ovalHeight);
fw = CGRectGetWidth (rect) / ovalWidth;
fh = CGRectGetHeight (rect) / ovalHeight;
CGContextMoveToPoint(context, fw, fh/2);
CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
CGContextClosePath(context);
CGContextRestoreGState(context);
}
次に、CGContextClip(context);を呼び出します。長方形のパスにクリップします。これで、画像の描画を含むすべての描画が、丸い長方形にクリップされます。
例として、「image」がUIImageであり、これがdrawRect:メソッドにあると仮定します。
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
addRoundedRectToPath(context, self.frame, 10, 10);
CGContextClip(context);
[image drawInRect:self.frame];
CGContextRestoreGState(context);
これは、iPhone 3.0 以降で利用できるさらに簡単な方法です。すべてのビューベースのオブジェクトには、関連付けられたレイヤーがあります。各レイヤーにはコーナー半径を設定できます。これにより、必要なものが得られます。
UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
// Get the Layer of any view
CALayer * layer = [roundedView layer];
[layer setMasksToBounds:YES];
[layer setCornerRadius:10.0];
// You can even add a border
[layer setBorderWidth:4.0];
[layer setBorderColor:[[UIColor blueColor] CGColor]];
これらのメソッドを使用するには、以下を追加する必要がある場合があります。
#import <QuartzCore/QuartzCore.h>
これは古いニュースだと思いますが、少し要約すると:
(1) 画面に表示される UIView (UIImageView など) に丸みを帯びた角を適用する方法と (2) 正方形の画像 (つまり、UIImage) をマスクする方法) 角の丸い新しい画像を生成します。
(1)については、CoreAnimation を使用して view.layer.cornerRadius プロパティを設定するのが最も簡単な方法です。
// Because we're using CoreAnimation, we must include QuartzCore.h
// and link QuartzCore.framework in a build phases
#import <QuartzCore/QuartzCore.h>
// start with an image
UIImage * fooImage = [UIImage imageNamed:@"foo.png"];
// put it in a UIImageView
UIView * view = [UIImageView alloc] initWithImage:fooImage];
// round its corners. This mask now applies to the view's layer's *background*
view.layer.cornerRadius = 10.f
// enable masksToBounds, so the mask applies to its foreground, the image
view.layer.masksToBounds = YES;
(2) については、UIKit グラフィック操作を使用するのが最善の方法です。
// start with an image
UIImage * fooImage = [UIImage imageNamed:@"foo.png"];
CGRect imageRect = CGRectMake(0, 0, fooImage.size.width, fooImage.size.height);
// set the implicit graphics context ("canvas") to a bitmap context for images
UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0);
// create a bezier path defining rounded corners
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.f];
// use this path for clipping in the implicit context
[path addClip];
// draw the image into the implicit context
[fooImage drawInRect:imageRect];
// save the clipped image from the implicit context into an image
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
// cleanup
UIGraphicsEndImageContext();
問題 (2) の厄介な点は、CoreAnimation の view.layer.mask プロパティを使用してすべての操作を実行できると思われることです。renderInContext:
しかし、マスクされたレイヤーから UIImage を生成するために使用するCALayer メソッドがマスクを無視しているように見えるため、それはできません。さらに悪いことに、のドキュメントでrenderInContext:
はこれについて言及されておらず、OSX 10.5 の動作についてのみ言及されています。
さらなるコンテキスト: (2) に対する上記のアプローチは、より基本的な CoreGraphics 機能の周りに UIKit のラッパーを使用しています。CoreGraphics 呼び出しを直接使用して同じことを行うことができます-それが選択された答えが行っていることです-しかし、曲線と線から手動で丸みを帯びた四角形のベジエパスを構築する必要があり、CoreGraphics が使用するという事実を補う必要もありますUIKit に関して反転された描画座標系。
この投稿を参照してください-非常に簡単な答え
UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
// Get the Layer of any view
CALayer * l = [roundedView layer];
[l setMasksToBounds:YES];
[l setCornerRadius:10.0];
とてもシンプルです。self.profileImageView.layer.cornerRadius = self.profileImageView.frame.size.width / 2; self.profileImageView.clipsToBounds = はい;
すべてのビューには、レイヤー プロパティがバンドルされています。したがって、上記の最初の行は、レイヤー オブジェクト (つまり、CALayer クラスのインスタンス) の角の半径を設定することです。正方形の画像から円形の画像を作成するには、半径を UIImageView の幅の半分に設定します。たとえば、正方形の画像の幅が 100 ピクセルの場合。半径は 50 ピクセルに設定されます。次に、レイヤーを機能させるために clipsToBounds プロパティを YES に設定する必要があります。
私はこの方法を使用します。
+ (UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size;
{
UIImage *img = nil;
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context,
color.CGColor);
CGContextFillRect(context, rect);
img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
どちらの方法も機能しますが、使用する場所によって違いが現れます。
例: セルが他のラベルなどと一緒に画像を表示するテーブル ビューがあり、レイヤーを使用して cornerRadius を設定する場合、スクロールは大きな打撃を受けます。ギクシャクします。
テーブルビューセルの画像にレイヤーを使用していたときにこの問題に直面し、そのジャーキネスの原因を突き止めようとして、CALayer が原因であることがわかりました。
NilObject で説明されている drawRect で処理を行う最初のソリューションを使用しました。スクロールがシルクのように滑らかで、それは魅力のように機能します。
一方、これをポップオーバー ビューなどの静的ビューで使用する場合は、レイヤーを使用するのが最も簡単な方法です。
前述したように、どちらの方法もうまく機能しますが、使用する場所に基づいて決定する必要があります。
algalに基づいて構築された、UIImage カテゴリに入れると便利ないくつかのメソッドを次に示します。
- (UIImage *) roundedCornerImageWithRadius:(CGFloat)radius
{
CGRect imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
UIGraphicsBeginImageContextWithOptions(imageRect.size,NO,0.0); //scale 0 yields better results
//create a bezier path defining rounded corners and use it for clippping
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:radius];
[path addClip];
// draw the image into the implicit context
[self drawInRect:imageRect];
// get image and cleanup
UIImage *roundedCornerImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return roundedCornerImage;
}
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size andCornerRadius:(CGFloat)radius
{
UIImage *image = nil;
if (size.width == 0 || size.height == 0) {
size = CGSizeMake(1.0, 1.0);
}
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
UIGraphicsBeginImageContextWithOptions(rect.size,NO,0.0); //yields sharper results than UIGraphicsBeginImageContext(rect.size)
CGContextRef context = UIGraphicsGetCurrentContext();
if (context)
{
CGContextSetFillColorWithColor(context, [color CGColor]);
if (radius > 0.0) {
//create a bezier path defining rounded corners and use it for clippping
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
[path addClip];
CGContextAddPath(context, path.CGPath);
}
CGContextFillRect(context, rect);
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return image;
}