ビューの背後にあるビューがこの透明フレームを通して見えるように、内部に透明フレームを持つビューを作成しようとしていますが、この外側の領域は透けて見えません。したがって、本質的にはビュー内のウィンドウです。
このようなことをできるようにしたい:
CGRect hole = CGRectMake(100, 100, 250, 250);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextFillRect(context, rect);
CGContextAddRect(context, hole);
CGContextClip(context);
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillRect(context, rect);
ただし、クリアは黒を上書きしないため、背景全体が黒になります。これらの線に沿ったアイデアはありますか?
これは私の実装です(透明部分のあるビューが必要だったため)。
ヘッダー(.h)ファイル:
// Subclasses UIview to draw transparent rects inside the view
#import <UIKit/UIKit.h>
@interface PartialTransparentView : UIView {
NSArray *rectsArray;
UIColor *backgroundColor;
}
- (id)initWithFrame:(CGRect)frame backgroundColor:(UIColor*)color andTransparentRects:(NSArray*)rects;
@end
実装(.m)ファイル:
#import "PartialTransparentView.h"
#import <QuartzCore/QuartzCore.h>
@implementation PartialTransparentView
- (id)initWithFrame:(CGRect)frame backgroundColor:(UIColor*)color andTransparentRects:(NSArray*)rects
{
backgroundColor = color;
rectsArray = rects;
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.opaque = NO;
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
[backgroundColor setFill];
UIRectFill(rect);
// clear the background in the given rectangles
for (NSValue *holeRectValue in rectsArray) {
CGRect holeRect = [holeRectValue CGRectValue];
CGRect holeRectIntersection = CGRectIntersection( holeRect, rect );
[[UIColor clearColor] setFill];
UIRectFill(holeRectIntersection);
}
}
@end
ここで、部分的に透明なビューを追加するには、PartialTransparentViewカスタムUIViewサブクラスをインポートし、次のように使用する必要があります。
NSArray *transparentRects = [[NSArray alloc] initWithObjects:[NSValue valueWithCGRect:CGRectMake(0, 50, 100, 20)],[NSValue valueWithCGRect:CGRectMake(0, 150, 10, 20)], nil];
PartialTransparentView *transparentView = [[PartialTransparentView alloc] initWithFrame:CGRectMake(0,0,200,400) backgroundColor:[UIColor colorWithWhite:1 alpha:0.75] andTransparentRects:rects];
[self.view addSubview:backgroundView];
これにより、2つの透明な四角形を持つビューが作成されます。もちろん、必要な数の四角形を追加することも、1つだけ使用することもできます。上記のコードは長方形のみを処理するため、円を使用する場合は修正する必要があります。
Lefteris Answerは絶対に正しいですが、透明なRectsを作成します。円形の透明レイヤーの場合、描画矩形を次のように変更します
- (void)drawRect:(CGRect)rect {
[backgroundColor setFill];
UIRectFill(rect);
for (NSValue *holeRectValue in rectsArray) {
CGRect holeRect = [holeRectValue CGRectValue];
CGRect holeRectIntersection = CGRectIntersection( holeRect, rect );
CGContextRef context = UIGraphicsGetCurrentContext();
if( CGRectIntersectsRect( holeRectIntersection, rect ) )
{
CGContextAddEllipseInRect(context, holeRectIntersection);
CGContextClip(context);
CGContextClearRect(context, holeRectIntersection);
CGContextSetFillColorWithColor( context, [UIColor clearColor].CGColor );
CGContextFillRect( context, holeRectIntersection);
}
}
}
UIBezierPath
を使用して、透明な穴の切り取りを処理しました。次のコードは、透明な穴を描画するUIView
のサブクラスに入ります。
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
// Clear any existing drawing on this view
// Remove this if the hole never changes on redraws of the UIView
CGContextClearRect(context, self.bounds);
// Create a path around the entire view
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:self.bounds];
// Your transparent window. This is for reference, but set this either as a property of the class or some other way
CGRect transparentFrame;
// Add the transparent window
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:transparentFrame cornerRadius:5.0f];
[clipPath appendPath:path];
// NOTE: If you want to add more holes, simply create another UIBezierPath and call [clipPath appendPath:anotherPath];
// This sets the algorithm used to determine what gets filled and what doesn't
clipPath.usesEvenOddFillRule = YES;
// Add the clipping to the graphics context
[clipPath addClip];
// set your color
UIColor *tintColor = [UIColor blackColor];
// (optional) set transparency alpha
CGContextSetAlpha(context, 0.7f);
// tell the color to be a fill color
[tintColor setFill];
// fill the path
[clipPath fill];
}
別の解決策:大きい四角形はすべてのビュー(黄色)で、小さい四角形は透明な四角形です。色の不透明度は設定可能です。
let pathBigRect = UIBezierPath(rect: bigRect)
let pathSmallRect = UIBezierPath(rect: smallRect)
pathBigRect.appendPath(pathSmallRect)
pathBigRect.usesEvenOddFillRule = true
let fillLayer = CAShapeLayer()
fillLayer.path = pathBigRect.CGPath
fillLayer.fillRule = kCAFillRuleEvenOdd
fillLayer.fillColor = UIColor.yellowColor().CGColor
//fillLayer.opacity = 0.4
view.layer.addSublayer(fillLayer)
@mosibの答えは、自分のビューに複数の円形の切り抜きを描きたいと思うまで、私にとって大きな助けになりました。少し苦労した後、私はdrawRectを次のように更新しました(Swiftのコード...申し訳ありませんが悪い編集):
override func drawRect(rect: CGRect)
{
backgroundColor.setFill()
UIRectFill(rect)
let layer = CAShapeLayer()
let path = CGPathCreateMutable()
for aRect in self.rects
{
let holeEnclosingRect = aRect
CGPathAddEllipseInRect(path, nil, holeEnclosingRect) // use CGPathAddRect() for rectangular hole
/*
// Draws only one circular hole
let holeRectIntersection = CGRectIntersection(holeRect, rect)
let context = UIGraphicsGetCurrentContext()
if( CGRectIntersectsRect(holeRectIntersection, rect))
{
CGContextBeginPath(context);
CGContextAddEllipseInRect(context, holeRectIntersection)
//CGContextDrawPath(context, kCGPathFillStroke)
CGContextClip(context)
//CGContextClearRect(context, holeRectIntersection)
CGContextSetFillColorWithColor(context, UIColor.clearColor().CGColor)
CGContextFillRect(context, holeRectIntersection)
CGContextClearRect(context, holeRectIntersection)
}*/
}
CGPathAddRect(path, nil, self.bounds)
layer.path = path
layer.fillRule = kCAFillRuleEvenOdd
self.layer.mask = layer
}
これはクリッピングを行います:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor( context, [UIColor blueColor].CGColor );
CGContextFillRect( context, rect );
CGRect holeRectIntersection = CGRectIntersection( CGRectMake(50, 50, 50, 50), rect );
if( CGRectIntersectsRect( holeRectIntersection, rect ) )
{
CGContextAddEllipseInRect(context, holeRectIntersection);
CGContextClip(context);
CGContextClearRect(context, holeRectIntersection);
CGContextSetFillColorWithColor( context, [UIColor clearColor].CGColor );
CGContextFillRect( context, holeRectIntersection);
}
この実装は、Swiftで記述された四角形と円をサポートしています。 PartialTransparentMaskView
class PartialTransparentMaskView: UIView{
var transparentRects: Array<CGRect>?
var transparentCircles: Array<CGRect>?
weak var targetView: UIView?
init(frame: CGRect, backgroundColor: UIColor?, transparentRects: Array<CGRect>?, transparentCircles: Array<CGRect>?, targetView: UIView?) {
super.init(frame: frame)
if((backgroundColor) != nil){
self.backgroundColor = backgroundColor
}
self.transparentRects = transparentRects
self.transparentCircles = transparentCircles
self.targetView = targetView
self.opaque = false
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(rect: CGRect) {
backgroundColor?.setFill()
UIRectFill(rect)
// clear the background in the given rectangles
if let rects = transparentRects {
for aRect in rects {
var holeRectIntersection = CGRectIntersection( aRect, rect )
UIColor.clearColor().setFill();
UIRectFill(holeRectIntersection);
}
}
if let circles = transparentCircles {
for aRect in circles {
var holeRectIntersection = aRect
let context = UIGraphicsGetCurrentContext();
if( CGRectIntersectsRect( holeRectIntersection, rect ) )
{
CGContextAddEllipseInRect(context, holeRectIntersection);
CGContextClip(context);
CGContextClearRect(context, holeRectIntersection);
CGContextSetFillColorWithColor( context, UIColor.clearColor().CGColor)
CGContextFillRect( context, holeRectIntersection);
}
}
}
}
}
迅速かつ効果的なものが必要な場合は、矩形(円形の穴)でオーバーレイを作成できるライブラリ( TAOverlayView )をCocoaPodsに追加し、ユーザーがオーバーレイの背後にあるビューと対話できるようにしました。私たちのアプリのいずれかでこのチュートリアルを作成するために使用しました:
オーバーレイのbackgroundColor
にUIColor(red: 0, green: 0, blue: 0, alpha: 0.85)
のようなものを設定することで、色と不透明度のニーズに応じて背景を変更できます。
こちらが私の一般的なSwiftの実装です。
{someViewArray.map{($0,false)}} // array of views, not round
他の貢献者のおかげで、それが誰かを助けることを願っています
public class HolyView : UIView {
public var holeViews = [(UIView,Bool)]()
public var holeViewsGenerator:(()->[(UIView,Bool)])?
internal var _backgroundColor : UIColor?
public override var backgroundColor : UIColor? {
get {return _backgroundColor}
set {_backgroundColor = newValue}
}
public override func drawRect(rect: CGRect) {
if (backgroundColor == nil) {return}
let ctxt = UIGraphicsGetCurrentContext()
backgroundColor?.setFill()
UIRectFill(rect)
UIColor.whiteColor().setFill()
UIRectClip(rect)
let views = (holeViewsGenerator == nil ? holeViews : holeViewsGenerator!())
for (view,isRound) in views {
let r = convertRect(view.bounds, fromView: view)
if (CGRectIntersectsRect(rect, r)) {
let radius = view.layer.cornerRadius
if (isRound || radius > 0) {
CGContextSetBlendMode(ctxt, kCGBlendModeDestinationOut);
UIBezierPath(roundedRect: r,
byRoundingCorners: .AllCorners,
cornerRadii: (isRound ? CGSizeMake(r.size.width/2, r.size.height/2) : CGSizeMake(radius,radius))
).fillWithBlendMode(kCGBlendModeDestinationOut, alpha: 1)
}
else {
UIRectFillUsingBlendMode(r, kCGBlendModeDestinationOut)
}
}
}
}
}
import UIKit
class PartialTransparentView: UIView {
var rectsArray: [CGRect]?
convenience init(rectsArray: [CGRect]) {
self.init()
self.rectsArray = rectsArray
backgroundColor = UIColor.black.withAlphaComponent(0.6)
isOpaque = false
}
override func draw(_ rect: CGRect) {
backgroundColor?.setFill()
UIRectFill(rect)
guard let rectsArray = rectsArray else {
return
}
for holeRect in rectsArray {
let holeRectIntersection = rect.intersection(holeRect)
UIColor.clear.setFill()
UIRectFill(holeRectIntersection)
}
}
}
私はBushra Shahidの answer を使用しましたが、うまく機能しましたが、円が互いに重なり合っている場合は問題があります。
このような場合にうまく機能するこの異なるアプローチを使用しました:
class HoleView: UIView {
var holes: [CGRect] = [] {
didSet {
lastProcessedSize = .zero
createMask()
}
}
private var lastProcessedSize = CGSize.zero
override func layoutSubviews() {
super.layoutSubviews()
createMask()
}
private func createMask() {
guard lastProcessedSize != frame.size,
holes.count > 0
else { return }
let size = frame.size
// create image
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
guard let context = UIGraphicsGetCurrentContext()
else { return }
UIColor.white.setFill()
context.fill(CGRect(Origin: .zero, size: size))
UIColor.black.setFill()
holes.forEach { context.fillEllipse(in: $0) }
// apply filter to convert black to transparent
guard let image = UIGraphicsGetImageFromCurrentImageContext(),
let cgImage = image.cgImage,
let filter = CIFilter(name: "CIMaskToAlpha")
else { return }
filter.setDefaults()
filter.setValue(CIImage(cgImage: cgImage), forKey: kCIInputImageKey)
guard let result = filter.outputImage,
let cgMaskImage = CIContext().createCGImage(result, from: result.extent)
else { return }
// Create mask
let mask = CALayer()
mask.frame = bounds
mask.contents = cgMaskImage
layer.mask = mask
}
}
要約すれば:
UIImage
マスクを作成します。CIMaskToAlpha
CIFilter
を使用して、透明/白マスクに変換します。CGImage
をCALayer
のコンテンツとして使用しますCALayer
を使用しています。C#を使用したXamarin Studio iOSの回答を含む。これは、60%のアルファを持つ単一の角丸長方形を描きます。主に@mikehoからの回答から取得
public override void Draw(CGRect rect)
{
base.Draw(rect);
//Allows us to draw a Nice clear rounded rect cutout
CGContext context = UIGraphics.GetCurrentContext();
// Create a path around the entire view
UIBezierPath clipPath = UIBezierPath.FromRect(rect);
// Add the transparent window to a sample rectangle
CGRect sampleRect = new CGRect(0f, 0f, rect.Width * 0.5f, rect.Height * 0.5f);
UIBezierPath path = UIBezierPath.FromRoundedRect(sampleRect, sampleRect.Height * 0.25f);
clipPath.AppendPath(path);
// This sets the algorithm used to determine what gets filled and what doesn't
clipPath.UsesEvenOddFillRule = true;
context.SetFillColor(UIColor.Black.CGColor);
context.SetAlpha(0.6f);
clipPath.Fill();
}
コメントを逃し、回答フォームに記入したので答えなければなりません:)私は、Carstenが彼が提案することをする最良の方法についてもっと情報を提供して欲しいです。
使用できます
+ (UIColor *)colorWithPatternImage:(UIImage *)image
複雑な背景の「カラー」画像を作成します。画像は、クラスの描画に精通している場合はプログラムで作成でき、Windowsフレームが事前定義されている場合は静的に作成できます。
このコードでは、円以上のものを作成します
- (void)drawRect:(CGRect)rect {
// Drawing code
UIColor *bgcolor=[UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0f];//Grey
[bgcolor setFill];
UIRectFill(rect);
if(!self.initialLoad){//If the view has been loaded from next time we will try to clear area where required..
// clear the background in the given rectangles
for (NSValue *holeRectValue in _rectArray) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect holeRect = [holeRectValue CGRectValue];
[[UIColor clearColor] setFill];
CGRect holeRectIntersection = CGRectIntersection( holeRect, rect );
CGContextSetFillColorWithColor( context, [UIColor clearColor].CGColor );
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextFillEllipseInRect( context, holeRectIntersection );
}
}
self.initialLoad=NO;
}
これを実現するには、ビューのレイヤーに境界線を付けます。
class HollowSquareView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor.clear
self.layer.masksToBounds = true
self.layer.borderColor = UIColor.black.cgColor
self.layer.borderWidth = 10.0
}
}
これにより、幅10の正方形のフレームと透明なコアが得られます。
レイヤーのcornerRadius
をビューの幅の半分に設定することもできます。これにより、中空の円が表示されます。
それを「偽造」してしまいました
windowFrameはプロパティです
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillRect(context, rect);
CGRect rootFrame = [[Navigation rootController] view].frame;
CGSize deviceSize = CGSizeMake(rootFrame.size.width, rootFrame.size.height);
CGRect topRect = CGRectMake(0, 0, deviceSize.width, windowFrame.Origin.y);
CGRect leftRect = CGRectMake(0, topRect.size.height, windowFrame.Origin.x, windowFrame.size.height);
CGRect rightRect = CGRectMake(windowFrame.size.width+windowFrame.Origin.x, topRect.size.height, deviceSize.width-windowFrame.size.width+windowFrame.Origin.x, windowFrame.size.height);
CGRect bottomRect = CGRectMake(0, windowFrame.Origin.y+windowFrame.size.height, deviceSize.width, deviceSize.height-windowFrame.Origin.y+windowFrame.size.height);
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextFillRect(context, topRect);
CGContextFillRect(context, leftRect);
CGContextFillRect(context, rightRect);
CGContextFillRect(context, bottomRect);