UIView 계층에 대한 내부 그림자 효과?
다음과 같은 CALayer가 있습니다.
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = CGRectMake(8, 57, 296, 30);
gradient.cornerRadius = 3.0f;
gradient.colors = [NSArray arrayWithObjects:(id)[RGB(130, 0, 140) CGColor], (id)[RGB(108, 0, 120) CGColor], nil];
[self.layer insertSublayer:gradient atIndex:0];
여기에 이너 섀도우 효과를 더하고 싶은데 어떻게 해야 할지 잘 모르겠습니다.제 생각에 저는 drawRect를 그려야 할 것 같습니다. 하지만 이것은 다른 UIView 객체 위에 레이어를 추가할 것입니다. 왜냐하면 이것은 일부 버튼 뒤에 막대가 있어야 하기 때문입니다. 그래서 저는 어떻게 해야 할지 모르겠습니다.
레이어를 하나 더 추가할 수 있지만 내부 그림자 효과를 얻는 방법을 잘 모르겠습니다(예:
도움 감사합니다...
Costique의 제안에 따라 Core Graphics를 사용하여 내부 그림자를 그리는 방법을 궁금해하는 다른 사람들을 위해, 다음과 같은 방법이 있습니다. (iOS에서 필요에 따라 조정)
도면에서 Rect: 메서드...
CGRect bounds = [self bounds];
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat radius = 0.5f * CGRectGetHeight(bounds);
// Create the "visible" path, which will be the shape that gets the inner shadow
// In this case it's just a rounded rect, but could be as complex as your want
CGMutablePathRef visiblePath = CGPathCreateMutable();
CGRect innerRect = CGRectInset(bounds, radius, radius);
CGPathMoveToPoint(visiblePath, NULL, innerRect.origin.x, bounds.origin.y);
CGPathAddLineToPoint(visiblePath, NULL, innerRect.origin.x + innerRect.size.width, bounds.origin.y);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, bounds.origin.y, bounds.origin.x + bounds.size.width, innerRect.origin.y, radius);
CGPathAddLineToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, innerRect.origin.y + innerRect.size.height);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height, innerRect.origin.x + innerRect.size.width, bounds.origin.y + bounds.size.height, radius);
CGPathAddLineToPoint(visiblePath, NULL, innerRect.origin.x, bounds.origin.y + bounds.size.height);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x, bounds.origin.y + bounds.size.height, bounds.origin.x, innerRect.origin.y + innerRect.size.height, radius);
CGPathAddLineToPoint(visiblePath, NULL, bounds.origin.x, innerRect.origin.y);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x, bounds.origin.y, innerRect.origin.x, bounds.origin.y, radius);
CGPathCloseSubpath(visiblePath);
// Fill this path
UIColor *aColor = [UIColor redColor];
[aColor setFill];
CGContextAddPath(context, visiblePath);
CGContextFillPath(context);
// Now create a larger rectangle, which we're going to subtract the visible path from
// and apply a shadow
CGMutablePathRef path = CGPathCreateMutable();
//(when drawing the shadow for a path whichs bounding box is not known pass "CGPathGetPathBoundingBox(visiblePath)" instead of "bounds" in the following line:)
//-42 cuould just be any offset > 0
CGPathAddRect(path, NULL, CGRectInset(bounds, -42, -42));
// Add the visible path (so that it gets subtracted for the shadow)
CGPathAddPath(path, NULL, visiblePath);
CGPathCloseSubpath(path);
// Add the visible paths as the clipping path to the context
CGContextAddPath(context, visiblePath);
CGContextClip(context);
// Now setup the shadow properties on the context
aColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 3.0f, [aColor CGColor]);
// Now fill the rectangle, so the shadow gets drawn
[aColor setFill];
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextEOFillPath(context);
// Release the paths
CGPathRelease(path);
CGPathRelease(visiblePath);
따라서 기본적으로 다음 단계가 있습니다.
- 경로 만들기
- 원하는 채우기 색을 설정하고 이 경로를 컨텍스트에 추가한 후 컨텍스트 채우기
- 이제 보이는 경로를 바인딩할 수 있는 더 큰 직사각형을 만듭니다.이 경로를 닫기 전에 표시된 경로를 추가합니다.그런 다음 경로를 닫아 가시적인 경로를 뺀 도형을 만듭니다.이러한 경로를 생성한 방법에 따라 채우기 방법(짝수/홀수의 0이 아닌 권선)을 조사할 수 있습니다.기본적으로 서브패스를 함께 추가할 때 서브패스를 "감산"하려면 서브패스를 시계 반대 방향으로 그려야 합니다(또는 생성해야 합니다).
- 그런 다음 화면에 표시되는 경로를 컨텍스트의 클리핑 경로로 설정하여 외부의 아무것도 그려내지 않도록 해야 합니다.
- 그런 다음 오프셋, 흐림 및 색상을 포함하는 컨텍스트에 그림자를 설정합니다.
- 그리고 큰 모양에 구멍을 메웁니다.색깔은 중요하지 않습니다. 왜냐하면 여러분이 모든 것을 제대로 했다면, 여러분은 이 색깔을 볼 수 없을 것이고, 그림자만 볼 수 있기 때문입니다.
파티에 늦었다는 건 알지만 여행 초기에 발견할 수 있었던...
신용이 있어야 할 곳에 신용을 부여하기 위해, 이것은 본질적으로 더 큰 지역에서 더 작은 지역을 빼는 코스티크의 솔루션에 대한 다니엘 소프의 정교함의 수정입니다.이 버전은 재정의하는 대신 도면층 구성을 사용하는 사용자를 위한 것입니다.-drawRect:
그CAShapeLayer
클래스를 사용하여 동일한 효과를 얻을 수 있습니다.
CAShapeLayer *shadowLayer = [CAShapeLayer layer];
[shadowLayer setFrame:[self bounds]];
// Standard shadow stuff
[shadowLayer setShadowColor:[[UIColor colorWithWhite:0 alpha:1] CGColor]];
[shadowLayer setShadowOffset:CGSizeMake(0.0f, 0.0f)];
[shadowLayer setShadowOpacity:1.0f];
[shadowLayer setShadowRadius:5];
// Causes the inner region in this example to NOT be filled.
[shadowLayer setFillRule:kCAFillRuleEvenOdd];
// Create the larger rectangle path.
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectInset(bounds, -42, -42));
// Add the inner path so it's subtracted from the outer path.
// someInnerPath could be a simple bounds rect, or maybe
// a rounded one for some extra fanciness.
CGPathAddPath(path, NULL, someInnerPath);
CGPathCloseSubpath(path);
[shadowLayer setPath:path];
CGPathRelease(path);
[[self layer] addSublayer:shadowLayer];
이때 상위 도면층이 경계까지 마스킹되지 않으면 도면층 가장자리 주변에 마스크 도면층의 추가 면적이 표시됩니다.예제를 직접 복사하면 42픽셀의 검은색이 됩니다.그것을 제거하기 위해, 당신은 단지 다른 것을 사용할 수 있습니다.CAShapeLayer
동일한 경로를 사용하여 섀도 계층의 마스크로 설정합니다.
CAShapeLayer *maskLayer = [CAShapeLayer layer];
[maskLayer setPath:someInnerPath];
[shadowLayer setMask:maskLayer];
벤치마킹하지는, 이이 벤하지는않만킹았지제가, 래스화사방는것용을하이우생다, 니합각뛰순정성더선고다나어것이를위능하는다보께식함보다 더 이 좋다고 생각합니다.-drawRect:
.
경계 밖에 큰 직사각형 경로를 만들고 경계 크기의 직사각형 경로를 뺀 다음 결과 경로를 "일반" 그림자로 채우면 코어 그래픽으로 내부 그림자를 그릴 수 있습니다.
하지만 그라데이션 레이어와 결합해야 하기 때문에 내부 그림자의 9분할 투명 PNG 이미지를 생성하여 적절한 크기로 확장하는 것이 더 쉬운 해결책이라고 생각합니다.9개 부분으로 구성된 그림자 이미지는 다음과 같습니다(크기는 21x21픽셀).
CALayer *innerShadowLayer = [CALayer layer];
innerShadowLayer.contents = (id)[UIImage imageNamed: @"innershadow.png"].CGImage;
innerShadowLayer.contentsCenter = CGRectMake(10.0f/21.0f, 10.0f/21.0f, 1.0f/21.0f, 1.0f/21.0f);
그런 다음 내부 섀도 레이어의 프레임을 설정하면 섀도가 제대로 늘어나야 합니다.
Swift에서 CALayer만 사용하는 단순화된 버전:
import UIKit
final class FrameView : UIView {
init() {
super.init(frame: CGRect.zero)
backgroundColor = UIColor.white
}
@available(*, unavailable)
required init?(coder decoder: NSCoder) { fatalError("unavailable") }
override func layoutSubviews() {
super.layoutSubviews()
addInnerShadow()
}
private func addInnerShadow() {
let innerShadow = CALayer()
innerShadow.frame = bounds
// Shadow path (1pt ring around bounds)
let path = UIBezierPath(rect: innerShadow.bounds.insetBy(dx: -1, dy: -1))
let cutout = UIBezierPath(rect: innerShadow.bounds).reversing()
path.append(cutout)
innerShadow.shadowPath = path.cgPath
innerShadow.masksToBounds = true
// Shadow properties
innerShadow.shadowColor = UIColor(white: 0, alpha: 1).cgColor // UIColor(red: 0.71, green: 0.77, blue: 0.81, alpha: 1.0).cgColor
innerShadow.shadowOffset = CGSize.zero
innerShadow.shadowOpacity = 1
innerShadow.shadowRadius = 3
// Add
layer.addSublayer(innerShadow)
}
}
내부 그림자 레이어는 그림자 앞에 렌더링되므로 배경색이 불투명하지 않아야 합니다.
약간 우회적이지만 이미지(읽기: 색상 변경이 용이함, 그림자 반경 등)를 사용할 필요가 없으며 코드 몇 줄에 불과합니다.
UIImageView를 드롭섀도에 표시할 UIIview의 첫 번째 하위 뷰로 추가합니다.저는 IB를 사용하지만 프로그래밍 방식으로 동일하게 할 수 있습니다.
UIImageView에 대한 참조가 'InnerShadow'라고 가정합니다.
`
[[innerShadow layer] setMasksToBounds:YES];
[[innerShadow layer] setCornerRadius:12.0f];
[[innerShadow layer] setBorderColor:[UIColorFromRGB(180, 180, 180) CGColor]];
[[innerShadow layer] setBorderWidth:1.0f];
[[innerShadow layer] setShadowColor:[UIColorFromRGB(0, 0, 0) CGColor]];
[[innerShadow layer] setShadowOffset:CGSizeMake(0, 0)];
[[innerShadow layer] setShadowOpacity:1];
[[innerShadow layer] setShadowRadius:2.0];
주의: 경계가 있어야 합니다. 그렇지 않으면 그림자가 나타나지 않습니다.[UIColor clearColor]가 작동하지 않습니다.예제에서는 다른 색을 사용하지만 그림자 시작 부분과 같은 색을 사용하도록 지정할 수 있습니다.:)
아래에 있는 bbrame의 코멘트를 참조하십시오.UIColorFromRGB
거시적인
늦더라도 안하는 것보다는...
여기 또 다른 접근법이 있습니다, 아마도 이미 게시된 것들보다 더 나은 것은 아닐 것입니다, 하지만 그것은 좋고 단순합니다.
-(void)drawInnerShadowOnView:(UIView *)view
{
UIImageView *innerShadowView = [[UIImageView alloc] initWithFrame:view.bounds];
innerShadowView.contentMode = UIViewContentModeScaleToFill;
innerShadowView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[view addSubview:innerShadowView];
[innerShadowView.layer setMasksToBounds:YES];
[innerShadowView.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[innerShadowView.layer setShadowColor:[UIColor blackColor].CGColor];
[innerShadowView.layer setBorderWidth:1.0f];
[innerShadowView.layer setShadowOffset:CGSizeMake(0, 0)];
[innerShadowView.layer setShadowOpacity:1.0];
// this is the inner shadow thickness
[innerShadowView.layer setShadowRadius:1.5];
}
내부 그림자를 그려서 그리는 대신 Rect 또는 UIView를 뷰에 추가합니다.예를 들어 UIViewV 하단에 내부 그림자 효과를 원하는 경우 테두리에 직접 CALayer를 추가할 수 있습니다.
innerShadowOwnerLayer = [[CALayer alloc]init];
innerShadowOwnerLayer.frame = CGRectMake(0, V.frame.size.height+2, V.frame.size.width, 2);
innerShadowOwnerLayer.backgroundColor = [UIColor whiteColor].CGColor;
innerShadowOwnerLayer.shadowColor = [UIColor blackColor].CGColor;
innerShadowOwnerLayer.shadowOffset = CGSizeMake(0, 0);
innerShadowOwnerLayer.shadowRadius = 10.0;
innerShadowOwnerLayer.shadowOpacity = 0.7;
[V.layer addSubLayer:innerShadowOwnerLayer];
대상 UIView에 대한 아래쪽 내부 그림자를 추가합니다.
여기 swift, change 버전이 있습니다.startPoint
그리고.endPoint
양쪽에서 만들어 내는 것.
let layer = CAGradientLayer()
layer.startPoint = CGPointMake(0.5, 0.0);
layer.endPoint = CGPointMake(0.5, 1.0);
layer.colors = [UIColor(white: 0.1, alpha: 1.0).CGColor, UIColor(white: 0.1, alpha: 0.5).CGColor, UIColor.clearColor().CGColor]
layer.locations = [0.05, 0.2, 1.0 ]
layer.frame = CGRectMake(0, 0, self.view.frame.width, 60)
self.view.layer.insertSublayer(layer, atIndex: 0)
이 솔루션은 PaintCode에서 내보낸 솔루션입니다.
-(void) drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
//// Shadow Declarations
UIColor* shadow = UIColor.whiteColor;
CGSize shadowOffset = CGSizeMake(0, 0);
CGFloat shadowBlurRadius = 10;
//// Rectangle Drawing
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: self.bounds];
[[UIColor blackColor] setFill];
[rectanglePath fill];
////// Rectangle Inner Shadow
CGContextSaveGState(context);
UIRectClip(rectanglePath.bounds);
CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);
CGContextSetAlpha(context, CGColorGetAlpha([shadow CGColor]));
CGContextBeginTransparencyLayer(context, NULL);
{
UIColor* opaqueShadow = [shadow colorWithAlphaComponent: 1];
CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, [opaqueShadow CGColor]);
CGContextSetBlendMode(context, kCGBlendModeSourceOut);
CGContextBeginTransparencyLayer(context, NULL);
[opaqueShadow setFill];
[rectanglePath fill];
CGContextEndTransparencyLayer(context);
}
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
}
Swift 4.2의 솔루션은 다음과 같습니다.해보시겠어요?
final class ACInnerShadowLayer : CAShapeLayer {
var innerShadowColor: CGColor? = UIColor.black.cgColor {
didSet { setNeedsDisplay() }
}
var innerShadowOffset: CGSize = .zero {
didSet { setNeedsDisplay() }
}
var innerShadowRadius: CGFloat = 8 {
didSet { setNeedsDisplay() }
}
var innerShadowOpacity: Float = 1 {
didSet { setNeedsDisplay() }
}
override init() {
super.init()
masksToBounds = true
contentsScale = UIScreen.main.scale
setNeedsDisplay()
}
override init(layer: Any) {
if let layer = layer as? InnerShadowLayer {
innerShadowColor = layer.innerShadowColor
innerShadowOffset = layer.innerShadowOffset
innerShadowRadius = layer.innerShadowRadius
innerShadowOpacity = layer.innerShadowOpacity
}
super.init(layer: layer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(in ctx: CGContext) {
ctx.setAllowsAntialiasing(true)
ctx.setShouldAntialias(true)
ctx.interpolationQuality = .high
let colorspace = CGColorSpaceCreateDeviceRGB()
var rect = bounds
var radius = cornerRadius
if borderWidth != 0 {
rect = rect.insetBy(dx: borderWidth, dy: borderWidth)
radius -= borderWidth
radius = max(radius, 0)
}
let innerShadowPath = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath
ctx.addPath(innerShadowPath)
ctx.clip()
let shadowPath = CGMutablePath()
let shadowRect = rect.insetBy(dx: -rect.size.width, dy: -rect.size.width)
shadowPath.addRect(shadowRect)
shadowPath.addPath(innerShadowPath)
shadowPath.closeSubpath()
if let innerShadowColor = innerShadowColor, let oldComponents = innerShadowColor.components {
var newComponets = Array<CGFloat>(repeating: 0, count: 4) // [0, 0, 0, 0] as [CGFloat]
let numberOfComponents = innerShadowColor.numberOfComponents
switch numberOfComponents {
case 2:
newComponets[0] = oldComponents[0]
newComponets[1] = oldComponents[0]
newComponets[2] = oldComponents[0]
newComponets[3] = oldComponents[1] * CGFloat(innerShadowOpacity)
case 4:
newComponets[0] = oldComponents[0]
newComponets[1] = oldComponents[1]
newComponets[2] = oldComponents[2]
newComponets[3] = oldComponents[3] * CGFloat(innerShadowOpacity)
default:
break
}
if let innerShadowColorWithMultipliedAlpha = CGColor(colorSpace: colorspace, components: newComponets) {
ctx.setFillColor(innerShadowColorWithMultipliedAlpha)
ctx.setShadow(offset: innerShadowOffset, blur: innerShadowRadius, color: innerShadowColorWithMultipliedAlpha)
ctx.addPath(shadowPath)
ctx.fillPath(using: .evenOdd)
}
}
}
}
저는 파티에 매우 늦었지만 지역 사회에 환원하고 싶습니다.정적 라이브러리를 제공하고 리소스가 없는 상태에서 UITextField 배경 이미지를 제거하기 위해 작성한 방법입니다.ViewController에서 한 문자 원시 또는 (BOOL)[self is UsingBullets] 또는 (BOOL)[self usingAsterisks]를 표시할 수 있는 4개의 UITextField 인스턴스의 PIN Entry 화면에 사용했습니다.iPhone/iPhone retina/iPad/iPad retina용 앱이므로 4개의 이미지를 제공할 필요가 없습니다...
#import <QuartzCore/QuartzCore.h>
- (void)setTextFieldInnerGradient:(UITextField *)textField
{
[textField setSecureTextEntry:self.isUsingBullets];
[textField setBackgroundColor:[UIColor blackColor]];
[textField setTextColor:[UIColor blackColor]];
[textField setBorderStyle:UITextBorderStyleNone];
[textField setClipsToBounds:YES];
[textField.layer setBorderColor:[[UIColor blackColor] CGColor]];
[textField.layer setBorderWidth:1.0f];
// make a gradient off-white background
CAGradientLayer *gradient = [CAGradientLayer layer];
CGRect gradRect = CGRectInset([textField bounds], 3, 3); // Reduce Width and Height and center layer
gradRect.size.height += 2; // minimise Bottom shadow, rely on clipping to remove these 2 pts.
gradient.frame = gradRect;
struct CGColor *topColor = [UIColor colorWithWhite:0.6f alpha:1.0f].CGColor;
struct CGColor *bottomColor = [UIColor colorWithWhite:0.9f alpha:1.0f].CGColor;
// We need to use this fancy __bridge object in order to get the array we want.
gradient.colors = [NSArray arrayWithObjects:(__bridge id)topColor, (__bridge id)bottomColor, nil];
[gradient setCornerRadius:4.0f];
[gradient setShadowOffset:CGSizeMake(0, 0)];
[gradient setShadowColor:[[UIColor whiteColor] CGColor]];
[gradient setShadowOpacity:1.0f];
[gradient setShadowRadius:3.0f];
// Now we need to Blur the edges of this layer "so it blends"
// This rasterizes the view down to 4x4 pixel chunks then scales it back up using bilinear filtering...
// it's EXTREMELY fast and looks ok if you are just wanting to blur a background view under a modal view.
// To undo it, just set the rasterization scale back to 1.0 or turn off rasterization.
[gradient setRasterizationScale:0.25];
[gradient setShouldRasterize:YES];
[textField.layer insertSublayer:gradient atIndex:0];
if (self.usingAsterisks) {
[textField setFont:[UIFont systemFontOfSize:80.0]];
} else {
[textField setFont:[UIFont systemFontOfSize:40.0]];
}
[textField setTextAlignment:UITextAlignmentCenter];
[textField setEnabled:NO];
}
이 포럼이 저에게 도움이 되었으니 누군가에게 도움이 되었으면 좋겠습니다.
내부 그림자가 페인트 코드에 의해 어떻게 그려지는지 설명하고 깨끗하고 깔끔한 코드 스니펫을 제공하는 Chris Emery의 Quartz의 Inner Shadows의 위대한 기사를 확인하십시오.
- (void)drawInnerShadowInContext:(CGContextRef)context
withPath:(CGPathRef)path
shadowColor:(CGColorRef)shadowColor
offset:(CGSize)offset
blurRadius:(CGFloat)blurRadius
{
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextClip(context);
CGColorRef opaqueShadowColor = CGColorCreateCopyWithAlpha(shadowColor, 1.0);
CGContextSetAlpha(context, CGColorGetAlpha(shadowColor));
CGContextBeginTransparencyLayer(context, NULL);
CGContextSetShadowWithColor(context, offset, blurRadius, opaqueShadowColor);
CGContextSetBlendMode(context, kCGBlendModeSourceOut);
CGContextSetFillColorWithColor(context, opaqueShadowColor);
CGContextAddPath(context, path);
CGContextFillPath(context);
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
CGColorRelease(opaqueShadowColor);
}
Swift의 CALayer를 사용하여 확장 가능한 솔루션
설명된 내용과 함께InnerShadowLayer
또한 다른 에지를 제외한 특정 에지에 대해서만 내부 섀도를 활성화할 수 있습니다(예: 뷰의 왼쪽 및 위쪽 에지에서만 내부 섀도를 활성화할 수 있습니다).
그러면 다음을 추가할 수 있습니다.InnerShadowLayer
다음을 사용하여 보기:
init(...) {
// ... your initialization code ...
super.init(frame: .zero)
layer.addSublayer(shadowLayer)
}
public override func layoutSubviews() {
super.layoutSubviews()
shadowLayer.frame = bounds
}
InnerShadowLayer
실행
/// Shadow is a struct defining the different kinds of shadows
public struct Shadow {
let x: CGFloat
let y: CGFloat
let blur: CGFloat
let opacity: CGFloat
let color: UIColor
}
/// A layer that applies an inner shadow to the specified edges of either its path or its bounds
public class InnerShadowLayer: CALayer {
private let shadow: Shadow
private let edge: UIRectEdge
public init(shadow: Shadow, edge: UIRectEdge) {
self.shadow = shadow
self.edge = edge
super.init()
setupShadow()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func layoutSublayers() {
updateShadow()
}
private func setupShadow() {
shadowColor = shadow.color.cgColor
shadowOpacity = Float(shadow.opacity)
shadowRadius = shadow.blur / 2.0
masksToBounds = true
}
private func updateShadow() {
shadowOffset = {
let topWidth: CGFloat = 0
let leftWidth = edge.contains(.left) ? shadow.y / 2 : 0
let bottomWidth: CGFloat = 0
let rightWidth = edge.contains(.right) ? -shadow.y / 2 : 0
let topHeight = edge.contains(.top) ? shadow.y / 2 : 0
let leftHeight: CGFloat = 0
let bottomHeight = edge.contains(.bottom) ? -shadow.y / 2 : 0
let rightHeight: CGFloat = 0
return CGSize(width: [topWidth, leftWidth, bottomWidth, rightWidth].reduce(0, +),
height: [topHeight, leftHeight, bottomHeight, rightHeight].reduce(0, +))
}()
let insets = UIEdgeInsets(top: edge.contains(.top) ? -bounds.height : 0,
left: edge.contains(.left) ? -bounds.width : 0,
bottom: edge.contains(.bottom) ? -bounds.height : 0,
right: edge.contains(.right) ? -bounds.width : 0)
let path = UIBezierPath(rect: bounds.inset(by: insets))
let cutout = UIBezierPath(rect: bounds).reversing()
path.append(cutout)
shadowPath = path.cgPath
}
}
이 코드는 나에게 효과가 있었습니다.
class InnerDropShadowView: UIView {
override func draw(_ rect: CGRect) {
//Drawing code
let context = UIGraphicsGetCurrentContext()
//// Shadow Declarations
let shadow: UIColor? = UIColor.init(hexString: "a3a3a3", alpha: 1.0) //UIColor.black.withAlphaComponent(0.6) //UIColor.init(hexString: "d7d7da", alpha: 1.0)
let shadowOffset = CGSize(width: 0, height: 0)
let shadowBlurRadius: CGFloat = 7.5
//// Rectangle Drawing
let rectanglePath = UIBezierPath(rect: bounds)
UIColor.groupTableViewBackground.setFill()
rectanglePath.fill()
////// Rectangle Inner Shadow
context?.saveGState()
UIRectClip(rectanglePath.bounds)
context?.setShadow(offset: CGSize.zero, blur: 0, color: nil)
context?.setAlpha((shadow?.cgColor.alpha)!)
context?.beginTransparencyLayer(auxiliaryInfo: nil)
do {
let opaqueShadow: UIColor? = shadow?.withAlphaComponent(1)
context?.setShadow(offset: shadowOffset, blur: shadowBlurRadius, color: opaqueShadow?.cgColor)
context!.setBlendMode(.sourceOut)
context?.beginTransparencyLayer(auxiliaryInfo: nil)
opaqueShadow?.setFill()
rectanglePath.fill()
context!.endTransparencyLayer()
}
context!.endTransparencyLayer()
context?.restoreGState()
}
}
이를 위해 사용할 수 있는 코드가 있습니다.재지정을 통해 뷰에서 도면층을 변경하는 경우+ (Class)layerClass
)에서 JTANnerShadowLayer로 이동하면 init 메서드에서 들여쓰기 레이어의 내부 그림자를 설정할 수 있습니다.원본 내용도 그리려면 전화하십시오.setDrawOriginalImage:yes
들여쓰기 레이어에 있습니다.여기에 이것이 어떻게 작동하는지에 대한 블로그 게시물이 있습니다.
그라데이션 도면층 사용:
UIView * mapCover = [UIView new];
mapCover.frame = map.frame;
[view addSubview:mapCover];
CAGradientLayer * vertical = [CAGradientLayer layer];
vertical.frame = mapCover.bounds;
vertical.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor,
(id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor,
(id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor,
(id)[UIColor whiteColor].CGColor, nil];
vertical.locations = @[@0.01,@0.1,@0.9,@0.99];
[mapCover.layer insertSublayer:vertical atIndex:0];
CAGradientLayer * horizontal = [CAGradientLayer layer];
horizontal.frame = mapCover.bounds;
horizontal.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor,
(id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor,
(id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor,
(id)[UIColor whiteColor].CGColor, nil];
horizontal.locations = @[@0.01,@0.1,@0.9,@0.99];
horizontal.startPoint = CGPointMake(0.0, 0.5);
horizontal.endPoint = CGPointMake(1.0, 0.5);
[mapCover.layer insertSublayer:horizontal atIndex:0];
간단한 해결책이 있습니다. 그냥 일반 그림자를 그리고 이렇게 회전하면 됩니다.
@objc func shadowView() -> UIView {
let shadowView = UIView(frame: .zero)
shadowView.backgroundColor = .white
shadowView.layer.shadowColor = UIColor.grey.cgColor
shadowView.layer.shadowOffset = CGSize(width: 0, height: 2)
shadowView.layer.shadowOpacity = 1.0
shadowView.layer.shadowRadius = 4
shadowView.layer.compositingFilter = "multiplyBlendMode"
return shadowView
}
func idtm_addBottomShadow() {
let shadow = shadowView()
shadow.transform = transform.rotated(by: 180 * CGFloat(Double.pi))
shadow.transform = transform.rotated(by: -1 * CGFloat(Double.pi))
shadow.translatesAutoresizingMaskIntoConstraints = false
addSubview(shadow)
NSLayoutConstraint.activate([
shadow.leadingAnchor.constraint(equalTo: leadingAnchor),
shadow.trailingAnchor.constraint(equalTo: trailingAnchor),
shadow.bottomAnchor.constraint(equalTo: bottomAnchor),
shadow.heightAnchor.constraint(equalToConstant: 1),
])
}
언급URL : https://stackoverflow.com/questions/4431292/inner-shadow-effect-on-uiview-layer
'programing' 카테고리의 다른 글
mysql_install_db 잘못된 문자 집합 및 정렬 (0) | 2023.08.11 |
---|---|
MySQL Server 버전 10.3.9-MariaDB에서 텍스트에 따옴표가 하나 있는 경우 쿼리할 수 없음 (0) | 2023.08.11 |
CSS에서 "워드-브레이크:브레이크-올"과 "워드-랩:브레이크-워드"의 차이점은 무엇입니까? (0) | 2023.08.11 |
Android 4.0용 AVD를 만드는 방법 (0) | 2023.08.11 |
PowerShell:Out-File은 왜 긴 줄을 더 작은 줄로 나누나요? (0) | 2023.08.11 |