วิธีการตั้งค่า cornerRadius สำหรับมุมบนซ้ายและมุมขวาบนของ UIView เท่านั้น


408

มีวิธีตั้งค่าcornerRadiusเฉพาะมุมบนซ้ายและมุมขวาบนของ a UIViewหรือไม่?

ฉันลองทำสิ่งต่อไปนี้ แต่ท้ายที่สุดก็ไม่เห็นวิวอีกต่อไป

UIView *view = [[UIView alloc] initWithFrame:frame];

CALayer *layer = [CALayer layer];
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:frame byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight) cornerRadii:CGSizeMake(3.0, 3.0)];
layer.shadowPath = shadowPath.CGPath;
view.layer.mask = layer;

9
หลังจากการแก้ไขของคุณสามสิ่งในการแก้ไขปัญหา (1) เส้นทางโค้งมนควรอยู่บนพื้นฐานview.boundsไม่frame(2) ชั้นควรจะเป็นCAShapeLayerไม่ได้CALayer; (3) การตั้งค่าของชั้นไม่path shadowPath
Kurt Revis

1
ซ้ำซ้อนของคำถาม & คำตอบนี้
Stuart

ใช้อัลกอริทึม Bezier curve เพื่อสร้างเส้นโค้งบน CGPath ฉันค่อนข้างแน่ใจว่ามันเป็นส่วนหนึ่งของ CoreGraphics ถ้าไม่en.wikipedia.org/wiki/Bézier_curveมีคำจำกัดความและภาพเคลื่อนไหวที่ยอดเยี่ยม
Nate Symer


ดูคำตอบของฉันที่นี่: stackoverflow.com/a/50396485/6246128
wcarhart

คำตอบ:


225

ให้ความสนใจกับข้อเท็จจริงที่ว่าถ้าคุณมีข้อ จำกัด ด้านโครงร่างติดอยู่คุณต้องรีเฟรชสิ่งนี้ดังต่อไปนี้ในคลาสย่อย UIView ของคุณ:

override func layoutSubviews() {
    super.layoutSubviews()
    roundCorners(corners: [.topLeft, .topRight], radius: 3.0)
}

หากคุณไม่ทำเช่นนั้นจะไม่ปรากฏขึ้น


และถึงมุมรอบใช้ส่วนขยาย:

extension UIView {
   func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        layer.mask = mask
    }
}

3
มันไม่ใช่คำตอบอย่างแน่นอนผู้เขียนถามว่าจะปัดเศษมุมเฉพาะอย่างไรไม่ใช่วิธีซิงโครไนซ์รัศมีมุมกับการเปลี่ยนแปลงโครงร่าง
kelin

1
นี่คือคำตอบที่ไม่สมเหตุสมผล
Tiago Couto

1
คำตอบได้รับการแก้ไขเร็ว ๆ นี้ .. @kelin
Michael

2
มุมนี้โค้งมนอย่างแน่นอน
aznelite89

คุณต้องทำสิ่งนี้หลังจากมุมมองที่ปรากฏ
โจนาธาน

535

ฉันไม่แน่ใจว่าทำไมทางออกของคุณไม่ทำงาน แต่รหัสต่อไปนี้ใช้งานได้สำหรับฉัน สร้างหน้ากาก bezier และนำไปใช้กับมุมมองของคุณ ในรหัสของฉันด้านล่างฉันได้ปัดมุมด้านล่างของ_backgroundViewรัศมีด้วย 3 พิกเซล selfเป็นประเพณีUITableViewCell:

UIBezierPath *maskPath = [UIBezierPath
    bezierPathWithRoundedRect:self.backgroundImageView.bounds
    byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight)
    cornerRadii:CGSizeMake(20, 20)
];

CAShapeLayer *maskLayer = [CAShapeLayer layer];

maskLayer.frame = self.bounds;
maskLayer.path = maskPath.CGPath;

self.backgroundImageView.layer.mask = maskLayer;

รุ่น Swift พร้อมการปรับปรุงบางอย่าง:

let path = UIBezierPath(roundedRect:viewToRound.bounds, byRoundingCorners:[.TopRight, .BottomLeft], cornerRadii: CGSizeMake(20, 20))
let maskLayer = CAShapeLayer()

