UIBezierPathを使用してimageviewの角を丸くしていますが、imageviewに境界線も追加したいと思います。上部がuiimageで下部がラベルであることを覚えておいてください。
現在このコードを使用すると、以下が生成されます。
let rectShape = CAShapeLayer()
rectShape.bounds = myCell2.NewFeedImageView.frame
rectShape.position = myCell2.NewFeedImageView.center
rectShape.path = UIBezierPath(roundedRect: myCell2.NewFeedImageView.bounds,
byRoundingCorners: .TopRight | .TopLeft,
cornerRadii: CGSize(width: 25, height: 25)).CGPath
myCell2.NewFeedImageView.layer.mask = rectShape
緑色の枠を追加したいのですが、使用できません
myCell2.NewFeedImageView.layer.borderWidth = 8
myCell2.NewFeedImageView.layer.borderColor = UIColor.greenColor().CGColor
この画像のように、境界線の左上隅と右上隅が切り取られているためです。
私の現在のコードと一緒にUIBezierPathを使用して境界線を追加する方法もありますか?
UIBezierPathパスを再利用して、シェイプレイヤーをビューに追加できます。以下は、ビューコントローラ内の例です。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Create a view with red background for demonstration
let v = UIView(frame: CGRectMake(0, 0, 100, 100))
v.center = view.center
v.backgroundColor = UIColor.redColor()
view.addSubview(v)
// Add rounded corners
let maskLayer = CAShapeLayer()
maskLayer.frame = v.bounds
maskLayer.path = UIBezierPath(roundedRect: v.bounds, byRoundingCorners: .TopRight | .TopLeft, cornerRadii: CGSize(width: 25, height: 25)).CGPath
v.layer.mask = maskLayer
// Add border
let borderLayer = CAShapeLayer()
borderLayer.path = maskLayer.path // Reuse the Bezier path
borderLayer.fillColor = UIColor.clearColor().CGColor
borderLayer.strokeColor = UIColor.greenColor().CGColor
borderLayer.lineWidth = 5
borderLayer.frame = v.bounds
v.layer.addSublayer(borderLayer)
}
}
最終結果は次のようになります。
これは、ビューのサイズが固定されている場合にのみ期待どおりに機能することに注意してください。ビューのサイズを変更できる場合は、カスタムビュークラスを作成し、layoutSubviews
のレイヤーのサイズを変更する必要があります。
上記のように:
これがドロップインソリューションです。
この
描画している問題に正しく対処します[〜#〜] half [〜#〜]OFボーダーライン
自動レイアウトで完全に使用可能です
ビューのサイズが変更された場合またはアニメーション化された場合に、完全に再調整されます。
完全にIBDesignableです-ストーリーボードでリアルタイムに確認できます
2019のために...
@IBDesignable
class RoundedCornersAndTrueBorder: UIView {
@IBInspectable var cornerRadius: CGFloat = 10 {
didSet { setup() }
}
@IBInspectable var borderColor: UIColor = UIColor.black {
didSet { setup() }
}
@IBInspectable var trueBorderWidth: CGFloat = 2.0 {
didSet { setup() }
}
override func layoutSubviews() {
setup()
}
var border:CAShapeLayer? = nil
func setup() {
// make a path with round corners
let path = UIBezierPath(
roundedRect: self.bounds, cornerRadius:cornerRadius)
// note that it is >exactly< the size of the whole view
// mask the whole view to that shape
// note that you will ALSO be masking the border we'll draw below
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
// add another layer, which will be the border as such
if (border == nil) {
border = CAShapeLayer()
self.layer.addSublayer(border!)
}
// IN SOME APPROACHES YOU would INSET THE FRAME
// of the border-drawing layer by the width of the border
// border.frame = bounds.insetBy(dx: borderWidth, dy: borderWidth)
// so that when you draw the line, ALL of the WIDTH of the line
// DOES fall within the actual mask.
// here, we will draw the border-line LITERALLY ON THE Edge
// of the path. that means >HALF< THE LINE will be INSIDE
// the path and HALF THE LINE WILL BE OUTSIDE the path
border!.frame = bounds
let pathUsingCorrectInsetIfAny =
UIBezierPath(roundedRect: border!.bounds, cornerRadius:cornerRadius)
border!.path = pathUsingCorrectInsetIfAny.cgPath
border!.fillColor = UIColor.clear.cgColor
// the following is not what you want:
// it results in "half-missing corners"
// (note however, sometimes you do use this approach):
//border.borderColor = borderColor.cgColor
//border.borderWidth = borderWidth
// this approach will indeed be "inside" the path:
border!.strokeColor = borderColor.cgColor
border!.lineWidth = trueBorderWidth * 2.0
// HALF THE LINE will be INSIDE the path and HALF THE LINE
// WILL BE OUTSIDE the path. so MAKE IT >>TWICE AS THICK<<
// as requested by the consumer class.
}
}
以上です。
「Fattie.Swift」と呼ばれる「新しいSwiftファイル)を作成します。(おかしなことに、実際にはそれが何と呼んでも違いはありません。「わからない」の段階にいる場合新しいファイルを作成する方法」で基本的なXcodeチュートリアルを探してください。)
上記のコードをすべてファイルに入れます
プロジェクトにクラス「RoundedCornersAndTrueBorder」を追加しました。
あなたのストーリーボード。 通常のUIViewをシーンに追加します。実際、実際のサイズや形は何でも好きなようにしてください。
Identity Inspectorを見てください。 (それが何であるかわからない場合は、基本的なチュートリアルを探してください。)クラスを「RoundedCornersAndTrueBorder」に変更するだけです。 (「Roun ...」と入力し始めると、どのクラスを意味するか推測します。
これで完了です-プロジェクトを実行してください。
もちろん、Xcodeで行うこととまったく同じように、UIViewに完全で正しい制約を追加する必要があることに注意してください。楽しい!
同様のソリューション:
https://stackoverflow.com/a/57465440/294884 -画像+丸め+影
https://stackoverflow.com/a/41553784/294884 -2つのコーナーの問題
https://stackoverflow.com/a/59092828/294884 -「シャドウ+ホール」または「グローボックス」の問題
https://stackoverflow.com/a/57400842/294884 -「境界線とギャップ」の問題
https://stackoverflow.com/a/57514286/294884 -基本的な「追加」ベジエ
さらに面倒なことはありませんが、これはまさにこれを行う方法です。
重要な事実は
だから、通常の方法でセットアップ
import UIKit
@IBDesignable class GreenCirclePerson: UIView {
@IBInspectable var borderColor: UIColor = UIColor.black { didSet { setup() } }
@IBInspectable var trueBorderThickness: CGFloat = 2.0 { didSet { setup() } }
@IBInspectable var trueGapThickness: CGFloat = 2.0 { didSet { setup() } }
@IBInspectable var picture: UIImage? = nil { didSet { setup() } }
override func layoutSubviews() { setup() }
var imageLayer: CALayer? = nil
var border: CAShapeLayer? = nil
func setup() {
if (imageLayer == nil) {
imageLayer = CALayer()
self.layer.addSublayer(imageLayer!)
}
if (border == nil) {
border = CAShapeLayer()
self.layer.addSublayer(border!)
}
次に、円形に切り抜いた画像のレイヤーを注意深く作成します。
// the ultimate size of our custom control:
let box = self.bounds.aspectFit()
let totalInsetOnAnyOneSide = trueBorderThickness + trueGapThickness
let boxInWhichImageSits = box.inset(by:
UIEdgeInsets(top: totalInsetOnAnyOneSide, left: totalInsetOnAnyOneSide,
bottom: totalInsetOnAnyOneSide, right: totalInsetOnAnyOneSide))
// just a note. that version of inset#by is much clearer than the
// confusing dx/dy variant, so best to use that one
imageLayer!.frame = boxInWhichImageSits
imageLayer!.contents = picture?.cgImage
imageLayer?.contentsGravity = .resizeAspectFill
let halfImageSize = boxInWhichImageSits.width / 2.0
let maskPath = UIBezierPath(roundedRect: imageLayer!.bounds,
cornerRadius:halfImageSize)
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
imageLayer!.mask = maskLayer
次に、完全に別のレイヤーとして、必要に応じて境界線を描画します。
// now create the border
border!.frame = bounds
// To draw the border, you must inset it by half the width of the border,
// otherwise you'll be drawing only half the border. (Indeed, as an additional
// subtle problem you are clipping rather than rendering the outside Edge.)
let halfWidth = trueBorderThickness / 2.0
let borderCenterlineBox = box.inset(by:
UIEdgeInsets(top: halfWidth, left: halfWidth,
bottom: halfWidth, right: halfWidth))
let halfBorderBoxSize = borderCenterlineBox.width / 2.0
let borderPath = UIBezierPath(roundedRect: borderCenterlineBox,
cornerRadius:halfBorderBoxSize)
border!.path = borderPath.cgPath
border!.fillColor = UIColor.clear.cgColor
border!.strokeColor = borderColor.cgColor
border!.lineWidth = trueBorderThickness
}
}
すべてがiOS標準コントロールのように完全に機能します。
見えないものはすべて見えない。カスタムコントロール全体を背後のマテリアルまで透視できます。「半分の厚さ」の問題や画像マテリアルの欠落はなく、カスタムコントロールの背景色を通常の方法で設定できます。インスペクターコントロールはすべて正しく機能します。 (ふhe!)
同様のソリューション:
https://stackoverflow.com/a/57465440/294884 -画像+丸め+影
https://stackoverflow.com/a/41553784/294884 -2つのコーナーの問題
https://stackoverflow.com/a/59092828/294884 -「シャドウ+ホール」または「グローボックス」の問題
https://stackoverflow.com/a/57400842/294884 -「境界線とギャップ」の問題
https://stackoverflow.com/a/57514286/294884 -基本的な「追加」ベジエ
確かにあります!すべてのビューにはlayer
プロパティがあります(レイヤーに角を丸くするとわかる)。 layer
のもう2つのプロパティは、borderColor
とborderWidth
です。それらを設定するだけで、ビューに境界線を追加できます! (境界は丸みを帯びた角に続きます。)UIColor.CGColor
for borderColor
as a plain UIColor
will not match the type。