Thêm góc tròn và bóng đổ vào UICollectionViewCell


104

Vì vậy, tôi đã xem qua các bài viết khác nhau về cách thêm chế độ xem thứ 2 để thêm bóng, nhưng tôi vẫn không thể làm cho nó hoạt động nếu tôi muốn thêm nó vào UICollectionViewCell. Tôi đã phân lớp UICollectionViewCellvà đây là mã của tôi, nơi tôi thêm các phần tử giao diện người dùng khác nhau vào chế độ xem nội dung của ô và thêm bóng vào lớp:

[self.contentView setBackgroundColor:[UIColor whiteColor]];

self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(0, 1);
self.layer.shadowRadius = 1.0;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 0.5;
[self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.bounds] CGPath]];

Tôi muốn biết cách thêm góc tròn và bóng đổ vào UICollectionViewCell.


Tôi nghĩ bạn cần cải thiện câu hỏi của mình để người khác hiểu. Nó thực sự lộn xộn những gì u đã hỏi
Dinesh Raja

ok cập nhật, tôi chỉ muốn biết làm thế nào để thêm góc tròn và bóng tối để UICollectionViewCell
Vincent Yiu

Bỏ qua một bên - sử dụng shadowRadius HOẶC setShadowPath, không ích lợi gì khi làm cả hai vì chúng về cơ bản là cùng một hướng dẫn trong ngữ cảnh này (tất cả các góc được làm tròn). Đường đổ bóng là cần thiết khi bạn muốn các hình dạng phức tạp hơn hoặc các góc tròn không được áp dụng cho tất cả các góc.
Oliver Dungey

Câu trả lời:


194

Cả hai giải pháp này đều không hiệu quả với tôi. Nếu bạn đặt tất cả các chế độ xem phụ của mình vào chế độ xem nội dung UICollectionViewCell, bạn có thể đặt bóng trên lớp của ô và đường viền trên lớp của contentView để đạt được cả hai kết quả.

cell.contentView.layer.cornerRadius = 2.0f;
cell.contentView.layer.borderWidth = 1.0f;
cell.contentView.layer.borderColor = [UIColor clearColor].CGColor;
cell.contentView.layer.masksToBounds = YES;

cell.layer.shadowColor = [UIColor blackColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0f);
cell.layer.shadowRadius = 2.0f;
cell.layer.shadowOpacity = 0.5f;
cell.layer.masksToBounds = NO;
cell.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:cell.contentView.layer.cornerRadius].CGPath;

Swift 3.0

self.contentView.layer.cornerRadius = 2.0
self.contentView.layer.borderWidth = 1.0
self.contentView.layer.borderColor = UIColor.clear.cgColor
self.contentView.layer.masksToBounds = true

self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 2.0)
self.layer.shadowRadius = 2.0
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.contentView.layer.cornerRadius).cgPath

9
Điều này hoạt động tốt cho tôi sau khi tôi thêmcell.layer.backgroundColor = [UIColor clearColor].CGColor;
nacross

2
Bất kỳ ý tưởng tại sao điều này chỉ làm tròn các góc trên cùng của tôi?
user3344977

@ user3344977 có lẽ phần dưới bị cắt bớt? Như ở các góc được làm tròn, nhưng nó nằm bên dưới phần có thể nhìn thấy của ô
CoderNinja

5
Tôi thấy rằng điều này làm tròn các góc trên cùng của tôi chứ không phải các góc dưới cùng của tôi.
fatuhoku

2
Làm cách nào để các góc luôn tròn khi bạn chọn / bỏ chọn / di chuyển các ô? Các góc của tôi sẽ vuông bất cứ lúc nào tôi thở vào ô sau khi nó vẽ đúng ban đầu.
Adrian

32

Phiên bản Swift 3:

cell.contentView.layer.cornerRadius = 10
cell.contentView.layer.borderWidth = 1.0

cell.contentView.layer.borderColor = UIColor.clear.cgColor
cell.contentView.layer.masksToBounds = true

cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 2.0
cell.layer.shadowOpacity = 1.0
cell.layer.masksToBounds = false
cell.layer.shadowPath = UIBezierPath(roundedRect:cell.bounds, cornerRadius:cell.contentView.layer.cornerRadius).cgPath

Tôi cần phải thêm một hiệu ứng đổ bóng vào góc phải và dưới cùng của mỗi tế bào, và cách mà các mã trên tác phẩm, nó lấp đầy các tế bào với một màu trong bóng tối ...
Joe Sene

25

Trong trường hợp nó hữu ích: Đây là cách nhanh chóng để làm tròn các góc:

cell.layer.cornerRadius = 10
cell.layer.masksToBounds = true

với ô là một biến kiểm soát ô: thông thường, bạn sẽ sử dụng điều này trong override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Thưởng thức!


18

