Menambahkan sudut membulat dan bayangan jatuh ke UICollectionViewCell

104

Jadi saya sudah melalui berbagai posting tentang menambahkan tampilan ke-2 untuk menambahkan bayangan, tetapi saya masih tidak bisa membuatnya berfungsi jika saya ingin menambahkannya UICollectionViewCell. Saya membuat subkelas UICollectionViewCell, dan inilah kode saya di mana saya menambahkan berbagai elemen UI ke tampilan konten sel dan menambahkan bayangan ke lapisan:

[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]];

Saya ingin tahu bagaimana cara menambahkan sudut bulat dan bayangan UICollectionViewCell.

Vincent Yiu
sumber
Saya pikir Anda perlu meningkatkan pertanyaan Anda untuk dipahami oleh orang lain. Benar-benar kacau apa yang Anda minta
Dinesh Raja
ok diperbarui, saya hanya ingin tahu cara menambahkan sudut bulat dan bayangan ke UICollectionViewCell
Vincent Yiu
Sedikit ke samping - gunakan shadowRadius ATAU setShadowPath, tidak ada gunanya melakukan keduanya karena mereka pada dasarnya adalah instruksi yang sama dalam konteks ini (semua sudut membulat). Shadowpath diperlukan jika Anda ingin bentuk yang lebih kompleks atau sudut membulat tidak diterapkan ke semua sudut.
Oliver Dungey

Jawaban:

194

Tak satu pun dari solusi ini berhasil untuk saya. Jika Anda menempatkan semua subview Anda ke dalam tampilan konten UICollectionViewCell, yang mungkin memang Anda lakukan, Anda dapat menyetel bayangan pada lapisan sel dan batas pada lapisan contentView untuk mencapai kedua hasil.

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.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
Mike Sabatini
sumber
9
Ini bekerja dengan baik untuk saya setelah saya menambahkancell.layer.backgroundColor = [UIColor clearColor].CGColor;
nacross
2
Ada ide mengapa ini hanya membulatkan sudut atas saya?
pengguna3344977
@ user3344977 mungkin bagian bawahnya sedang dipotong? Seperti di sudut-sudut yang membulat, tetapi di bawah bagian yang terlihat dari sel
CoderNinja
5
Saya menemukan bahwa ini membulatkan sudut atas saya dan bukan sudut bawah saya juga.
fatuhoku
2
Bagaimana Anda mendapatkan sudut tetap bulat saat Anda memilih / membatalkan pilihan / memindahkan sel? Sudut saya menjadi persegi setiap kali saya menghirup sel setelah awalnya menggambar dengan benar.
Adrian
32

Versi 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
Torre Lasley
sumber
Saya perlu menambahkan efek bayangan ke sudut kanan dan bawah setiap sel, dan cara kerja kode di atas, itu mengisi sel dengan warna bayangan ...
Joe Sene
25

Jika ini membantu: Berikut kecepatan untuk membulatkan sudut:

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

dengan sel menjadi variabel yang mengontrol sel: sering kali, Anda akan menggunakan ini di override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Nikmati!

roket101
sumber
18

Berikut solusi Swift 4 , diperbarui ke setiap sudut dan tidak hanya sudut atas:

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
Massimo Polimeni
sumber
1
Bekerja di 4,2 cepat juga, thanls
ShadeToD
2
Saya sedang mencari solusi ... terima kasih Massimo yang lebih muda: 'D
Massimo Polimeni
16

Tetapkan layeratribut untuk sel, bukan 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]];
inzonemobileDev
sumber
2
Ini sepertinya tidak berhasil untuk saya. Saya menggunakan kode serupa untuk uitableviewcell tetapi tampaknya tidak berfungsi di collectionviewcell. Aneh bagaimana kode yang sama tidak bekerja di sel cv.
Jason
Pembaruan untuk komentar saya di atas. Saya menemukan bahwa UICollectionViewCells tampaknya menggunakan offset bayangan yang berbeda dari UITableViewCells. Jika Anda tidak melihat bayangan, coba ubah offsetnya (meningkatkan nilai Y membantu saya).
Jason
14