maskLayer.path = path.CGPath
viewToRound.layer.mask = maskLayer

เวอร์ชั่น Swift 3.0:

let path = UIBezierPath(roundedRect:viewToRound.bounds,
                        byRoundingCorners:[.topRight, .bottomLeft],
                        cornerRadii: CGSize(width: 20, height:  20))

let maskLayer = CAShapeLayer()

maskLayer.path = path.cgPath
viewToRound.layer.mask = maskLayer

ส่วนขยายที่รวดเร็วที่นี่


2
ลองในฟิลด์ข้อความ ประสบความสำเร็จในด้านซ้ายความล้มเหลวทางด้านขวา
Rainer Liao

10
@RealLiao ฉันมีปัญหาเดียวกันฉันทำทุกอย่างตามviewDidLoadวิธีที่กำหนดและย้ายไปviewDidAppearใช้งานได้
Lucho

ฉันจะตั้งค่านี้ให้ทำงานกับอุปกรณ์ใด ๆ ได้อย่างไร ใช้งานได้ดีกับsimulatorขนาดสตอรี่บอร์ดเท่านั้น ex: if the simulator size is 6s it works fine for 6s, but not of others.ฉันจะเอาชนะสิ่งนี้ได้อย่างไร
Chanaka Caldera

1
ข้อผิดพลาดทางไวยากรณ์เล็กน้อยในรุ่น Swift 3: path.CGPathควรเป็นpath.cgPath
Rob

@RainerLiao หากคุณไม่ต้องการให้ปัดเมื่อมุมมองปรากฏขึ้นให้เปลี่ยนviewWillAppearเป็น ยังใช้งานได้
Matthew Knippen

263

นี่คือคำตอบ @JohnnyRockex รุ่นSwift

extension UIView {

    func roundCorners(_ corners: UIRectCorner, radius: CGFloat) {
         let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
         let mask = CAShapeLayer()
         mask.path = path.cgPath
         self.layer.mask = mask
    }

}

view.roundCorners([.topLeft, .bottomRight], radius: 10)

บันทึก

หากคุณใช้เลย์เอาต์อัตโนมัติคุณจะต้องซับคลาสของคุณUIViewและโทรroundCornersในมุมมองlayoutSubviewsเพื่อให้ได้ผลที่ดีที่สุด

class View: UIView {
    override func layoutSubviews() {
        super.layoutSubviews()

        self.roundCorners([.topLeft, .bottomLeft], radius: 10)
    }
}

12
นามสกุลที่ยอดเยี่ยม อย่างไรก็ตาม: .TopRightและ.BottomRightดูเหมือนจะไม่เหมาะกับฉัน
Onichan

4
ในSwift 2 :view.roundCorners([.TopLeft , .BottomLeft], radius: 10)
fahrulazmi

2
มันไม่ทำงานทางด้านขวาเนื่องจากขอบเขตมุมมองของคุณยังไม่ได้กำหนดไว้อย่างดีกับการชำระอัตโนมัติ ... ขณะนี้ฉันกำลังเผชิญกับปัญหาเดียวกัน
dosdos

3
@dosdos Subclass ที่ดูและใน layoutSubviews รอบมุมของตนเอง
Arbitur

10
หากคุณใช้เลย์เอาต์อัตโนมัติและไม่มีการอ้างอิงไปยังมุมมองที่ต้องการปัดเศษคุณสามารถโทร.layoutIfNeeded()แล้วใช้วิธีนี้
zgjie

209

และในที่สุด…มีCACornerMaskใน iOS11! ด้วยCACornerMaskสามารถทำได้ค่อนข้างง่าย:

let view = UIView()
view.clipsToBounds = true
view.layer.cornerRadius = 10
view.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] // Top right corner, Top left corner respectively

1
วิธีนี้ใช้ได้ผลดีที่สุด เรามักจะมีปัญหากับการแก้ปัญหาอื่น ๆ เมื่อการปัดเศษขอบของเซลล์มุมมองการปรับขนาดแบบไดนามิก
cornr

2
โปรเจ็กต์จะต้องรองรับ iOS 11 เป็นต้นไปเพื่อที่จะใช้โซลูชันนั้น
มนุษย์ต่างดาว