Đây là giải pháp Swift 4 , được cập nhật để làm tròn mọi góc và không chỉ các góc trên cùng:

contentView.layer.cornerRadius = 6.0
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true

layer.shadowColor = UIColor.lightGray.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2.0)
layer.shadowRadius = 6.0
layer.shadowOpacity = 1.0
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath
layer.backgroundColor = UIColor.clear.cgColor

1
Hoạt động nhanh chóng 4,2 cũng vậy, cảm ơn
ShadeToD

2
Tôi đang tìm kiếm một giải pháp ... nhờ trẻ Massimo: 'D
Massimo Polimeni

16

Đặt layerthuộc tính cho ô, không phải contentView.

CALayer * layer = [cell layer];
[layer setShadowOffset:CGSizeMake(0, 2)];
[layer setShadowRadius:1.0];
[layer setShadowColor:[UIColor redColor].CGColor] ;
[layer setShadowOpacity:0.5]; 
[layer setShadowPath:[[UIBezierPath bezierPathWithRect:cell.bounds] CGPath]];

2
Điều này dường như không hiệu quả với tôi. Tôi sử dụng mã tương tự cho một uitableviewcell nhưng nó dường như không hoạt động trong một collectionviewcell. Thật kỳ lạ khi cùng một mã sẽ không hoạt động trong ô cv.
Jason

Một bản cập nhật cho nhận xét ở trên của tôi. Tôi nhận thấy rằng UICollectionViewCells dường như sử dụng độ lệch bóng khác với UITableViewCells. Nếu bạn không nhìn thấy bóng, hãy thử thay đổi độ lệch (tôi đã tăng giá trị Y).
Jason

14

SWIFT 4.2

Người ta nên thêm điều này vào ô tùy chỉnh của bạn hoặc ôForItemAt: Nếu bạn đang sử dụng cellForItemAt: tiếp cận thay thế tự -> ô

        self.layer.cornerRadius = 10
        self.layer.borderWidth = 1.0
        self.layer.borderColor = UIColor.lightGray.cgColor

        self.layer.backgroundColor = UIColor.white.cgColor
        self.layer.shadowColor = UIColor.gray.cgColor
        self.layer.shadowOffset = CGSize(width: 2.0, height: 4.0)
        self.layer.shadowRadius = 2.0
        self.layer.shadowOpacity = 1.0
        self.layer.masksToBounds = false

Điều này sẽ cung cấp cho bạn một ô có đường viền tròn và bóng đổ.


13

Đây là câu trả lời của tôi, gần giống với những cái khác, nhưng tôi thêm bán kính góc vào lớp nếu không các góc sẽ không được điền chính xác. Ngoài ra, điều này làm cho một phần mở rộng nhỏ tốt đẹp trên UICollectionViewCell.

extension UICollectionViewCell {
func shadowDecorate() {
    let radius: CGFloat = 10
    contentView.layer.cornerRadius = radius
    contentView.layer.borderWidth = 1
    contentView.layer.borderColor = UIColor.clear.cgColor
    contentView.layer.masksToBounds = true

    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0, height: 1.0)
    layer.shadowRadius = 2.0
    layer.shadowOpacity = 0.5
    layer.masksToBounds = false
    layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
    layer.cornerRadius = radius
}

}

Bạn có thể gọi nó trong collectionView(_:cellForItemAt:)nguồn dữ liệu sau khi bạn xếp hàng lại ô của mình.


8

Bạn chỉ cần đặt (a) cornerRadiusvà (b) đặt thành shadowPathmột hình chữ nhật tròn với cùng bán kính như cornerRadiussau:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];

2
Bất kỳ ý tưởng tại sao điều này chỉ làm tròn các góc dưới cùng của tôi?
user3344977

Có vẻ như bất kỳ lớp nào bạn đang làm tròn đều bị che khuất một phần bởi thứ gì đó. Không thể đi xa hơn thế mà không có chi tiết.
Timothy Moose

Này Tim, tôi vừa hỏi câu này. Tôi có cảm giác bạn sẽ có thể lấy nó nhanh chóng. Có phải vì tôi chỉ có bóng ở phía dưới / "bên dưới" ô? stackoverflow.com/q/27929735/3344977
dùng3344977

6

Tôi đã phải thực hiện một số thay đổi nhỏ cho Swift :

cell.contentView.layer.cornerRadius = 2.0;
cell.contentView.layer.borderWidth = 1.0;
cell.contentView.layer.borderColor = UIColor.clearColor().CGColor;
cell.contentView.layer.masksToBounds = true;

cell.layer.shadowColor = UIColor.grayColor().CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0);
cell.layer.shadowRadius = 2.0;
cell.layer.shadowOpacity = 1.0;
cell.layer.masksToBounds = false;
cell.layer.shadowPath = UIBezierPath(roundedRect:cell.bounds, cornerRadius:cell.contentView.layer.cornerRadius).CGPath;

