Für alle anderen, die sich fragen, wie sie mit Core Graphics gemäß Costique-Vorschlag einen inneren Schatten zeichnen sollen, gilt Folgendes: (unter iOS nach Bedarf anpassen)
In Ihrer drawRect: Methode ...
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);
Im Wesentlichen gibt es also die folgenden Schritte:
- Erstellen Sie Ihren Weg
- Stellen Sie die gewünschte Füllfarbe ein, fügen Sie diesen Pfad dem Kontext hinzu und füllen Sie den Kontext
- Erstellen Sie nun ein größeres Rechteck, das den sichtbaren Pfad begrenzen kann. Fügen Sie den sichtbaren Pfad hinzu, bevor Sie diesen Pfad schließen. Schließen Sie dann den Pfad, sodass Sie eine Form erstellen, von der der sichtbare Pfad abgezogen wird. Abhängig davon, wie Sie diese Pfade erstellt haben, möchten Sie möglicherweise die Füllmethoden untersuchen (Wicklung ungerade ungerade / ungerade). Um die Unterpfade beim Addieren zu "subtrahieren", müssen Sie sie im Wesentlichen im Uhrzeigersinn und gegen den Uhrzeigersinn in entgegengesetzte Richtungen zeichnen (oder vielmehr konstruieren).
- Dann müssen Sie Ihren sichtbaren Pfad als Beschneidungspfad für den Kontext festlegen, damit Sie nichts außerhalb davon auf den Bildschirm zeichnen.
- Richten Sie dann den Schatten im Kontext ein, der den Versatz, die Unschärfe und die Farbe enthält.
- Dann füllen Sie die große Form mit dem Loch darin. Die Farbe spielt keine Rolle, denn wenn Sie alles richtig gemacht haben, sehen Sie diese Farbe nicht, nur den Schatten.
Ich weiß, dass ich zu spät zu dieser Party komme, aber das hätte mir geholfen, früh auf meinen Reisen zu finden ...
Um Kredit zu geben, wo Kredit fällig ist, ist dies im Wesentlichen eine Modifikation von Daniel Thorpes Ausarbeitung von Costiques Lösung, eine kleinere Region von einer größeren Region zu subtrahieren. Diese Version ist für Benutzer gedacht, die die Ebenenzusammensetzung verwenden, anstatt sie zu überschreiben
-drawRect:
Die
CAShapeLayer
Klasse kann verwendet werden, um den gleichen Effekt zu erzielen:Wenn Ihre übergeordnete Ebene zu diesem Zeitpunkt nicht bis zu ihren Grenzen maskiert, wird an dieser Stelle der zusätzliche Bereich der Maskenebene um die Ränder der Ebene angezeigt. Dies sind 42 Pixel Schwarz, wenn Sie das Beispiel direkt kopiert haben. Um es loszuwerden, können Sie einfach ein anderes
CAShapeLayer
mit demselben Pfad verwenden und es als Maske der Schattenebene festlegen:Ich habe dies selbst nicht bewertet, aber ich vermute, dass die Verwendung dieses Ansatzes in Verbindung mit Rasterisierung leistungsfähiger ist als das Überschreiben
-drawRect:
.quelle
[[UIBezierPath pathWithRect:[shadowLayer bounds]] CGPath]
die einfachste Wahl sein.Es ist möglich, mit Core Graphics einen inneren Schatten zu zeichnen, indem Sie einen großen Rechteckpfad außerhalb der Grenzen erstellen, einen Rechteckpfad mit Grenzgröße subtrahieren und den resultierenden Pfad mit einem "normalen" Schatten füllen.
Da Sie es jedoch mit einer Verlaufsebene kombinieren müssen, besteht meiner Meinung nach eine einfachere Lösung darin, ein 9-teiliges transparentes PNG-Bild des inneren Schattens zu erstellen und es auf die richtige Größe zu strecken. Das 9-teilige Schattenbild würde folgendermaßen aussehen (seine Größe beträgt 21 x 21 Pixel):
Stellen Sie dann den Rahmen von innerShadowLayer ein und er sollte den Schatten richtig dehnen.
quelle
Eine vereinfachte Version mit nur einem CALayer in Swift:
Beachten Sie, dass die innerShadow-Ebene keine undurchsichtige Hintergrundfarbe haben sollte, da diese vor dem Schatten gerendert wird.
quelle
let innerShadow = CALayer(); innerShadow.frame = bounds
. Ohne die richtigen Grenzen würde es nicht den richtigen Schatten zeichnen.layoutSubviews()
um es synchron zu haltenlayoutSubviews()
oder indraw(_ rect)
Ein bisschen rundherum, aber es wird vermieden, Bilder verwenden zu müssen (lesen Sie: einfach zu ändernde Farben, Schattenradius usw.) und es sind nur ein paar Codezeilen.
Fügen Sie eine UIImageView als erste Unteransicht der UIView hinzu, auf der der Dropshadow angezeigt werden soll. Ich benutze IB, aber Sie können das gleiche programmgesteuert tun.
Angenommen, der Verweis auf UIImageView lautet "innerShadow".
`
Vorsichtsmaßnahme: Sie müssen einen Rand haben, sonst wird der Schatten nicht angezeigt. [UIColor clearColor] funktioniert nicht. Im Beispiel verwende ich eine andere Farbe, aber Sie können damit herumspielen, damit sie dieselbe Farbe wie der Anfang des Schattens hat. :) :)
Siehe den Kommentar von bbrame unten zum
UIColorFromRGB
Makro.quelle
Besser spät als nie...
Hier ist ein anderer Ansatz, wahrscheinlich nicht besser als die bereits veröffentlichten, aber er ist nett und einfach -
quelle
Anstatt mit drawRect einen inneren Schatten zu zeichnen oder der Ansicht UIView hinzuzufügen. Sie können CALayer direkt zum Rand hinzufügen, zum Beispiel: Wenn ich einen inneren Schatteneffekt auf der Unterseite von UIView V haben möchte.
Dadurch wird ein unterer innerer Schatten für das Ziel-UIView hinzugefügt
quelle
Hier ist eine Version von schnell, ändern
startPoint
undendPoint
auf jeder Seite zu machen.quelle
Dies ist Ihre Lösung, die ich aus PaintCode exportiert habe :
quelle
Ich bin sehr spät zur Party, aber ich möchte der Community etwas zurückgeben. Dies ist eine Methode, die ich geschrieben habe, um das UITextField-Hintergrundbild zu entfernen, da ich eine statische Bibliothek und KEINE Ressourcen bereitgestellt habe Ein PIN-Eingabebildschirm mit vier UITextField-Instanzen, auf denen in ViewController ein Zeichen roh oder (BOOL) [self isUsingBullets] oder (BOOL) [self usingAsterisks] angezeigt werden kann. App ist für iPhone / iPhone Retina / iPad / iPad Retina, so dass ich nicht vier Bilder liefern muss ...
Ich hoffe das hilft jemandem, denn dieses Forum hat mir geholfen.
quelle
Lesen Sie den großartigen Artikel über innere Schatten in Quarz von Chris Emery , in dem erklärt wird, wie die inneren Schatten von PaintCode gezeichnet werden, und der einen sauberen und übersichtlichen Codeausschnitt enthält:
quelle
Hier ist meine Lösung in Swift 4.2. Möchten Sie es versuchen?
quelle
let ctx = UIGraphicsGetCurrentContext
UIGraphicsGetCurrentContext
, wenn einige Ansichten ihren Kontext auf den Stapel verschieben.Skalierbare Lösung mit CALayer in Swift
Mit dem beschriebenen können
InnerShadowLayer
Sie auch innere Schatten nur für bestimmte Kanten aktivieren, ausgenommen andere. (z. B. können Sie innere Schatten nur am linken und oberen Rand Ihrer Ansicht aktivieren)Sie können
InnerShadowLayer
Ihrer Ansicht dann ein hinzufügen , indem Sie:InnerShadowLayer
Implementierungquelle
Dieser Code hat bei mir funktioniert
quelle
Hier gibt es einen Code , der dies für Sie erledigen kann. Wenn Sie die Ebene in Ihrer Ansicht (durch Überschreiben
+ (Class)layerClass
) in JTAInnerShadowLayer ändern, können Sie den inneren Schatten auf der Einrückungsebene in Ihrer Init-Methode festlegen und er erledigt die Arbeit für Sie. Wenn Sie auch den ursprünglichen Inhalt zeichnen möchten, stellen Sie sicher, dass SiesetDrawOriginalImage:yes
die Einrückungsebene aufrufen . Es gibt einen Blog-Beitrag darüber, wie das hier funktioniert .quelle
Verwenden der Verlaufsebene:
quelle
Es gibt eine einfache Lösung - zeichnen Sie einfach den normalen Schatten und drehen Sie ihn so
quelle