13
@ Aliens และ…ฉันพูดถึงว่า
Sergey Belous

1
คำตอบอื่น ๆ ไม่ทำงานเมื่อหมุนอุปกรณ์รหัสนี้ใช้สำหรับการหมุนและช่วยให้คุณปัดเศษบางมุมนี่ควรเป็นคำตอบที่ยอมรับได้
Cloud9999Strife

1
Simple is beautiful
eharo2

99

ตัวอย่างโค้ดที่รวดเร็วที่นี่: https://stackoverflow.com/a/35621736/308315


ไม่ได้โดยตรง คุณจะต้อง:

  1. สร้าง CAShapeLayer
  2. ตั้งค่าpathให้เป็นแบบCGPathRefอิงview.boundsแต่มีมุมโค้งมนเพียงสองมุมเท่านั้น (อาจใช้+[UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:])
  3. กำหนดview.layer.maskให้คุณเป็นCAShapeLayer

21
ถูกเตือนว่าจะส่งผลกระทบต่อประสิทธิภาพการทำงานหากคุณทำมากกว่าแค่สองมุมมอง ...
jjxtra

@jjxtra ดังนั้นวิธีที่ดีที่สุดในการทำโดยไม่สูญเสียประสิทธิภาพมากคืออะไร? ฉันต้องการแสดงใน UITableViewCell
xi.lin

@ xi.lin จากสิ่งที่ฉันจำได้ว่าการตั้งค่าlayer.shouldRasterize == YESเพิ่มความเร็ว 5 เท่าหรือมากกว่านั้น แต่เอกสารบอกว่ามันใช้งานได้เฉพาะเมื่อคุณทำงานกับเซลล์ที่ไม่โปร่งใส ลองยิงดู
codrut

64

นี่เป็นวิธีสั้น ๆ ที่นำมาใช้เช่นนี้:

- (void)viewDidLoad {
    [super viewDidLoad];
    UIButton *openInMaps = [UIButton new];
    [openInMaps setFrame:CGRectMake(15, 135, 114, 70)];
    openInMaps = (UIButton *)[self roundCornersOnView:openInMaps onTopLeft:NO topRight:NO bottomLeft:YES bottomRight:NO radius:5.0];
}

- (UIView *)roundCornersOnView:(UIView *)view onTopLeft:(BOOL)tl topRight:(BOOL)tr bottomLeft:(BOOL)bl bottomRight:(BOOL)br radius:(float)radius {

    if (tl || tr || bl || br) {
        UIRectCorner corner = 0;
        if (tl) {corner = corner | UIRectCornerTopLeft;}
        if (tr) {corner = corner | UIRectCornerTopRight;}
        if (bl) {corner = corner | UIRectCornerBottomLeft;}
        if (br) {corner = corner | UIRectCornerBottomRight;}

        UIView *roundedView = view;
        UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:roundedView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(radius, radius)];
        CAShapeLayer *maskLayer = [CAShapeLayer layer];
        maskLayer.frame = roundedView.bounds;
        maskLayer.path = maskPath.CGPath;
        roundedView.layer.mask = maskLayer;
        return roundedView;
    }
    return view;
}

แล้วการตั้งค่าสีล่ะ maskLayer.borderWidth = 10; maskLayer.borderColor = [UIColor redColor] .CGColor; มันไม่ทำงานสำหรับฉันครับ
kiran

1
@kiran a mask ไม่มีสีคุณสามารถเพิ่ม CAShapeLayer อันที่สองหากคุณต้องการมีเส้นขอบ
Johnny Rockex

25

ใน swift 4.1 และ Xcode 9.4.1

ในiOS 11บรรทัดเดียวนี้เพียงพอ:

detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]//Set your view here

ดูรหัสที่สมบูรณ์:

//In viewDidLoad
if #available(iOS 11.0, *){
        detailsSubView.clipsToBounds = false
        detailsSubView.layer.cornerRadius = 10
        detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
} else {
      //For lower versions
}

แต่สำหรับรุ่นที่ต่ำกว่า