3

Câu trả lời của Mike Sabatini hoạt động tốt, nếu bạn định cấu hình các thuộc tính ô trực tiếp trên collectionView cellForItemAt, nhưng nếu bạn cố gắng đặt chúng trong awfromNib () của lớp con UICollectionViewCell tùy chỉnh, bạn sẽ kết thúc với một bộ bezierPath sai trên các thiết bị không 'không khớp với chiều rộng và chiều cao đã đặt trước đó trong Bảng phân cảnh (IB) của bạn.

Giải pháp cho tôi là tạo một func bên trong lớp con của UICollectionViewCell và gọi nó từ cellForItemAt như sau:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as? CustomCollectionViewCell{
        cell.configure())
        return cell
    }
    else {
        return UICollectionViewCell()
    }
}

Và trên CustomCollectionViewCell.swift:

class CustomCollectionViewCell: UICollectionViewCell{
    func configure() {
    contentView.layer.cornerRadius = 20
    contentView.layer.borderWidth = 1.0
    contentView.layer.borderColor = UIColor.clear.cgColor
    contentView.layer.masksToBounds = true
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0, height: 2.0)
    layer.shadowRadius = 2.0
    layer.shadowOpacity = 0.5
    layer.masksToBounds = false
    layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath}
 }

3

Cái này làm việc cho tôi

cell.contentView.layer.cornerRadius = 5.0
cell.contentView.layer.borderColor = UIColor.gray.withAlphaComponent(0.5).cgColor
cell.contentView.layer.borderWidth = 0.5

let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: cell.contentView.frame.size.height - width, width:  cell.contentView.frame.size.width, height: cell.contentView.frame.size.height)

border.borderWidth = width
cell.contentView.layer.addSublayer(border)
cell.contentView.layer.masksToBounds = true
cell.contentView.clipsToBounds = true

3

Tôi sử dụng phương pháp sau để thực hiện loại hiệu ứng này:

extension UICollectionViewCell {
    /// Call this method from `prepareForReuse`, because the cell needs to be already rendered (and have a size) in order for this to work
    func shadowDecorate(radius: CGFloat = 8,
                        shadowColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3),
                        shadowOffset: CGSize = CGSize(width: 0, height: 1.0),
                        shadowRadius: CGFloat = 3,
                        shadowOpacity: Float = 1) {
        contentView.layer.cornerRadius = radius
        contentView.layer.borderWidth = 1
        contentView.layer.borderColor = UIColor.clear.cgColor
        contentView.layer.masksToBounds = true

        layer.shadowColor = shadowColor.cgColor
        layer.shadowOffset = shadowOffset
        layer.shadowRadius = shadowRadius
        layer.shadowOpacity = shadowOpacity
        layer.masksToBounds = false
        layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
        layer.cornerRadius = radius
    }
}

2

Bạn có thể đặt màu bóng, bán kính và độ lệch trong phương thức UICollectionViewDataSource trong khi tạo UICollectionViewCell

cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 1.0
cell.layer.shadowOpacity = 0.5
cell.layer.masksToBounds = false

2

Đây là giải pháp của tôi. Nó tương tự như các câu trả lời khác, với một điểm khác biệt chính. Nó không tạo ra một đường dẫn phụ thuộc vào các giới hạn của chế độ xem. Bất cứ khi nào bạn tạo một đường dẫn dựa trên các giới hạn và cung cấp nó cho lớp, bạn có thể gặp sự cố khi nó thay đổi kích thước và cần thiết lập các phương pháp để cập nhật đường dẫn.

Một giải pháp đơn giản hơn là tránh sử dụng bất kỳ thứ gì phụ thuộc vào giới hạn.

let radius: CGFloat = 10

self.contentView.layer.cornerRadius = radius
// Always mask the inside view
self.contentView.layer.masksToBounds = true

self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 1.0)
self.layer.shadowRadius = 3.0
self.layer.shadowOpacity = 0.5
// Never mask the shadow as it falls outside the view
self.layer.masksToBounds = false

// Matching the contentView radius here will keep the shadow
// in sync with the contentView's rounded shape
self.layer.cornerRadius = radius

Bây giờ khi kích thước ô thay đổi, API chế độ xem sẽ thực hiện tất cả công việc trong nội bộ.


Câu trả lời rõ ràng nhất theo ý kiến ​​của tôi. Yêu thích ý tưởng giữ cho các bức xạ được đồng bộ.
Kirill Kudaev

2

Tôi nhận thấy một điều quan trọng: UICollectionViewCell phải có backgroundColor là clearmàu để làm cho những điều trên hoạt động.


Điều này RẤT quan trọng để đạt được không cắt bỏ bóng! Đừng bỏ qua câu trả lời này, cảm ơn RẤT NHIỀU, anh bạn!
DennyDog
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.