SWIFT 4.2

Seseorang harus menambahkan ini di sel kustom Anda atau cellForItemAt: Jika Anda menggunakan cellForItemAt: pendekatan substitusi self -> sel

        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

Ini akan memberi Anda sel dengan tepi bulat dan bayangan jatuh.

Alexander
sumber
13

Inilah jawaban saya, mendekati yang lain, tetapi saya menambahkan radius sudut ke lapisan jika tidak sudut tidak akan terisi dengan benar. Juga, ini membuat ekstensi kecil yang bagus 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
}

}

Anda dapat memanggilnya dalam collectionView(_:cellForItemAt:)sumber data setelah Anda membatalkan antrean sel Anda.

smileBot
sumber
8

Anda hanya perlu (a) set cornerRadiusdan (b) set shadowPathmenjadi persegi bulat dengan radius yang sama seperti cornerRadius:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];
Timothy Moose
sumber
2
Tahu mengapa ini hanya membulatkan sudut bawah saya?
pengguna3344977
Kedengarannya seperti lapisan apa pun yang Anda bulatkan sebagian tertutup oleh sesuatu. Tidak bisa melangkah lebih jauh dari itu tanpa detail.
Timothy Moose
Hai Tim, saya baru saja menanyakan pertanyaan ini. Saya rasa Anda akan bisa mendapatkannya dengan cepat. Apakah karena saya hanya memiliki bayangan di bagian bawah / "di bawah" sel? stackoverflow.com/q/27929735/3344977
user3344977
6

Saya harus membuat sedikit perubahan untuk 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;
Keith Holliday
sumber
4

Jawaban dari Mike Sabatini berfungsi dengan baik, jika Anda mengonfigurasi properti sel secara langsung di collectionView cellForItemAt, tetapi jika Anda mencoba menyetelnya di awakeFromNib () subkelas UICollectionViewCell kustom, Anda akan diakhiri dengan set bezierPath yang salah pada perangkat yang tidak tidak cocok dengan lebar dan tinggi yang ditetapkan sebelumnya di Storyboard (IB) Anda.

Solusi bagi saya adalah membuat func di dalam subclass UICollectionViewCell dan memanggilnya dari cellForItemAt seperti ini:

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()
    }
}

Dan di 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}
 }
frantenerelli.dll
sumber
3

Yang ini berhasil untuk saya

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
Tom Derry Marion Mantilla
sumber
3

Saya menggunakan metode berikut untuk mencapai efek semacam ini:

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
    }
}
marcelosalloum.dll
sumber
2

Anda dapat menyetel warna bayangan, radius, dan offset dalam metode UICollectionViewDataSource sambil membuat 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
Rahul Panzade
sumber
2

Inilah solusi saya. Ini mirip dengan jawaban lain, dengan satu perbedaan utama. Itu tidak membuat jalur yang bergantung pada batas-batas tampilan. Setiap kali Anda membuat jalur berdasarkan batas dan memberikannya ke lapisan, Anda dapat mengalami masalah saat mengubah ukurannya, dan perlu menyiapkan metode untuk memperbarui jalur.

Solusi yang lebih sederhana adalah menghindari penggunaan apa pun yang bergantung pada batas.

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

Sekarang ketika ukuran sel berubah, API tampilan akan melakukan semua pekerjaan secara internal.

Adam
sumber
Jawaban terbersih menurut saya. Suka ide untuk menjaga agar radius tetap sinkron.
Kirill Kudaev
2

Saya menemukan satu hal penting: UICollectionViewCell harus memiliki backgroundColor sebagai clearwarna untuk membuat ini bekerja di atas.

Khang Azun
sumber
Ini SANGAT penting untuk dicapai dengan tidak memotong bayangan! Jangan abaikan jawaban ini, terima kasih BANYAK!
DennyDog