let rectShape = CAShapeLayer()
    rectShape.bounds = detailsSubView.frame
    rectShape.position = detailsSubView.center
    rectShape.path = UIBezierPath(roundedRect: detailsSubView.bounds,    byRoundingCorners: [.topLeft , .topRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
    detailsSubView.layer.mask = rectShape

รหัสที่สมบูรณ์คือ

if #available(iOS 11.0, *){
    detailsSubView.clipsToBounds = false
    detailsSubView.layer.cornerRadius = 10
    detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
}else{
    let rectShape = CAShapeLayer()
    rectShape.bounds = detailsSubView.frame
    rectShape.position = detailsSubView.center
    rectShape.path = UIBezierPath(roundedRect: detailsSubView.bounds,    byRoundingCorners: [.topLeft , .topRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
    detailsSubView.layer.mask = rectShape
}

หากคุณกำลังใช้ AutoResizing ในกระดานเขียนโค้ดนี้ในviewDidLayoutSubviews ()

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if #available(iOS 11.0, *){
        detailsSubView.clipsToBounds = false
        detailsSubView.layer.cornerRadius = 10
        detailsSubView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
    }else{
        let rectShape = CAShapeLayer()
        rectShape.bounds = detailsSubView.frame
        rectShape.position = detailsSubView.center
        rectShape.path = UIBezierPath(roundedRect: detailsSubView.bounds,    byRoundingCorners: [.topLeft , .topRight], cornerRadii: CGSize(width: 20, height: 20)).cgPath
        detailsSubView.layer.mask = rectShape
    }
}

1
มันใช้งานไม่ได้กับ iOS 9 แต่ใช้งานได้ตั้งแต่วันที่ 11
Ali Ihsan URAL

วิธีแก้ปัญหาสำหรับ iOS 9 หรือไม่?
jey

@jay ให้ rectShape = CAShapeLayer () rectShape.bounds = detailsSubView.frame rectShape.position = detailsSubView.center rectShape.path = UIBezierPath (roundRect: detailsSubView.bounds โดยรอบการจัดมุม: [.topLeft, .topRight] 20, ความสูง: 20)). cgPath detailsSubView.layer.mask = rectShape รหัสนี้สามารถใช้งานได้กับ iOS 9
iOS

@jay ตรวจสอบว่าไม่แจ้งฉัน
iOS

ไม่ทำงานกับ iOS 9 ไม่มีขอบที่มุม
jey

24

iOS 11, Swift 4
และคุณสามารถลองใช้รหัสนี้:

if #available(iOS 11.0, *) {
   element.clipsToBounds = true
   element.layer.cornerRadius = CORNER_RADIUS
   element.layer.maskedCorners = [.layerMaxXMaxYCorner]
} else {
   // Fallback on earlier versions
}

และคุณสามารถใช้สิ่งนี้ในเซลล์มุมมองตาราง


1
นั่นเป็นคำตอบที่ถูกต้องสำหรับการเข้ารหัสของวันนี้ ลาก่อนลาเพื่อปกปิดเลเยอร์
Alen Liang

1
นี่จะเป็นคำตอบที่ดีที่สุด!
fujianjin6471

18

นี่จะเป็นคำตอบที่ง่ายที่สุด:

yourView.layer.cornerRadius = 8
yourView.layer.masksToBounds = true
yourView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]

แท็กที่เป็นโซลูชันสำหรับ iOS 11 ขึ้นไป
Ankur Lahiry

16

ลองรหัสนี้

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:( UIRectCornerTopLeft | UIRectCornerTopRight) cornerRadii:CGSizeMake(5.0, 5.0)];

CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.view.bounds;
maskLayer.path  = maskPath.CGPath;

view.layer.mask = maskLayer;

15

เอ็มม่า: .TopRightและ.BottomRightไม่ได้ผลสำหรับคุณบางทีอาจเป็นเพราะการเรียกร้องให้view.roundCornersทำก่อนที่จะview boundsมีการคำนวณขั้นสุดท้าย โปรดทราบว่าBezier Pathมาจากขอบเขตการดูในเวลาที่เรียกว่า ตัวอย่างเช่นหากเลย์เอาต์อัตโนมัติจะ จำกัด มุมมองให้มุมมนด้านขวาอาจอยู่นอกมุมมอง ลองโทรเข้าviewDidLayoutSubviewsที่ที่ขอบเขตของมุมมองเป็นที่สิ้นสุด


