我在一个应用程序上工作了几年,收到了一个简单的设计请求:在UIView上圆角并添加投影。做以下所给的事
我想要一个自定义的UIView…:我只是想要一个空白的白色视图与圆角和光滴阴影(没有照明效果)。我可以逐个执行这些操作,但通常会发生clipToBounds/maskToBounds冲突。
我在一个应用程序上工作了几年,收到了一个简单的设计请求:在UIView上圆角并添加投影。做以下所给的事
我想要一个自定义的UIView…:我只是想要一个空白的白色视图与圆角和光滴阴影(没有照明效果)。我可以逐个执行这些操作,但通常会发生clipToBounds/maskToBounds冲突。
当前回答
如果你不想像David c建议的那样改变你的nibs和视图层次结构,这个方法可以帮你。为你的UIImageView添加圆角和阴影只需使用这个方法,例如:
[Utils roundCornersForImageView:myImageView withCornerRadius:6.0
andShadowOffset:2.0];
(!)出于性能原因,我不认为在像UITableView这样的东西中使用这段代码是个好主意,因为这段代码改变了视图层次结构。所以我会建议改变你的nib,并添加一个容器视图的阴影效果和使用戴维C.代码。
+ (void)roundCornersForImageView:(UIImageView *)imageView
withCornerRadius:(float)cornerRadius andShadowOffset:(float)shadowOffset
{
const float CORNER_RADIUS = cornerRadius;
const float BORDER_WIDTH = 1.0;
const float SHADOW_OFFSET = shadowOffset;
const float SHADOW_OPACITY = 0.8;
const float SHADOW_RADIUS = 3.0;
//Our old image now is just background image view with shadow
UIImageView *backgroundImageView = imageView;
UIView *superView = backgroundImageView.superview;
//Make wider actual visible rect taking into account shadow
//offset
CGRect oldBackgroundFrame = backgroundImageView.frame;
CGRect newBackgroundFrame = CGRectMake(oldBackgroundFrame.origin.x, oldBackgroundFrame.origin.y, oldBackgroundFrame.size.width + SHADOW_OFFSET, oldBackgroundFrame.size.height + SHADOW_OFFSET);
[backgroundImageView removeFromSuperview];
backgroundImageView.frame = newBackgroundFrame;
//Make new UIImageView with rounded corners and put our old image
CGRect frameForRoundedImageView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
UIImageView *roundedImageView = [[UIImageView alloc]initWithFrame:frameForRoundedImageView];
roundedImageView.image = imageView.image;
[roundedImageView.layer setCornerRadius:CORNER_RADIUS];
[roundedImageView.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[roundedImageView.layer setBorderWidth:BORDER_WIDTH];
[roundedImageView.layer setMasksToBounds:YES];
//Set shadow preferences
[backgroundImageView setImage:nil];
[backgroundImageView.layer setShadowColor:[UIColor blackColor].CGColor];
[backgroundImageView.layer setShadowOpacity:SHADOW_OPACITY];
[backgroundImageView.layer setShadowRadius:SHADOW_RADIUS];
[backgroundImageView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];
//Add out two image views back to the view hierarchy.
[backgroundImageView addSubview:roundedImageView];
[superView addSubview:backgroundImageView];
}
其他回答
extension UIView {
func dropRoundedShadowForAllSides() {
let backgroundView = UIView(frame:self.frame)
let radius = frame.height/2
backgroundView.layer.masksToBounds = false
self.layer.masksToBounds = true
backgroundView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
backgroundView.layer.shadowRadius = 4
backgroundView.layer.shadowOpacity = 0.4
let path = UIBezierPath()
// Start at the Top Left Corner + radius distance
path.move(to: CGPoint(x: 2*radius, y: 0.0))
// Move to the Top Right Corner - radius distance
path.addLine(to: CGPoint(x: backgroundView.frame.size.width - radius, y: 0.0))
// Move to top right corner + radius down as curve
let centerPoint1 = CGPoint(x:backgroundView.frame.size.width - radius,y:radius)
path.addArc(withCenter: centerPoint1, radius: radius, startAngle: 3*(.pi/2), endAngle: 0, clockwise: true)
// Move to the Bottom Right Corner - radius
path.addLine(to: CGPoint(x: backgroundView.frame.size.width, y: backgroundView.frame.size.height - radius))
// Move to top right corner + radius left as curve
let centerPoint2 = CGPoint(x:backgroundView.frame.size.width - radius,y:backgroundView.frame.size.height - radius)
path.addArc(withCenter: centerPoint2, radius: radius, startAngle: 0, endAngle: .pi/2, clockwise: true)
// Move to the Bottom Left Corner - radius
path.addLine(to: CGPoint(x: radius, y: backgroundView.frame.size.height))
// Move to left right corner - radius up as curve
let centerPoint3 = CGPoint(x:radius,y:backgroundView.frame.size.height - radius)
path.addArc(withCenter: centerPoint3, radius: radius, startAngle: .pi/2, endAngle: .pi, clockwise: true)
// Move to the top Left Corner - radius
path.addLine(to: CGPoint(x: 0, y: radius))
// Move to top right corner + radius down as curve
let centerPoint4 = CGPoint(x:radius,y:radius)
path.addArc(withCenter: centerPoint4, radius: radius, startAngle: .pi, endAngle: 3 * (.pi/2), clockwise: true)
path.close()
backgroundView.layer.shadowPath = path.cgPath
if let superView = self.superview {
superView.addSubview(backgroundView)
superView.sendSubview(toBack: backgroundView)
superView.bringSubview(toFront: self)
}
}
}
在研究了一整天的圆角视图与阴影之后,我很高兴在这里发布我的自定义uiview类,希望结束这个问题:
RoundCornerShadowView.h
#import <UIKit/UIKit.h>
@interface RoundCornerShadowView : UIView
@end
RoundCornerShadowView.m
#import "RoundCornerShadowView.h"
@implementation RoundCornerShadowView
// *** must override this method, not the other method ***
// otherwise, the background corner doesn't disappear....
// @2015/05/29
-(void) layoutSubviews {
[super layoutSubviews];//is must to ensure rightly layout children view
//1. first, create Inner layer with content
CALayer *innerView = [CALayer layer];
innerView.frame = CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height);
//instead of: innerView.frame = self.frame;
innerView.borderWidth = 1.0f;
innerView.cornerRadius = 6.0f;
innerView.masksToBounds = YES;
innerView.borderColor = [[UIColor lightGrayColor] CGColor];
innerView.backgroundColor = [[UIColor whiteColor] CGColor];
//put the layer to the BOTTOM of layers is also a MUST step...
//otherwise this layer will overlay the sub uiviews in current uiview...
[self.layer insertSublayer:innerView atIndex:0];
//2. then, create shadow with self layer
self.layer.masksToBounds = NO;
self.layer.shadowColor = [[UIColor darkGrayColor] CGColor];
self.layer.shadowOpacity = 0.4f;
//shadow length
self.layer.shadowRadius = 2.0f;
//no offset
self.layer.shadowOffset = CGSizeMake(0, 0);
//right down shadow
//[self.layer setShadowOffset: CGSizeMake(1.0f, 1.0f)];
//3. last but important, MUST clear current view background color, or the color will show in the corner!
self.backgroundColor = [UIColor clearColor];
}
@end
所以,不需要在视图中添加子视图或在目标视图中添加子视图,只需在当前视图中添加一层,并执行3步即可完成!
仔细查看代码中的注释,这有助于理解组件!
一种方法是将带有圆角的视图放到带有投影的视图中。
UIView* roundedView = [[UIView alloc] initWithFrame: frame];
roundedView.layer.cornerRadius = 5.0;
roundedView.layer.masksToBounds = YES;
UIView* shadowView = [[UIView alloc] initWithFrame: frame];
shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
shadowView.layer.shadowRadius = 5.0;
shadowView.layer.shadowOffset = CGSizeMake(3.0, 3.0);
shadowView.layer.shadowOpacity = 1.0;
[shadowView addSubview: roundedView];
然后你可以在任何你想要的地方添加shadowView。
import UIKit
extension UIView {
func addShadow(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
let shadowLayer = CAShapeLayer()
let size = CGSize(width: cornerRadius, height: cornerRadius)
let cgPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
shadowLayer.path = cgPath //2
shadowLayer.fillColor = fillColor.cgColor //3
shadowLayer.shadowColor = shadowColor.cgColor //4
shadowLayer.shadowPath = cgPath
shadowLayer.shadowOffset = offSet //5
shadowLayer.shadowOpacity = opacity
shadowLayer.shadowRadius = shadowRadius
self.layer.addSublayer(shadowLayer)
}
}
iOS阴影和拐角半径
[iOS CALayer]
[iOS masksToBounds]
[iOS调试渲染]
你可以使用图层设置阴影
view1.layer.shadowColor = UIColor.magenta.cgColor
view1.layer.shadowOffset = CGSize(width: 0, height: 0)
view1.layer.shadowOpacity = 1
view1.layer.shadowRadius = 0
可视化
1. shadowoffset。宽度,2. shadowoffset。高度,3。shadowOpacity 4。shadowRadius
shadowOffset宽度和高度是任意的 shadowOpacity从0到1 shadowRadius从0开始为正
不是简单的任务
请注意,阴影不是仅根据边界和边角raduis计算的。在创建阴影的过程中,需要考虑以下事项:
子视图层 子层 内容(支持图像)
view1.backgroundColor = .clear
view1.layer.contents = UIImage(named: "ring")?.cgImage
view1.layer.contentsScale = UIScreen.main.scale
ScaleFactor(contentsScale, rasterizationScale) -默认为1.0
currentBitmapSize = layerSize * scaleFactor
//non retina
1 point == 1x pixels
//Retina
1 point == 2x pixels
//or
1 point == 3x pixels
//For example to draw line
point(width: 4, height: 2) == 1x pixels(width: 4, height: 2)(8 pixels) == 2x pixels(width: 8, height: 4)(32 pixels)
使用uisscreen .main.scale =当前屏幕的缩放因子
[iOS像素、点数、单位]
的绩效
使用层。角半径,阴影有一些性能影响
至于层。cornerRadius性能:
应用它的颜色混合使用[阅读更多]
至于影子Xcode提示你:
The layer is using dynamic shadows which are expensive to render. If possible try setting shadowPath, or pre-rendering the shadow into an image and putting it under the layer
1. 另外使用shadowPath
用于内部静态层。默认情况下,它是nil,这就是为什么UIKit应该创建一个屏幕外视图,并基于这个信息创建一个阴影。这就是为什么您能够预定义路径并进行设置。另一个优点是,您可以根据需要创建自定义阴影
view1.layer.shadowPath = UIBezierPath(roundedRect: view1.bounds, cornerRadius: 50).cgPath
缺点-缺乏活力。如果视图改变边界(宽度,高度,角半径…),阴影仍然是它是(旧的边界)。如果视图的位置被改变(移动,滚动),shadowPath将是正确的
2. 缓存栅格化
(iOS shouldRasterize)