要UIScrollView *toScrollView
(屏幕的宽度),我想添加一个灰色的底部边框(与iPhone的原生消息应用程序的撰写视图的目标字段完全相同)。 / p>
为实现这一目标,我按了Cocoa Touch: How To Change UIView's Border Color And Thickness?并使用自定义UINavigationBar
覆盖了顶部边框,并使toScrollView
的x坐标为-1&宽度322使左和右;右边界就在屏幕外。
这看起来很好,但它有点像黑客,我想知道是否有更好的方法来做到这一点。
- (void)viewDidLoad {
[super viewDidLoad];
// Add UINavigationBar *navigationBar at top.
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:@selector(cancelAction)];
UINavigationBar *navigationBar = [[UINavigationBar alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)];
navigationBar.items = [NSArray arrayWithObject:self.navigationItem];
// Add UIScrollView *toScrollView below navigationBar.
UIScrollView *toScrollView = [[UIScrollView alloc]
initWithFrame:CGRectMake(-1.0f, 43.0f, 322.0f, 45.0f)];
toScrollView.backgroundColor = [UIColor whiteColor];
toScrollView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor;
toScrollView.layer.borderWidth = 1.0f;
[self.view addSubview:toScrollView];
[self.view addSubview:navigationBar]; // covers top of toScrollView
}
答案 0 :(得分:250)
正如@ImreKelényi建议的那样,您可以使用UIView
来代替使用CALayer
:
// Add a bottomBorder.
CALayer *bottomBorder = [CALayer layer];
bottomBorder.frame = CGRectMake(0.0f, 43.0f, toScrollView.frame.size.width, 1.0f);
bottomBorder.backgroundColor = [UIColor colorWithWhite:0.8f
alpha:1.0f].CGColor;
[toScrollView.layer addSublayer:bottomBorder];
答案 1 :(得分:68)
这是一个更通用的Swift扩展,可以为任何arr
子类创建边框:
UIView
import UIKit
extension UIView {
func addTopBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRectMake(0, 0, self.frame.size.width, width)
self.layer.addSublayer(border)
}
func addRightBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRectMake(self.frame.size.width - width, 0, width, self.frame.size.height)
self.layer.addSublayer(border)
}
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRectMake(0, self.frame.size.height - width, self.frame.size.width, width)
self.layer.addSublayer(border)
}
func addLeftBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.frame = CGRectMake(0, 0, width, self.frame.size.height)
self.layer.addSublayer(border)
}
}
答案 2 :(得分:60)
在以下类别中实施:
<强>的UIButton + Border.h:强>
@interface UIButton (Border)
- (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
- (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
- (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
- (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
@end
<强>的UIButton + Border.m:强>
@implementation UIButton (Border)
- (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
[self.layer addSublayer:border];
}
- (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
[self.layer addSublayer:border];
}
- (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
[self.layer addSublayer:border];
}
- (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
[self.layer addSublayer:border];
}
@end
答案 3 :(得分:20)
Swift 4
如果您需要一个真正的自适应解决方案(适用于所有屏幕尺寸),那么就是这样:
/**
* Extends UIView with shortcut methods
*
* @author Alexander Volkov
* @version 1.0
*/
extension UIView {
/// Adds bottom border to the view with given side margins
///
/// - Parameters:
/// - color: the border color
/// - margins: the left and right margin
/// - borderLineSize: the size of the border
func addBottomBorder(color: UIColor = UIColor.red, margins: CGFloat = 0, borderLineSize: CGFloat = 1) {
let border = UIView()
border.backgroundColor = color
border.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(border)
border.addConstraint(NSLayoutConstraint(item: border,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .height,
multiplier: 1, constant: borderLineSize))
self.addConstraint(NSLayoutConstraint(item: border,
attribute: .bottom,
relatedBy: .equal,
toItem: self,
attribute: .bottom,
multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: border,
attribute: .leading,
relatedBy: .equal,
toItem: self,
attribute: .leading,
multiplier: 1, constant: margins))
self.addConstraint(NSLayoutConstraint(item: border,
attribute: .trailing,
relatedBy: .equal,
toItem: self,
attribute: .trailing,
multiplier: 1, constant: margins))
}
}
答案 4 :(得分:10)
Swift 4解决方案
let bottomBorder = CALayer()
bottomBorder.frame = CGRect(x: 0.0, y: calendarView.frame.size.height-1, width: calendarView.frame.width, height: 1.0)
bottomBorder.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
calendarView.layer.addSublayer(bottomBorder)
背景色浅灰色。根据需要更改颜色。
答案 5 :(得分:8)
还有一些带有删除边框功能的改进代码。基于confile answer。
import UIKit
enum viewBorder: String {
case Left = "borderLeft"
case Right = "borderRight"
case Top = "borderTop"
case Bottom = "borderBottom"
}
extension UIView {
func addBorder(vBorder: viewBorder, color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
border.name = vBorder.rawValue
switch vBorder {
case .Left:
border.frame = CGRectMake(0, 0, width, self.frame.size.height)
case .Right:
border.frame = CGRectMake(self.frame.size.width - width, 0, width, self.frame.size.height)
case .Top:
border.frame = CGRectMake(0, 0, self.frame.size.width, width)
case .Bottom:
border.frame = CGRectMake(0, self.frame.size.height - width, self.frame.size.width, width)
}
self.layer.addSublayer(border)
}
func removeBorder(border: viewBorder) {
var layerForRemove: CALayer?
for layer in self.layer.sublayers! {
if layer.name == border.rawValue {
layerForRemove = layer
}
}
if let layer = layerForRemove {
layer.removeFromSuperlayer()
}
}
}
更新:Swift 3
import UIKit
enum ViewBorder: String {
case left, right, top, bottom
}
extension UIView {
func add(border: ViewBorder, color: UIColor, width: CGFloat) {
let borderLayer = CALayer()
borderLayer.backgroundColor = color.cgColor
borderLayer.name = border.rawValue
switch border {
case .left:
borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
case .right:
borderLayer.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height)
case .top:
borderLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
case .bottom:
borderLayer.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
}
self.layer.addSublayer(borderLayer)
}
func remove(border: ViewBorder) {
guard let sublayers = self.layer.sublayers else { return }
var layerForRemove: CALayer?
for layer in sublayers {
if layer.name == border.rawValue {
layerForRemove = layer
}
}
if let layer = layerForRemove {
layer.removeFromSuperlayer()
}
}
}
答案 6 :(得分:7)
这些扩展方法的问题在于,当UIView / UIButton稍后调整它的大小时,您没有机会更改CALayer的大小以匹配新大小。哪个会让你错位边框。我发现将UIButton子类化更好,你当然也可以将其他UIViews子类化。 这是一些代码:
enum BorderedButtonSide {
case Top, Right, Bottom, Left
}
class BorderedButton : UIButton {
private var borderTop: CALayer?
private var borderTopWidth: CGFloat?
private var borderRight: CALayer?
private var borderRightWidth: CGFloat?
private var borderBottom: CALayer?
private var borderBottomWidth: CGFloat?
private var borderLeft: CALayer?
private var borderLeftWidth: CGFloat?
func setBorder(side: BorderedButtonSide, _ color: UIColor, _ width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.CGColor
switch side {
case .Top:
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: width)
borderTop?.removeFromSuperlayer()
borderTop = border
borderTopWidth = width
case .Right:
border.frame = CGRect(x: frame.size.width - width, y: 0, width: width, height: frame.size.height)
borderRight?.removeFromSuperlayer()
borderRight = border
borderRightWidth = width
case .Bottom:
border.frame = CGRect(x: 0, y: frame.size.height - width, width: frame.size.width, height: width)
borderBottom?.removeFromSuperlayer()
borderBottom = border
borderBottomWidth = width
case .Left:
border.frame = CGRect(x: 0, y: 0, width: width, height: frame.size.height)
borderLeft?.removeFromSuperlayer()
borderLeft = border
borderLeftWidth = width
}
layer.addSublayer(border)
}
override func layoutSubviews() {
super.layoutSubviews()
borderTop?.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: borderTopWidth!)
borderRight?.frame = CGRect(x: frame.size.width - borderRightWidth!, y: 0, width: borderRightWidth!, height: frame.size.height)
borderBottom?.frame = CGRect(x: 0, y: frame.size.height - borderBottomWidth!, width: frame.size.width, height: borderBottomWidth!)
borderLeft?.frame = CGRect(x: 0, y: 0, width: borderLeftWidth!, height: frame.size.height)
}
}
答案 7 :(得分:6)
或者,性能最友好的方法是重载drawRect,就像那样:
@interface TPActionSheetButton : UIButton
@property (assign) BOOL drawsTopLine;
@property (assign) BOOL drawsBottomLine;
@property (assign) BOOL drawsRightLine;
@property (assign) BOOL drawsLeftLine;
@property (strong, nonatomic) UIColor * lineColor;
@end
@implementation TPActionSheetButton
- (void) drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 0.5f * [[UIScreen mainScreen] scale]);
CGFloat red, green, blue, alpha;
[self.lineColor getRed:&red green:&green blue:&blue alpha:&alpha];
CGContextSetRGBStrokeColor(ctx, red, green, blue, alpha);
if(self.drawsTopLine) {
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextStrokePath(ctx);
}
if(self.drawsBottomLine) {
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGContextStrokePath(ctx);
}
if(self.drawsLeftLine) {
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextStrokePath(ctx);
}
if(self.drawsRightLine) {
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGContextStrokePath(ctx);
}
[super drawRect:rect];
}
@end
答案 8 :(得分:5)
Swift 3版本的Confile回答:
import UIKit
extension UIView {
func addTopBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
self.layer.addSublayer(border)
}
func addRightBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
border.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height)
self.layer.addSublayer(border)
}
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
self.layer.addSublayer(border)
}
func addLeftBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
self.layer.addSublayer(border)
}
}
使用自动布局时的用法:
class CustomView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
addBottomBorderWithColor(color: UIColor.white, width: 1)
}
}
答案 9 :(得分:3)
Swift
创建UIView扩展
private var bottomLineColorAssociatedKey : UIColor = .black
private var topLineColorAssociatedKey : UIColor = .black
private var rightLineColorAssociatedKey : UIColor = .black
private var leftLineColorAssociatedKey : UIColor = .black
extension UIView {
@IBInspectable var bottomLineColor: UIColor {
get {
if let color = objc_getAssociatedObject(self, &bottomLineColorAssociatedKey) as? UIColor {
return color
} else {
return .black
}
} set {
objc_setAssociatedObject(self, &bottomLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
@IBInspectable var bottomLineWidth: CGFloat {
get {
return self.bottomLineWidth
}
set {
DispatchQueue.main.async {
self.addBottomBorderWithColor(color: self.bottomLineColor, width: newValue)
}
}
}
@IBInspectable var topLineColor: UIColor {
get {
if let color = objc_getAssociatedObject(self, &topLineColorAssociatedKey) as? UIColor {
return color
} else {
return .black
}
} set {
objc_setAssociatedObject(self, &topLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
@IBInspectable var topLineWidth: CGFloat {
get {
return self.topLineWidth
}
set {
DispatchQueue.main.async {
self.addTopBorderWithColor(color: self.topLineColor, width: newValue)
}
}
}
@IBInspectable var rightLineColor: UIColor {
get {
if let color = objc_getAssociatedObject(self, &rightLineColorAssociatedKey) as? UIColor {
return color
} else {
return .black
}
} set {
objc_setAssociatedObject(self, &rightLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
@IBInspectable var rightLineWidth: CGFloat {
get {
return self.rightLineWidth
}
set {
DispatchQueue.main.async {
self.addRightBorderWithColor(color: self.rightLineColor, width: newValue)
}
}
}
@IBInspectable var leftLineColor: UIColor {
get {
if let color = objc_getAssociatedObject(self, &leftLineColorAssociatedKey) as? UIColor {
return color
} else {
return .black
}
} set {
objc_setAssociatedObject(self, &leftLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
@IBInspectable var leftLineWidth: CGFloat {
get {
return self.leftLineWidth
}
set {
DispatchQueue.main.async {
self.addLeftBorderWithColor(color: self.leftLineColor, width: newValue)
}
}
}
func addTopBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.name = "topBorderLayer"
removePreviouslyAddedLayer(name: border.name ?? "")
border.backgroundColor = color.cgColor
border.frame = CGRect(x: 0, y : 0,width: self.frame.size.width, height: width)
self.layer.addSublayer(border)
}
func addRightBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.name = "rightBorderLayer"
removePreviouslyAddedLayer(name: border.name ?? "")
border.backgroundColor = color.cgColor
border.frame = CGRect(x: self.frame.size.width - width, y: 0, width : width, height :self.frame.size.height)
self.layer.addSublayer(border)
}
func addBottomBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.name = "bottomBorderLayer"
removePreviouslyAddedLayer(name: border.name ?? "")
border.backgroundColor = color.cgColor
border.frame = CGRect(x: 0, y: self.frame.size.height - width,width : self.frame.size.width,height: width)
self.layer.addSublayer(border)
}
func addLeftBorderWithColor(color: UIColor, width: CGFloat) {
let border = CALayer()
border.name = "leftBorderLayer"
removePreviouslyAddedLayer(name: border.name ?? "")
border.backgroundColor = color.cgColor
border.frame = CGRect(x:0, y:0,width : width, height : self.frame.size.height)
self.layer.addSublayer(border)
}
func removePreviouslyAddedLayer(name : String) {
if self.layer.sublayers?.count ?? 0 > 0 {
self.layer.sublayers?.forEach {
if $0.name == name {
$0.removeFromSuperlayer()
}
}
}
}
}
目标C
创建UIView的类别类
<强>的UIView + Border.h 强>
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface UIView (Border)
@property (nonatomic) IBInspectable UIColor *topLineColor;
@property (nonatomic) IBInspectable CGFloat topLineWidth;
@property (nonatomic) IBInspectable UIColor *bottomLineColor;
@property (nonatomic) IBInspectable CGFloat bottomLineWidth;
@property (nonatomic) IBInspectable UIColor *rightLineColor;
@property (nonatomic) IBInspectable CGFloat rightLineWidth;
@property (nonatomic) IBInspectable UIColor *leftLineColor;
@property (nonatomic) IBInspectable CGFloat leftLineWidth;
- (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
- (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
- (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
- (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth;
@end
<强>的UIView + Border.m 强>
#import "UIView+Border.h"
#import <objc/runtime.h>
static char bottomLineColorKey,topLineColorKey,rightLineColorKey,leftLineColorKey;
@implementation UIView(Border)
@dynamic bottomLineWidth,topLineWidth,rightLineWidth,leftLineWidth;
// for Bottom Line
- (UIColor *)bottomLineColor {
return objc_getAssociatedObject(self, &bottomLineColorKey);
}
- (void)setBottomLineColor:(UIColor *)bottomLineColor {
objc_setAssociatedObject(self, &bottomLineColorKey,
bottomLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(void)setBottomLineWidth:(CGFloat)bottomLineWidth {
dispatch_async(dispatch_get_main_queue(), ^{
[self addBottomBorderWithColor:[self bottomLineColor] andWidth:bottomLineWidth];
});
}
// for top Line
- (UIColor *)topLineColor {
return objc_getAssociatedObject(self, &topLineColorKey);
}
- (void)setTopLineColor:(UIColor *)topLineColor {
objc_setAssociatedObject(self, &topLineColorKey,
topLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setTopLineWidth:(CGFloat)topLineWidth{
dispatch_async(dispatch_get_main_queue(), ^{
[self addTopBorderWithColor:[self topLineColor] andWidth:topLineWidth];
});
}
// for right Line
- (UIColor *)rightLineColor {
return objc_getAssociatedObject(self, &rightLineColorKey);
}
-(void)setRightLineColor:(UIColor *)rightLineColor {
objc_setAssociatedObject(self, &rightLineColorKey,
rightLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(void)setRightLineWidth:(CGFloat)rightLineWidth{
dispatch_async(dispatch_get_main_queue(), ^{
[self addRightBorderWithColor:[self rightLineColor] andWidth:rightLineWidth];
});
}
// for left Line
-(UIColor *)leftLineColor {
return objc_getAssociatedObject(self, &leftLineColorKey);
}
-(void)setLeftLineColor:(UIColor *)leftLineColor{
objc_setAssociatedObject(self, &leftLineColorKey,
leftLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(void)setLeftLineWidth:(CGFloat)leftLineWidth{
dispatch_async(dispatch_get_main_queue(), ^{
[self addLeftBorderWithColor:[self leftLineColor] andWidth:leftLineWidth];
});
}
- (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.name = @"topBorderLayer";
[self removePreviouslyAddedLayer:border.name];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
[self.layer addSublayer:border];
}
- (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.name = @"bottomBorderLayer";
[self removePreviouslyAddedLayer:border.name];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
[self.layer addSublayer:border];
}
- (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.name = @"leftBorderLayer";
[self removePreviouslyAddedLayer:border.name];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
[self.layer addSublayer:border];
}
- (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
CALayer *border = [CALayer layer];
border.name = @"rightBorderLayer";
[self removePreviouslyAddedLayer:border.name];
border.backgroundColor = color.CGColor;
border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
[self.layer addSublayer:border];
}
- (void)removePreviouslyAddedLayer:(NSString *)name {
if (self.layer.sublayers.count > 0) {
for (CALayer *layer in self.layer.sublayers) {
if ([layer.name isEqualToString:name]) {
[layer removeFromSuperlayer];
}
}
}
}
@end
用法: - 从故事板中选择任何控件,然后显示属性检查器(右侧)您将看到下面的图像示例。(注意:边框仅在运行时出现。)
现在您可以设置边框颜色和宽度的任何一面。
答案 10 :(得分:2)
我写了一个通用方法,可以在任何UIView
的任意一侧添加边框。您可以为每一侧定义厚度,颜色,边距和zOrder
。
/*
view: the view to draw border around
thickness: thickness of the border on the given side
color: color of the border on the given side
margin: space between the border's outer edge and the view's frame edge on the given side.
zOrder: defines the order to add the borders to the view. The borders will be added by zOrder from lowest to highest, thus making the highest priority border visible when two borders overlap at the corners.
*/
+(void) drawBorderAroundUIView:(UIView *) view thicknessLeft:(CGFloat) thicknessLeft colorLeft:(UIColor *)colorLeft marginLeft:(CGFloat) marginLeft zOrderLeft:(int) zOrderLeft thicknessRight:(CGFloat) thicknessRight colorRight:(UIColor *)colorRight marginRight:(CGFloat) marginRight zOrderRight:(int) zOrderRight thicknessTop:(CGFloat) thicknessTop colorTop:(UIColor *)colorTop marginTop:(CGFloat) marginTop zOrderTop:(int) zOrderTop thicknessBottom:(CGFloat) thicknessBottom colorBottom:(UIColor *)colorBottom marginBottom:(CGFloat) marginBottom zOrderBottom:(int) zOrderBottom{
//make margins be the outside edge and make positive margin represent a smaller rectangle
marginBottom = -1 * marginBottom - thicknessBottom;
marginTop = -1 * marginTop - thicknessTop;
marginLeft = -1 * marginLeft - thicknessLeft;
marginRight = -1 * marginRight - thicknessRight;
//get reference points for corners
CGPoint upperLeftCorner = CGPointZero;
CGPoint lowerLeftCorner = CGPointMake(upperLeftCorner.x, upperLeftCorner.y + view.frame.size.height);
CGPoint upperRightCorner = CGPointMake(upperLeftCorner.x + view.frame.size.width, upperLeftCorner.y);
//left
CALayer *leftBorder = [CALayer layer];
leftBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, upperLeftCorner.y - thicknessTop - marginTop, thicknessLeft, view.frame.size.height + marginTop + marginBottom + thicknessBottom + thicknessTop);
leftBorder.backgroundColor = colorLeft.CGColor;
//right
CALayer *rightBorder = [CALayer layer];
rightBorder.frame = CGRectMake(upperRightCorner.x + marginRight, upperRightCorner.y - thicknessTop - marginTop, thicknessRight, view.frame.size.height + marginTop + marginBottom + thicknessBottom + thicknessTop);
rightBorder.backgroundColor = colorRight.CGColor;
//top
CALayer *topBorder = [CALayer layer];
topBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, upperLeftCorner.y - thicknessTop - marginTop, view.frame.size.width + marginLeft + marginRight + thicknessLeft + thicknessRight, thicknessTop);
topBorder.backgroundColor = colorTop.CGColor;
//bottom
CALayer *bottomBorder = [CALayer layer];
bottomBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, lowerLeftCorner.y + marginBottom, view.frame.size.width + marginLeft + marginRight + thicknessLeft + thicknessRight, thicknessBottom);
bottomBorder.backgroundColor = colorBottom.CGColor;
//define dictionary keys to be used for adding borders in order of zOrder
NSString *borderDK = @"border";
NSString *zOrderDK = @"zOrder";
//storing borders in dictionaries in preparation to add them in order of zOrder
NSDictionary *leftBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:leftBorder, borderDK, [NSNumber numberWithInt:zOrderLeft], zOrderDK, nil];
NSDictionary *rightBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:rightBorder, borderDK, [NSNumber numberWithInt:zOrderRight], zOrderDK, nil];
NSDictionary *topBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:topBorder, borderDK, [NSNumber numberWithInt:zOrderTop], zOrderDK, nil];
NSDictionary *bottomBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:bottomBorder, borderDK, [NSNumber numberWithInt:zOrderBottom], zOrderDK, nil];
NSMutableArray *borders = [NSMutableArray arrayWithObjects:leftBorderDictionary, rightBorderDictionary, topBorderDictionary, bottomBorderDictionary, nil];
//add borders in order of zOrder (lowest -> highest). Thus the highest zOrder will be added last so it will be on top.
while (borders.count)
{
//look for the next lowest zOrder border to add
NSDictionary *nextBorderToLayDown = [borders objectAtIndex:0];
for (int indexOfBorder = 0; indexOfBorder < borders.count; indexOfBorder++)
{
NSDictionary *borderAtIndex = [borders objectAtIndex:indexOfBorder];
if ([[borderAtIndex objectForKey:zOrderDK] intValue] < [[nextBorderToLayDown objectForKey:zOrderDK] intValue])
{
nextBorderToLayDown = borderAtIndex;
}
}
//add the border to the view
[view.layer addSublayer:[nextBorderToLayDown objectForKey:borderDK]];
[borders removeObject:nextBorderToLayDown];
}
}
答案 11 :(得分:1)
Swift 4/3
您可以在下方使用此解决方案。它适用于比层更轻的UIBezierPaths,从而缩短了启动时间。它易于使用,请参阅下面的说明。
class ResizeBorderView: UIView {
var color = UIColor.white
var lineWidth: CGFloat = 1
var edges = [UIRectEdge](){
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
if edges.contains(.top) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0, y: 0 + lineWidth / 2))
path.addLine(to: CGPoint(x: self.bounds.width, y: 0 + lineWidth / 2))
path.stroke()
}
if edges.contains(.bottom) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0, y: self.bounds.height - lineWidth / 2))
path.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height - lineWidth / 2))
path.stroke()
}
if edges.contains(.left) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0 + lineWidth / 2, y: 0))
path.addLine(to: CGPoint(x: 0 + lineWidth / 2, y: self.bounds.height))
path.stroke()
}
if edges.contains(.right) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: self.bounds.width - lineWidth / 2, y: 0))
path.addLine(to: CGPoint(x: self.bounds.width - lineWidth / 2, y: self.bounds.height))
path.stroke()
}
}
}
答案 12 :(得分:1)
雨燕4
基于https://stackoverflow.com/a/32513578/5391914
import UIKit
enum viewBorder: String {
case Left = "borderLeft"
case Right = "borderRight"
case Top = "borderTop"
case Bottom = "borderBottom"
}
extension UIView {
func addBorder(vBorders: [viewBorder], color: UIColor, width: CGFloat) {
vBorders.forEach { vBorder in
let border = CALayer()
border.backgroundColor = color.cgColor
border.name = vBorder.rawValue
switch vBorder {
case .Left:
border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
case .Right:
border.frame = CGRect(x:self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height)
case .Top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
case .Bottom:
border.frame = CGRect(x: 0, y: self.frame.size.height - width , width: self.frame.size.width, height: width)
}
self.layer.addSublayer(border)
}
}
}
答案 13 :(得分:1)
Swift 4
基于:https://stackoverflow.com/a/32821607/9980800
UIView + Border
extension UIView {
enum ViewBorder: String {
case left, right, top, bottom
}
func add(Border border: ViewBorder, withColor color: UIColor = UIColor.lightGray, andWidth width: CGFloat = 1.0) {
let borderView = UIView()
borderView.backgroundColor = color
borderView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(borderView)
NSLayoutConstraint.activate(getConstrainsFor(forView: borderView, WithBorderType: border, andWidth: width))
}
private func getConstrainsFor(forView borderView: UIView, WithBorderType border: ViewBorder, andWidth width: CGFloat) -> [NSLayoutConstraint] {
let height = borderView.heightAnchor.constraint(equalToConstant: width)
let widthAnchor = borderView.widthAnchor.constraint(equalToConstant: width)
let leading = borderView.leadingAnchor.constraint(equalTo: self.leadingAnchor)
let trailing = borderView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
let top = borderView.topAnchor.constraint(equalTo: self.topAnchor)
let bottom = borderView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
switch border {
case .bottom:
return [bottom, leading, trailing, height]
case .top:
return [top, leading, trailing, height]
case .left:
return [top, bottom, leading, widthAnchor]
case .right:
return [top, bottom, trailing, widthAnchor]
}
}
}
用法:-
class ViewController: UIViewController {
@IBOutlet weak var sampleView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
sampleView.add(Border: .bottom)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
答案 14 :(得分:1)
如果使用约束(因此没有框架大小),则可以添加具有所需约束的边框视图
// MARK: - Add a border to one side of a view
public enum BorderSide {
case top, bottom, left, right
}
extension UIView {
public func addBorder(side: BorderSide, color: UIColor, width: CGFloat) {
let border = UIView()
border.translatesAutoresizingMaskIntoConstraints = false
border.backgroundColor = color
self.addSubview(border)
let topConstraint = topAnchor.constraint(equalTo: border.topAnchor)
let rightConstraint = trailingAnchor.constraint(equalTo: border.trailingAnchor)
let bottomConstraint = bottomAnchor.constraint(equalTo: border.bottomAnchor)
let leftConstraint = leadingAnchor.constraint(equalTo: border.leadingAnchor)
let heightConstraint = border.heightAnchor.constraint(equalToConstant: width)
let widthConstraint = border.widthAnchor.constraint(equalToConstant: width)
switch side {
case .top:
NSLayoutConstraint.activate([leftConstraint, topConstraint, rightConstraint, heightConstraint])
case .right:
NSLayoutConstraint.activate([topConstraint, rightConstraint, bottomConstraint, widthConstraint])
case .bottom:
NSLayoutConstraint.activate([rightConstraint, bottomConstraint, leftConstraint, heightConstraint])
case .left:
NSLayoutConstraint.activate([bottomConstraint, leftConstraint, topConstraint, widthConstraint])
}
}
}
然后将其设置如下所示
myButton.addBorder(side: .left, color: UIColor.lightGray, width: 1)
(受this answer启发)
答案 15 :(得分:1)
您不必为每个边框添加图层,只需使用贝塞尔曲线路径绘制一次。
CGRect rect = self.bounds;
CGPoint destPoint[4] = {CGPointZero,
(CGPoint){0, rect.size.height},
(CGPoint){rect.size.width, rect.size.height},
(CGPoint){rect.size.width, 0}};
BOOL position[4] = {_top, _left, _bottom, _right};
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:destPoint[3]];
for (int i = 0; i < 4; ++i) {
if (position[i]) {
[path addLineToPoint:destPoint[i]];
} else {
[path moveToPoint:destPoint[i]];
}
}
CAShapeLayer *borderLayer = [CAShapeLayer new];
borderLayer.frame = self.bounds;
borderLayer.path = path.CGPath;
borderLayer.lineWidth = _borderWidth ?: 1 / [UIScreen mainScreen].scale;
borderLayer.strokeColor = _borderColor.CGColor;
borderLayer.fillColor = [UIColor clearColor].CGColor;
[self.layer addSublayer:borderLayer];
答案 16 :(得分:1)
extension UIView {
func addBottomLine(color: UIColor, height: CGFloat) {
let bottomView = UIView(frame: CGRect(x: 0, y: self.frame.height - 1, width: self.frame.width, height: height))
bottomView.translatesAutoresizingMaskIntoConstraints = false
bottomView.autoresizingMask = .flexibleWidth
bottomView.backgroundColor = color
self.addSubview(bottomView)
}
}
答案 17 :(得分:0)
最完整的答案。 https://github.com/oney/UIView-Border
let rectangle = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 60))
rectangle.backgroundColor = UIColor.grayColor()
view.addSubview(rectangle)
rectangle.borderTop = Border(size: 3, color: UIColor.orangeColor(), offset: UIEdgeInsets(top: 0, left: -10, bottom: 0, right: -5))
rectangle.borderBottom = Border(size: 6, color: UIColor.redColor(), offset: UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 0))
rectangle.borderLeft = Border(size: 2, color: UIColor.blueColor(), offset: UIEdgeInsets(top: 10, left: -10, bottom: 0, right: 0))
rectangle.borderRight = Border(size: 2, color: UIColor.greenColor(), offset: UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 0))
答案 18 :(得分:0)
迅速4扩展名与边框的宽度和颜色。 很棒!
@IBDesignable
final class SideBorders: UIView {
@IBInspectable var topColor: UIColor = UIColor.clear
@IBInspectable var topWidth: CGFloat = 0
@IBInspectable var rightColor: UIColor = UIColor.clear
@IBInspectable var rightWidth: CGFloat = 0
@IBInspectable var bottomColor: UIColor = UIColor.clear
@IBInspectable var bottomWidth: CGFloat = 0
@IBInspectable var leftColor: UIColor = UIColor.clear
@IBInspectable var leftWidth: CGFloat = 0
override func draw(_ rect: CGRect) {
let topBorder = CALayer()
topBorder.backgroundColor = topColor.cgColor
topBorder.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: topWidth)
self.layer.addSublayer(topBorder)
let rightBorder = CALayer()
rightBorder.backgroundColor = rightColor.cgColor
rightBorder.frame = CGRect(x: self.frame.size.width - rightWidth, y: 0, width: rightWidth, height: self.frame.size.height)
self.layer.addSublayer(rightBorder)
let bottomBorder = CALayer()
bottomBorder.backgroundColor = bottomColor.cgColor
bottomBorder.frame = CGRect(x: 0, y: self.frame.size.height - bottomWidth, width: self.frame.size.width, height: bottomWidth)
self.layer.addSublayer(bottomBorder)
let leftBorder = CALayer()
leftBorder.backgroundColor = leftColor.cgColor
leftBorder.frame = CGRect(x: 0, y: self.frame.size.height - leftWidth, width: self.frame.size.width, height: leftWidth)
self.layer.addSublayer(leftBorder)
}
}
答案 19 :(得分:0)
迅速5.1。与两个扩展一起使用,方法返回CALayer,因此您将重用它来更新框架。
enum Border: Int {
case top = 0
case bottom
case right
case left
}
extension UIView {
func addBorder(for side: Border, withColor color: UIColor, borderWidth: CGFloat) -> CALayer {
let borderLayer = CALayer()
borderLayer.backgroundColor = color.cgColor
let xOrigin: CGFloat = (side == .right ? frame.width - borderWidth : 0)
let yOrigin: CGFloat = (side == .bottom ? frame.height - borderWidth : 0)
let width: CGFloat = (side == .right || side == .left) ? borderWidth : frame.width
let height: CGFloat = (side == .top || side == .bottom) ? borderWidth : frame.height
borderLayer.frame = CGRect(x: xOrigin, y: yOrigin, width: width, height: height)
layer.addSublayer(borderLayer)
return borderLayer
}
}
extension CALayer {
func updateBorderLayer(for side: Border, withViewFrame viewFrame: CGRect) {
let xOrigin: CGFloat = (side == .right ? viewFrame.width - frame.width : 0)
let yOrigin: CGFloat = (side == .bottom ? viewFrame.height - frame.height : 0)
let width: CGFloat = (side == .right || side == .left) ? frame.width : viewFrame.width
let height: CGFloat = (side == .top || side == .bottom) ? frame.height : viewFrame.height
frame = CGRect(x: xOrigin, y: yOrigin, width: width, height: height)
}
}