ขอบคุณ. สำหรับฉันสิ่งที่แก้ไขปัญหาได้คือการย้ายการเรียกไปสู่การใช้งานที่กำหนดโดย "Arbitur" จาก viewDidLoad และ viewWillAppear เป็น viewDidAppear ฉันสามารถทำได้เนื่องจากการควบคุมของฉันถูกตั้งค่าเป็นซ่อน
Matti

คุณพูดถูก มันจะสร้างปัญหากับการชำระอัตโนมัติและคุณทำได้ดีมาก
Ashish Kakkad

15

Swift 4 Swift 5วิธีง่ายๆใน 1 บรรทัด

การใช้งาน:

//MARK:- Corner Radius of only two side of UIViews
self.roundCorners(view: yourview, corners: [.bottomLeft, .topRight], radius: 12.0)

ฟังก์ชั่น:

//MARK:- Corner Radius of only two side of UIViews
func roundCorners(view :UIView, corners: UIRectCorner, radius: CGFloat){
        let path = UIBezierPath(roundedRect: view.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        view.layer.mask = mask
}

ในวัตถุประสงค์ -C

การใช้งาน:

[self.verticalSeparatorView roundCorners:UIRectCornerTopLeft radius:10.0];

ฟังก์ชั่นที่ใช้ในหมวดหมู่ (มุมเดียวเท่านั้น):

-(void)roundCorners: (UIRectCorner) corners radius:(CGFloat)radius {
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];
        CAShapeLayer *mask = [[CAShapeLayer alloc] init];
        mask.path = path.CGPath;
        self.layer.mask = mask;
    }

โปรดจำไว้ว่ามุมของมุมมองของคุณจะไม่ถูกคำนวณจนกว่า viewDidLayoutSubviews เสร็จแล้วดังนั้นคุณควรเรียก roundCorners func ข้างใน
Jirson Tavera

คุณสามารถบอกได้อย่างไรว่าฉันจะเพิ่มเงาให้กับมุมมองนี้ได้อย่างไร
Vadlapalli Masthan

@ShakeelAhmed นี้จะไม่ทำงานหากคุณต้องการเพิ่มเงาให้กับมุมมอง
mojtaba al moussawi

ก่อนเพิ่มรัศมีมุมแล้วเพิ่มเงา
Shakeel Ahmed

10

โซลูชันของฉันสำหรับการปัดเศษมุมเฉพาะของ UIView และ UITextFiels อย่างรวดเร็วคือการใช้งาน

.layer.cornerRadius

และ

layer.maskedCorners

ของ UIView จริงหรือ UITextFields

ตัวอย่าง:

fileprivate func inputTextFieldStyle() {
        inputTextField.layer.masksToBounds = true
        inputTextField.layer.borderWidth = 1
        inputTextField.layer.cornerRadius = 25
        inputTextField.layer.maskedCorners = [.layerMaxXMaxYCorner,.layerMaxXMinYCorner]
        inputTextField.layer.borderColor = UIColor.white.cgColor
    }

และโดยการใช้

.layerMaxXMaxYCorner

และ

.layerMaxXMinYCorner

ฉันสามารถระบุมุมขวาบนและล่างขวาของ UITextField ที่จะปัดเศษ

คุณสามารถดูผลลัพธ์ได้ที่นี่:

ป้อนคำอธิบายรูปภาพที่นี่


สมบูรณ์แบบสำหรับการรวมขอบและมุมที่เฉพาะเจาะจง🎉🎉🎉
Nomnom

8

สวิฟต์ 4

extension UIView {

    func roundTop(radius:CGFloat = 5){
        self.clipsToBounds = true
        self.layer.cornerRadius = radius
        if #available(iOS 11.0, *) {
            self.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
        } else {
            // Fallback on earlier versions
        }
    }

    func roundBottom(radius:CGFloat = 5){
        self.clipsToBounds = true
        self.layer.cornerRadius = radius
        if #available(iOS 11.0, *) {
            self.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner]
        } else {
            // Fallback on earlier versions
        }
    }
}

