2011-09-20 19 views
13

Chcę dodać cień przy użyciu CALayer do widoku interfejsu użytkownika (obraz). Poniższy kod działa ogólnie dobrzeUIView shadow i InterfaceBuilder

previewImage.layer.shadowColor = [[UIColor blackColor] CGColor]; 
previewImage.layer.shadowOffset = CGSizeMake(1.0f, 1.0f); 
previewImage.layer.shadowOpacity = 1.0f; 
previewImage.layer.shadowRadius = 8.0f; 

Jednak ta działa tylko wtedy, gdy tworzę ten pogląd programowo i dodać go jako podrzędny do mojego widoku głównego. Kiedy widok ten jest skonfigurowany w InterfaceBuilder i zdefiniowany jako UIImageView obiektu IBOutlet, to NIE działa. Nie pojawia się cień. Więc czego tu brakuje?

+1

Zupełnie przypadkowo, po prostu okazało się, rzeczywisty problem nie wydaje się być InterfaceBuilder, ale fakt, że mogę ustawić clipsToBounds mojego InterfaceBuilder widzenia użytkownika = TAK. Brak NO tutaj jest w porządku. Sądzę więc, że będę musiał zawinąć widok w drugim widoku za pomocą clipsToBound = NO i cienia. Czy istnieje inny sposób? – Dennis

+0

Miałem ten sam problem, ale to dlatego, że "Klip subviews" został sprawdzony pod kątem widoku w Konstruktorze interfejsu. Odznaczenie, które spowodowało, że cień CALayera jest widoczny. – azdev

Odpowiedz

2

Nie jestem pewien, na czym polega problem - upewnij się, że Twoja własność UIImageView jest ustawiona na na wartość NO. Możesz to zrobić w viewDidLoad po wczytaniu z pliku nib przez odniesienie do IBOutlet. Nie musisz owijać go w inny widok.

Edit

W świetle ty potrzebować swój wizerunek być skalowane za pomocą proporcji do syta, można użyć własność UIImageViewcontentsRect „podstawowej warstwie s do«symulacyjnej»efektu zawartości wycinek. contentsRect to prostokąt w przestrzeni współrzędnych jednostki treści warstwy (w tym przypadku obrazu), która definiuje podtemat zawartości, która ma zostać narysowana.

Z odrobiną matematyki, możemy znaleźć ten prostokąt poprzez porównanie wielkości obrazu do rozmiaru obrazu (stanowiących skalowania aspekt napełnienia):

CGSize imageViewSize = previewImage.size; 
CGSize imageSize = previewImage.image.size; 

// Find the scaling required for the image to fit the image view (as for aspect fill). 
CGFloat imageWidthScale = fabsf(imageViewSize.width/imageSize.width); 
CGFloat imageHeightScale = fabsf(imageViewSize.height/imageSize.height); 
CGFloat imageScale = (imageWidthScale > imageHeightScale) ? imageWidthScale : imageHeightScale; 

// Determine the new image size, after scaling. 
CGSize scaledImageSize = CGSizeApplyAffineTransform(imageSize, CGAffineTransformMakeScale(imageScale, imageScale)); 

// Set the layer's contentsRect property in order to 'clip' the image to the image view's bounds. 
previewImage.layer.contentsRect = CGRectMake(((scaledImageSize.width - imageViewSize.width)/2.0f)/scaledImageSize.width, 
              ((scaledImageSize.height - imageViewSize.height)/2.0f)/scaledImageSize.height, 
              imageViewSize.width/scaledImageSize.width, 
              imageViewSize.height/scaledImageSize.height); 

ten sposób można pozostawić clipsToBounds zestaw do NO dla widoku obrazu, ale obraz będzie nadal wyświetlany jako obcięty. Jeśli chcesz w ogóle zmienić rozmiar widoku obrazu, wygodne może być zawarcie tego kodu w metodzie, która jako parametr przyjmuje wartość UIImageView.

Mam nadzieję, że to pomoże.

+0

Zgadzam się. Bez konieczności owijania. Po prostu nie clipToBounds - jak cień jest poza granicami. – bandejapaisa

+0

Powodem, dla którego potrzebuję clipToBounds jest to, że obraz jest zbyt duży, aby zmieścił się w widoku i muszę użyć "Wypełnienia aspektu", aby wyglądał dobrze. Mogłem, oczywiście, przyciąć ten obraz, rysując go zupełnie nowym, a następnie dopasowując go za pomocą UIGraphicsGetImageFromCurrentImageContext(). Ale czy nie byłoby to dużo w górze? – Dennis

+0

