Bagi orang lain yang bertanya-tanya bagaimana cara menggambar bayangan dalam menggunakan Core Graphics sesuai saran Costique, maka begini caranya: (di iOS sesuaikan sesuai kebutuhan)
Dalam metode drawRect: ...
CGRect bounds = [self bounds];
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat radius = 0.5f * CGRectGetHeight(bounds);
// Create the "visible" path, which will be the shape that gets the inner shadow
// In this case it's just a rounded rect, but could be as complex as your want
CGMutablePathRef visiblePath = CGPathCreateMutable();
CGRect innerRect = CGRectInset(bounds, radius, radius);
CGPathMoveToPoint(visiblePath, NULL, innerRect.origin.x, bounds.origin.y);
CGPathAddLineToPoint(visiblePath, NULL, innerRect.origin.x + innerRect.size.width, bounds.origin.y);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, bounds.origin.y, bounds.origin.x + bounds.size.width, innerRect.origin.y, radius);
CGPathAddLineToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, innerRect.origin.y + innerRect.size.height);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height, innerRect.origin.x + innerRect.size.width, bounds.origin.y + bounds.size.height, radius);
CGPathAddLineToPoint(visiblePath, NULL, innerRect.origin.x, bounds.origin.y + bounds.size.height);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x, bounds.origin.y + bounds.size.height, bounds.origin.x, innerRect.origin.y + innerRect.size.height, radius);
CGPathAddLineToPoint(visiblePath, NULL, bounds.origin.x, innerRect.origin.y);
CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x, bounds.origin.y, innerRect.origin.x, bounds.origin.y, radius);
CGPathCloseSubpath(visiblePath);
// Fill this path
UIColor *aColor = [UIColor redColor];
[aColor setFill];
CGContextAddPath(context, visiblePath);
CGContextFillPath(context);
// Now create a larger rectangle, which we're going to subtract the visible path from
// and apply a shadow
CGMutablePathRef path = CGPathCreateMutable();
//(when drawing the shadow for a path whichs bounding box is not known pass "CGPathGetPathBoundingBox(visiblePath)" instead of "bounds" in the following line:)
//-42 cuould just be any offset > 0
CGPathAddRect(path, NULL, CGRectInset(bounds, -42, -42));
// Add the visible path (so that it gets subtracted for the shadow)
CGPathAddPath(path, NULL, visiblePath);
CGPathCloseSubpath(path);
// Add the visible paths as the clipping path to the context
CGContextAddPath(context, visiblePath);
CGContextClip(context);
// Now setup the shadow properties on the context
aColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 3.0f, [aColor CGColor]);
// Now fill the rectangle, so the shadow gets drawn
[aColor setFill];
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextEOFillPath(context);
// Release the paths
CGPathRelease(path);
CGPathRelease(visiblePath);
Jadi, intinya ada langkah-langkah berikut:
- Ciptakan jalan Anda
- Atur warna isian yang Anda inginkan, tambahkan jalur ini ke konteks, dan isi konteksnya
- Sekarang buat persegi panjang yang lebih besar yang dapat mengikat jalur yang terlihat. Sebelum menutup jalur ini, tambahkan jalur yang terlihat. Kemudian tutup jalurnya, sehingga Anda membuat bentuk dengan jalur yang terlihat dikurangi darinya. Anda mungkin ingin menyelidiki metode pengisian (belitan genap / ganjil bukan nol) bergantung pada cara Anda membuat jalur ini. Intinya, untuk mendapatkan subpath untuk "mengurangi" saat Anda menjumlahkannya, Anda perlu menggambarnya (atau lebih tepatnya membangunnya) ke arah yang berlawanan, satu searah jarum jam dan yang lainnya berlawanan arah jarum jam.
- Kemudian Anda perlu mengatur jalur yang terlihat sebagai jalur kliping pada konteks, sehingga Anda tidak menggambar apa pun di luarnya ke layar.
- Kemudian atur bayangan pada konteksnya, yang mencakup offset, blur, dan warna.
- Kemudian isi bentuk besar dengan lubang di dalamnya. Warnanya tidak masalah, karena jika Anda melakukan semuanya dengan benar, Anda tidak akan melihat warna ini, hanya bayangannya.
Saya tahu saya terlambat ke pesta ini, tetapi ini akan membantu saya menemukan lebih awal dalam perjalanan saya ...
Untuk memberikan kredit di mana kredit jatuh tempo, ini pada dasarnya adalah modifikasi dari elaborasi Daniel Thorpe tentang solusi Costique untuk mengurangi wilayah yang lebih kecil dari wilayah yang lebih besar. Versi ini untuk mereka yang menggunakan komposisi lapisan, bukan menimpa
-drawRect:
The
CAShapeLayer
kelas dapat digunakan untuk mencapai efek yang sama:Pada titik ini, jika lapisan induk Anda tidak menutupi batasnya, Anda akan melihat area ekstra dari lapisan topeng di sekitar tepi lapisan. Ini akan menjadi 42 piksel hitam jika Anda baru saja menyalin contoh secara langsung. Untuk menghilangkannya, Anda cukup menggunakan yang lain
CAShapeLayer
dengan jalur yang sama dan mengaturnya sebagai topeng lapisan bayangan:Saya belum membandingkannya sendiri, tetapi saya menduga bahwa menggunakan pendekatan ini dalam hubungannya dengan rasterisasi lebih berkinerja daripada menimpa
-drawRect:
.sumber
[[UIBezierPath pathWithRect:[shadowLayer bounds]] CGPath]
menjadi pilihan paling sederhana.Anda dapat menggambar bayangan bagian dalam dengan Grafik Inti dengan membuat jalur persegi panjang besar di luar batas, mengurangi jalur persegi panjang seukuran batas dan mengisi jalur yang dihasilkan dengan bayangan "normal" aktif.
Namun, karena Anda perlu menggabungkannya dengan lapisan gradien, saya pikir solusi yang lebih mudah adalah membuat gambar PNG transparan 9 bagian dari bayangan bagian dalam dan merentangkannya ke ukuran yang tepat. Gambar bayangan 9 bagian akan terlihat seperti ini (ukurannya 21x21 piksel):
Kemudian setel bingkai innerShadowLayer dan itu harus meregangkan bayangan dengan benar.
sumber
Versi yang disederhanakan hanya menggunakan CALayer, di Swift:
Perhatikan bahwa lapisan innerShadow tidak boleh memiliki warna latar belakang buram karena ini akan ditampilkan di depan bayangan.
sumber
let innerShadow = CALayer(); innerShadow.frame = bounds
. Tanpa batas yang tepat, itu tidak akan menarik bayangan yang tepat. Terima kasihlayoutSubviews()
tetap sinkronlayoutSubviews()
atau didraw(_ rect)
Agak berputar-putar, tetapi menghindari keharusan menggunakan gambar (baca: mudah mengubah warna, radius bayangan, dll.) Dan itu hanya beberapa baris kode.
Tambahkan UIImageView sebagai subview pertama dari UIView tempat Anda ingin dropshadow. Saya menggunakan IB, tetapi Anda dapat melakukan hal yang sama secara terprogram.
Mengasumsikan referensi ke UIImageView adalah 'innerShadow'
`
Peringatan: Anda harus memiliki perbatasan, atau bayangan tidak muncul. [UIColor clearColor] tidak berfungsi. Dalam contoh, saya menggunakan warna yang berbeda, tetapi Anda dapat mengacaukannya untuk membuatnya memiliki warna yang sama seperti awal bayangan. :)
Lihat komentar bbrame di bawah tentang
UIColorFromRGB
makro.sumber
Lebih baik terlambat daripada tidak sama sekali...
Berikut pendekatan lain, mungkin tidak lebih baik dari yang sudah diposting, tapi bagus & sederhana -
sumber
Alih-alih menggambar bayangan dalam dengan drawRect atau menambahkan UIView ke View. Anda dapat langsung menambahkan CALayer ke perbatasan, misalnya: jika saya ingin efek bayangan di bagian bawah UIView V.
Ini menambahkan bayangan bagian dalam bawah untuk target UIView
sumber
Berikut ini adalah versi swift, change
startPoint
andendPoint
make it on each side.sumber
Ini adalah solusi Anda, yang telah saya ekspor dari PaintCode :
sumber
Saya sangat terlambat ke pesta tetapi saya ingin memberikan kembali kepada komunitas .. Ini adalah metode yang saya tulis untuk menghapus Gambar latar belakang UITextField karena saya menyediakan Perpustakaan Statis dan TANPA Sumber Daya ... Saya menggunakan ini untuk layar Entri PIN dari empat instance UITextField yang dapat menampilkan Satu karakter mentah atau (BOOL) [self isUsingBullets] atau (BOOL) [self usingAsterisks] di ViewController. Aplikasi untuk iPhone / iPhone retina / iPad / iPad Retina jadi saya tidak perlu menyediakan empat gambar ...
Saya harap ini membantu seseorang karena forum ini telah membantu saya.
sumber
Periksa artikel hebat Inner Shadows in Quartz oleh Chris Emery yang menjelaskan bagaimana bayangan bagian dalam digambar oleh PaintCode dan memberikan cuplikan kode yang bersih dan rapi:
sumber
Inilah solusi saya di Swift 4.2. Mau coba?
sumber
let ctx = UIGraphicsGetCurrentContext
UIGraphicsGetCurrentContext
untuk mengambil ketika beberapa tampilan mendorong konteks mereka ke tumpukan.Solusi yang dapat diskalakan menggunakan CALayer di Swift
Dengan yang dijelaskan
InnerShadowLayer
Anda juga dapat mengaktifkan bayangan dalam untuk tepi tertentu saja, tidak termasuk yang lain. (misalnya, Anda dapat mengaktifkan bayangan dalam hanya di tepi kiri dan atas tampilan Anda)Anda kemudian dapat menambahkan a
InnerShadowLayer
ke tampilan Anda menggunakan:InnerShadowLayer
penerapansumber
kode ini berhasil untuk saya
sumber
Ada beberapa kode di sini yang dapat melakukan ini untuk Anda. Jika Anda mengubah lapisan dalam tampilan Anda (dengan menimpa
+ (Class)layerClass
), ke JTAInnerShadowLayer maka Anda dapat mengatur bayangan dalam pada lapisan indentasi di metode init Anda dan itu akan melakukan pekerjaan untuk Anda. Jika Anda juga ingin menggambar konten asli, pastikan Anda memanggilsetDrawOriginalImage:yes
lapisan indentasi. Ada entri blog tentang cara kerjanya di sini .sumber
Menggunakan Gradient Layer:
sumber
Ada solusi sederhana - cukup gambar bayangan normal dan putar, seperti ini
sumber