คุณบันทึกวันของฉันในกรณีของฉันฉันต้องทำให้มุมมองตารางถูกปัดเศษสำหรับเซลล์เฉพาะ
Shakti

ans ที่สมบูรณ์แบบตามความต้องการของฉัน ฉันใช้คำตอบทั้งหมดไม่มีอะไรทำงานได้ แต่คำตอบของคุณช่วยฉันและแก้ไขปัญหาของฉัน
Nikita Patil

6

วิธีในการทำโปรแกรมนี้คือการสร้างUIViewส่วนบนของส่วนUIViewที่มีมุมโค้งมน หรือคุณอาจซ่อนส่วนบนไว้ใต้บางสิ่ง


6
วิธีแก้ปัญหาที่น่าเกลียดมาก: P
Arbitur

6
    // Create the path (with only the top-left corner rounded)
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds 
                           byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) 
                           cornerRadii:CGSizeMake(7.0, 7.0)];

// Create the shape layer and set its path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = cell.stripBlackImnageView.bounds;
maskLayer.path = maskPath.CGPath; 
// Set the newly created shapelayer as the mask for the image view's layer
view.layer.mask = maskLayer;

4

วิธีที่ง่ายที่สุดคือการสร้างมาสก์ที่มีเลเยอร์มุมโค้งมน

CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0,0,maskWidth ,maskHeight);
maskLayer.contents = (__bridge id)[[UIImage imageNamed:@"maskImageWithRoundedCorners.png"] CGImage];

aUIView.layer.mask = maskLayer;

และอย่าลืม:

#import <QuartzCore/QuartzCore.h>

4

คำตอบทั้งหมดที่ได้รับนั้นดีและใช้ได้จริง ๆ (โดยเฉพาะความคิดของ Yunus ในการใช้ maskทรัพย์สิน)

อย่างไรก็ตามฉันต้องการบางสิ่งที่ซับซ้อนกว่านี้เล็กน้อยเพราะเลเยอร์ของฉันสามารถเปลี่ยนขนาดได้บ่อยซึ่งหมายความว่าฉันต้องเรียกตรรกะการปิดบังนั้นทุกครั้งและมันก็น่ารำคาญนิดหน่อย

ฉันใช้extensionsคุณสมบัติที่คำนวณได้อย่างรวดเร็วเพื่อสร้างของจริงcornerRadiiอสังหาริมทรัพย์ซึ่งดูแลการอัพเดตหน้ากากอัตโนมัติเมื่อเลเยอร์เลเยอร์

นี่คือความสำเร็จโดยใช้มุมมองที่ยอดเยี่ยมของPeter Steinbergห้องสมุดร้อนแรง

รหัสเต็มอยู่ที่นี่:

extension CALayer {
  // This will hold the keys for the runtime property associations
  private struct AssociationKey {
    static var CornerRect:Int8 = 1    // for the UIRectCorner argument
    static var CornerRadius:Int8 = 2  // for the radius argument
  }

  // new computed property on CALayer
  // You send the corners you want to round (ex. [.TopLeft, .BottomLeft])
  // and the radius at which you want the corners to be round
  var cornerRadii:(corners: UIRectCorner, radius:CGFloat) {
    get {
      let number = objc_getAssociatedObject(self, &AssociationKey.CornerRect)  as? NSNumber ?? 0
      let radius = objc_getAssociatedObject(self, &AssociationKey.CornerRadius)  as? NSNumber ?? 0
      return (corners: UIRectCorner(rawValue: number.unsignedLongValue), radius: CGFloat(radius.floatValue))
    }
    set (v) {
      let radius = v.radius
      let closure:((Void)->Void) = {
        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: v.corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.CGPath
        self.mask = mask
      }
      let block: @convention(block) Void -> Void = closure
      let objectBlock = unsafeBitCast(block, AnyObject.self)
      objc_setAssociatedObject(self, &AssociationKey.CornerRect, NSNumber(unsignedLong: v.corners.rawValue), .OBJC_ASSOCIATION_RETAIN)
      objc_setAssociatedObject(self, &AssociationKey.CornerRadius, NSNumber(float: Float(v.radius)), .OBJC_ASSOCIATION_RETAIN)
      do { try aspect_hookSelector("layoutSublayers", withOptions: .PositionAfter, usingBlock: objectBlock) }
      catch _ { }
    }
  }
}