@Dennis: Jeśli obraz jest statyczny i zostanie użyty tylko w tym rozmiarze, moją pierwszą sugestią będzie najpierw odtworzenie obrazu w oprogramowaniu do edycji obrazów, a następnie użycie go w widoku obrazu projektu bez potrzeby zmiany jego geometria. Jeśli to nie jest opcja, zobacz moją edycję powyżej. – Stuart

14

Wiem, że to pytanie jest długie, ale ostatnio byłem w podobnej sytuacji, więc postanowiłem udzielić mojej odpowiedzi tym, którzy znajdują się w takiej sytuacji.

Chciałem być w stanie ustawić borderColor i shadowColor na zasadzie UIView przez Builder interfejsu, ale typ warstwy borderColor nieruchomości jest CGColor (podobnie jak shadowColor), który nie jest jednym z rodzajów dozwolonych zostać zmienione w zdefiniowana przez użytkownika funkcja atrybutów środowiska wykonawczego.

więc zrobiłem rozszerzenie dla CALayer i dodałem dwie właściwości zwane borderColorIB i shadowColorIB że są typu UIColor:

RuntimeAttributes.h

@import QuartzCore; 

@interface CALayer (IBConfiguration) 

@property(nonatomic, assign) UIColor* borderColorIB; 
@property(nonatomic, assign) UIColor* shadowColorIB; 

@end 

RuntimeAttributes.m

#import <UIKit/UIKit.h> 
#import "RuntimeAttributes.h" 

@implementation CALayer (IBConfiguration) 

-(void)setBorderColorIB:(UIColor*)color 
{ 
    self.borderColor = color.CGColor; 
} 

-(UIColor*)borderColorIB 
{ 
    return [UIColor colorWithCGColor:self.borderColor]; 
} 

-(void)setShadowColorIB:(UIColor*)color 
{ 
    self.shadowColor = color.CGColor; 
} 

-(UIColor*)shadowColorIB 
{ 
    return [UIColor colorWithCGColor:self.shadowColor]; 
} 

@end 

Teraz ja alredy móc ustawić te dwie właściwości poprzez interfejs Builder tak:

  1. W sekcji atrybutów wykonywalne zdefiniowane przez użytkownika "(Identity inspektor)
  2. Upewnij UIView jest zaznaczona, a następnie dodaj następujące atrybuty środowiska wykonawczego:

    • layer.borderWidth, Numer, 1
    • layer.borderColorIB Color, someColor <- my custom property to set the borderColor
    • layer.shadowColorIB Color, someColor <- my custom property to set the shadowColor
    • layer.shadowOpacity, Ilość 0,8
    • layer.shadowOffset, rozmiar {5,5}
    • warstwy. cornerRadius, Number, 5

Oto obraz, aby pokazać, jak to zrobiłem:

enter image description here

... i wynik będzie widoczne w czasie wykonywania, a nie w Xcode:

enter image description here

mam nadzieję, że to może pomóc niektórym ludziom tam!

16

Dodaj plik o nazwie UIView.swift w projekcie (lub po prostu wkleić w dowolnym pliku):

import UIKit 

@IBDesignable extension UIView { 

    /* The color of the shadow. Defaults to opaque black. Colors created 
    * from patterns are currently NOT supported. Animatable. */ 
    @IBInspectable var shadowColor: UIColor? { 
     set { 
      layer.shadowColor = newValue!.CGColor 
     } 
     get { 
      if let color = layer.shadowColor { 
       return UIColor(CGColor:color) 
      } 
      else { 
       return nil 
      } 
     } 
    } 

    /* The opacity of the shadow. Defaults to 0. Specifying a value outside the 
    * [0,1] range will give undefined results. Animatable. */ 
    @IBInspectable var shadowOpacity: Float { 
     set { 
      layer.shadowOpacity = newValue 
     } 
     get { 
      return layer.shadowOpacity 
     } 
    } 

    /* The shadow offset. Defaults to (0, -3). Animatable. */ 
    @IBInspectable var shadowOffset: CGPoint { 
     set { 
      layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y) 
     } 
     get { 
      return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height) 
     } 
    } 

    /* The blur radius used to create the shadow. Defaults to 3. Animatable. */ 
    @IBInspectable var shadowRadius: CGFloat { 
     set { 
      layer.shadowRadius = newValue 
     } 
     get { 
      return layer.shadowRadius 
     } 
    } 
} 

Wtedy to będzie dostępne w konstruktorze Interface dla każdego widoku w panelu Narzędzia> Inspektor Atrybuty:

Utilities Panel

można łatwo ustawić cień teraz.

Notatki:
- Cień pojawi się tylko w środowisku uruchomieniowym.
- clipsToBounds powinny być false (domyślnie jest)