Тень UIView и InterfaceBuilder - PullRequest
       1

Тень UIView и InterfaceBuilder

14 голосов
/ 20 сентября 2011

Я хочу добавить тень с помощью CALayer в представление пользовательского интерфейса (изображения).Следующий код обычно работает нормально

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

Однако это работает, только если я создаю это представление программно и добавляю его в качестве подпредставления к моему основному виду.Когда это представление настроено в InterfaceBuilder и определено как IBOutlet UIImageView, это НЕ работает.Тень не появляется.Так чего мне здесь не хватает?

Ответы [ 4 ]

21 голосов
/ 13 февраля 2016

Добавьте файл с именем UIView.swift в ваш проект (или просто вставьте его в любой файл):

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

Тогда это будет доступно в Интерфейсном Разработчике для каждого представления на Панели утилит> Инспектор атрибутов:

Utilities Panel

Теперь вы можете легко установить тень.

Примечания:
- Тень появится только во время выполнения.
- clipsToBounds должно быть ложным (по умолчанию это так)

15 голосов
/ 17 февраля 2015

Я знаю, что этот вопрос давно, но недавно я был в похожей ситуации, поэтому я решил поставить свой ответ для тех, кто находится в такой ситуации.

Я хотел иметь возможность установить borderColor и shadowColor на UIView через Interface Builder, но тип свойства borderColor слоя - CGColor (как shadowColor), что не является одним из типов, которые можно изменять в пользовательской функции атрибутов среды выполнения.

Итак, я сделал расширение для CALayer и добавил два свойства с именами borderColorIB и shadowColorIB, которые имеют тип 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

Теперь я уже могу установить эти два свойства через Interface Builder следующим образом:

  1. В разделе «Атрибуты пользовательской среды выполнения» (инспектор удостоверений)
  2. Убедитесь, что выбран UIView, и добавьте следующие атрибуты времени выполнения:

    • layer.borderWidth, Number, 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, Число, 0,8
    • layer.shadowOffset, size, {5,5}
    • layer.cornerRadius, Number, 5

Вот изображение, чтобы показать вам, как я это сделал:

enter image description here

... и результат будет очевиден во время выполнения, а не в Xcode:

enter image description here

Надеюсь, это поможет некоторым людям!

3 голосов
/ 20 сентября 2011

Я не уверен, в чем проблема - убедитесь, что для свойства UIImageView clipsToBounds установлено значение NO. Вы можете сделать это в viewDidLoad после загрузки из файла пера, ссылаясь на свой IBOutlet. Вам не нужно оборачивать это в другое представление.

Редактировать

В свете необходимости масштабирования изображения с использованием заливки аспектом вы можете использовать свойство contentsRect базового слоя UIImageView, чтобы «имитировать» эффект отсечения содержимого. contentsRect - это прямоугольник в единичном координатном пространстве содержимого слоя (в данном случае вашего изображения), который определяет под прямоугольник содержимого, которое должно быть нарисовано.

Немного математики. Мы можем найти этот прямоугольник, сравнивая размер изображения с размером изображения (учитывая масштабирование заливки):

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);

Делая это, вы можете оставить clipsToBounds установленным на NO для вашего изображения, но изображение все равно будет выглядеть обрезанным. Если вам вообще нужно изменить размер представления изображения, может оказаться удобным заключить этот код в метод, который принимает UIImageView в качестве параметра.

Надеюсь, это поможет.

0 голосов
/ 27 августа 2018

UIView тень с угловым радиусом + построитель интерфейса - swift4

    extension UIView {

        @IBInspectable
        var cornerRadius: CGFloat {
            get {
                return layer.cornerRadius
            }
            set {
                layer.cornerRadius = newValue
                if shadowOpacity > 0.0 {
                    layer.masksToBounds = false
                }
                else {
                    layer.masksToBounds = true
                }
            }
        }
      @IBInspectable
        var borderWidth: CGFloat {
            get {
                return layer.borderWidth
            }
            set {
                layer.borderWidth = newValue
            }
        }
    @IBInspectable
        var borderColor: UIColor? {
            get {
                if let color = layer.borderColor {
                    return UIColor(cgColor: color)
                }
                return nil
            }
            set {
                if let color = newValue {
                    layer.borderColor = color.cgColor
                } else {
                    layer.borderColor = nil
                }
            }
      @IBInspectable var shadowColor: UIColor? {
            set {
                layer.shadowColor = newValue!.cgColor
            }
            get {
                if let color = layer.shadowColor {
                    return UIColor(cgColor: color)
                }
                else {
                    return nil
                }
            }
        }
       @IBInspectable var shadowOpacity: Float {
            set {
                layer.shadowOpacity = newValue
            }
            get {
                return layer.shadowOpacity
            }
        }
     @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)
            }
        }
     @IBInspectable var shadowRadius: CGFloat {
            set {
                layer.shadowRadius = newValue
            }
            get {
                return layer.shadowRadius
            }
        }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...