ฉันเขียนโพสต์บล็อกง่ายๆอธิบายเรื่องนี้



2

นี่คือวิธีที่คุณสามารถตั้งค่ารัศมีมุมสำหรับแต่ละมุมของปุ่มด้วยXamarin ใน C # :

var maskPath = UIBezierPath.FromRoundedRect(MyButton.Bounds, UIRectCorner.BottomLeft | UIRectCorner.BottomRight,
    new CGSize(10.0, 10.0));
var maskLayer = new CAShapeLayer
{
    Frame = MyButton.Bounds,
    Path = maskPath.CGPath
};
MyButton.Layer.Mask = maskLayer;

2

ส่วนขยายที่น่ารักเพื่อนำโซลูชัน Yunus Nedim Mehel กลับมาใช้ใหม่

สวิฟท์ 2.3

extension UIView {
func roundCornersWithLayerMask(cornerRadii: CGFloat, corners: UIRectCorner) {
    let path = UIBezierPath(roundedRect: bounds,
                            byRoundingCorners: corners,
                            cornerRadii: CGSize(width: cornerRadii, height: cornerRadii))
    let maskLayer = CAShapeLayer()
    maskLayer.path = path.CGPath
    layer.mask = maskLayer
} }

การใช้

let view = UIView()
view.roundCornersWithLayerMask(10,[.TopLeft,.TopRight])

วิธีทำความสะอาดที่ดี
Aggressor

1

หลังจากเปลี่ยนรหัสบิตของ @apinho อย่างรวดเร็ว 4.3 ทำงานได้ดี

extension UIView {
func roundCornersWithLayerMask(cornerRadii: CGFloat, corners: UIRectCorner) {
    let path = UIBezierPath(roundedRect: bounds,
                            byRoundingCorners: corners,
                            cornerRadii: CGSize(width: cornerRadii, height: cornerRadii))
    let maskLayer = CAShapeLayer()
    maskLayer.path = path.cgPath
    layer.mask = maskLayer
  }
}

ในการใช้ฟังก์ชั่นนี้ให้คุณดู

YourViewName. roundCornersWithLayerMask(cornerRadii: 20,corners: [.topLeft,.topRight])

0

คำตอบของStephaneรุ่นอื่น

import UIKit

    class RoundCornerView: UIView {
    var corners : UIRectCorner = [.topLeft,.topRight,.bottomLeft,.bottomRight]
        var roundCornerRadius : CGFloat = 0.0
        override func layoutSubviews() {
            super.layoutSubviews()
            if corners.rawValue > 0 && roundCornerRadius > 0.0 {
                self.roundCorners(corners: corners, radius: roundCornerRadius)
            }
        }
        private func roundCorners(corners: UIRectCorner, radius: CGFloat) {
            let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            layer.mask = mask
        }

    }

0

ใน Swift 4.2 สร้างมันผ่าน@IBDesignableสิ่งนี้:

@IBDesignable

class DesignableViewCustomCorner: UIView {

    @IBInspectable var cornerRadious: CGFloat = 0 {
        didSet {
            let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: cornerRadious, height: cornerRadious))
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            self.layer.mask = mask
        }
    }

}

0

ส่วนขยายที่เรียบง่าย

extension UIView {
    func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        if #available(iOS 11, *) {
            self.clipsToBounds = true
            self.layer.cornerRadius = radius
            var masked = CACornerMask()
            if corners.contains(.topLeft) { masked.insert(.layerMinXMinYCorner) }
            if corners.contains(.topRight) { masked.insert(.layerMaxXMinYCorner) }
            if corners.contains(.bottomLeft) { masked.insert(.layerMinXMaxYCorner) }
            if corners.contains(.bottomRight) { masked.insert(.layerMaxXMaxYCorner) }
            self.layer.maskedCorners = masked
        }
        else {
            let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
            let mask = CAShapeLayer()
            mask.path = path.cgPath
            layer.mask = mask
        }
    }
}

การใช้งาน:

view.roundCorners(corners: [.bottomLeft, .bottomRight], radius: 12)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.