次のようなビューでコードを使用してビューの境界線を追加する場合
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;
次のようにビュー内に境界線が追加されます。
ご覧のとおり、右側のビューは元のビューです。境界線付きビューの黒い領域は元のビューよりも小さくなっています。しかし、私が取得したいのは、次のような元のビューの外側の境界線です:。黒い領域は元の領域と同じですが、どうすれば実装できますか?
残念ながら、境界線を外側に揃えるために設定できる小さなプロパティはありません。 UIViewsのデフォルトの描画操作はその境界内で描画するため、内側に揃えて描画します。
頭に浮かぶ最も簡単な解決策は、境界線を適用するときに、境界線の幅のサイズでUIViewを拡張することです。
CGFloat borderWidth = 2.0f;
self.frame = CGRectInset(self.frame, -borderWidth, -borderWidth);
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = borderWidth;
はい、すでに受け入れられた答えがありますが、それを行うためのより良い方法があると思います、あなたはあなたのビューより少し大きい新しいレイヤーを持っている必要があり、ビューのレイヤーの境界にマスクしないでください(実際にはデフォルトの動作)。サンプルコードは次のとおりです。
CALayer * externalBorder = [CALayer layer];
externalBorder.frame = CGRectMake(-1, -1, myView.frame.size.width+2, myView.frame.size.height+2);
externalBorder.borderColor = [UIColor blackColor].CGColor;
externalBorder.borderWidth = 1.0;
[myView.layer addSublayer:externalBorder];
myView.layer.masksToBounds = NO;
もちろん、これは境界線を1単位の大きさにしたい場合です。もっと大きくしたい場合は、borderWidth
とレイヤーのフレームをそれに応じて調整します。これは、CALayer
がUIView
よりも軽いため、2番目のビューを使用するよりも優れており、myView
のフレームを変更する必要はありません。 myView
はaUIImageView
です
N.B:私にとって、結果はシミュレーターでは完璧ではありませんでした(レイヤーが正確な位置になかったため、レイヤーが一方の側で厚くなったことがありました)が、実際のデバイスで要求されたとおりでした。
編集
実際にN.Bで話している問題は、シミュレーターの画面を縮小したからでした。通常のサイズではまったく問題はありません。
それが役に立てば幸い
上記の受け入れられた最良の答えで、私はそのようなではないニースの結果と見苦しいエッジを経験しました:
したがって、UIViewSwift拡張機能を共有します。これは、UIBezierPathを境界線のアウトラインとして使用します-見苦しいエッジなし( @Fattie ):
// UIView+BezierPathBorder.Swift
import UIKit
extension UIView {
fileprivate var bezierPathIdentifier:String { return "bezierPathBorderLayer" }
fileprivate var bezierPathBorder:CAShapeLayer? {
return (self.layer.sublayers?.filter({ (layer) -> Bool in
return layer.name == self.bezierPathIdentifier && (layer as? CAShapeLayer) != nil
}) as? [CAShapeLayer])?.first
}
func bezierPathBorder(_ color:UIColor = .white, width:CGFloat = 1) {
var border = self.bezierPathBorder
let path = UIBezierPath(roundedRect: self.bounds, cornerRadius:self.layer.cornerRadius)
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
if (border == nil) {
border = CAShapeLayer()
border!.name = self.bezierPathIdentifier
self.layer.addSublayer(border!)
}
border!.frame = self.bounds
let pathUsingCorrectInsetIfAny =
UIBezierPath(roundedRect: border!.bounds, cornerRadius:self.layer.cornerRadius)
border!.path = pathUsingCorrectInsetIfAny.cgPath
border!.fillColor = UIColor.clear.cgColor
border!.strokeColor = color.cgColor
border!.lineWidth = width * 2
}
func removeBezierPathBorder() {
self.layer.mask = nil
self.bezierPathBorder?.removeFromSuperlayer()
}
}
例:
let view = UIView(frame: CGRect(x: 20, y: 20, width: 100, height: 100))
view.layer.cornerRadius = view.frame.width / 2
view.backgroundColor = .red
//add white 2 pixel border outline
view.bezierPathBorder(.white, width: 2)
//remove border outline (optional)
view.removeBezierPathBorder()
直接的な方法はありません。いくつかの回避策を検討できます。
明確な境界線(明確な境界線)が必要ない場合は、目的のために影に頼ることができます
[view1 setBackgroundColor:[UIColor blackColor]];
UIColor *color = [UIColor yellowColor];
view1.layer.shadowColor = [color CGColor];
view1.layer.shadowRadius = 10.0f;
view1.layer.shadowOpacity = 1;
view1.layer.shadowOffset = CGSizeZero;
view1.layer.masksToBounds = NO;
Swift実装の場合、これをUIView拡張機能として追加できます。
extension UIView {
struct Constants {
static let ExternalBorderName = "externalBorder"
}
func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.whiteColor()) -> CALayer {
let externalBorder = CALayer()
externalBorder.frame = CGRectMake(-borderWidth, -borderWidth, frame.size.width + 2 * borderWidth, frame.size.height + 2 * borderWidth)
externalBorder.borderColor = borderColor.CGColor
externalBorder.borderWidth = borderWidth
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, atIndex: 0)
layer.masksToBounds = false
return externalBorder
}
func removeExternalBorders() {
layer.sublayers?.filter() { $0.name == Constants.ExternalBorderName }.forEach() {
$0.removeFromSuperlayer()
}
}
func removeExternalBorder(externalBorder: CALayer) {
guard externalBorder.name == Constants.ExternalBorderName else { return }
externalBorder.removeFromSuperlayer()
}
}
枠を追加する前に、枠の幅でビューのフレームの幅と高さを増やします。
float borderWidth = 2.0f
CGRect frame = self.frame;
frame.width += borderWidth;
frame.height += borderWidth;
self.layer.borderColor = [UIColor yellowColor].CGColor;
self.layer.borderWidth = 2.0f;
実際には非常に簡単な解決策があります。両方を次のように設定します。
view.layer.borderWidth = 5
view.layer.borderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.25).cgColor
@piccianoと@Maksim Kniazevのソリューションが気に入りました。また、次のようにして環状の境界線を作成することもできます。
func addExternalAnnularBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) {
let externalBorder = CALayer()
externalBorder.frame = CGRect(x: -borderWidth*2, y: -borderWidth*2, width: frame.size.width + 4 * borderWidth, height: frame.size.height + 4 * borderWidth)
externalBorder.borderColor = borderColor.cgColor
externalBorder.borderWidth = borderWidth
externalBorder.cornerRadius = (frame.size.width + 4 * borderWidth) / 2
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, at: 0)
layer.masksToBounds = false
}
@ piccianoの解が好きでした。正方形の代わりに円を分解したい場合は、addExternalBorder関数を次のように置き換えます。
func addExternalBorder(borderWidth: CGFloat = 2.0, borderColor: UIColor = UIColor.white) {
let externalBorder = CALayer()
externalBorder.frame = CGRect(x: -borderWidth, y: -borderWidth, width: frame.size.width + 2 * borderWidth, height: frame.size.height + 2 * borderWidth)
externalBorder.borderColor = borderColor.cgColor
externalBorder.borderWidth = borderWidth
externalBorder.cornerRadius = (frame.size.width + 2 * borderWidth) / 2
externalBorder.name = Constants.ExternalBorderName
layer.insertSublayer(externalBorder, at: 0)
layer.masksToBounds = false
}