UIView с закругленными углами и тени? - PullRequest
349 голосов
/ 21 января 2011

Мне нужен пользовательский UIView ...: я просто хотел чистый белый вид с закругленными углами и легкую тень (без эффекта освещения). Я могу сделать каждый из них один за другим, но возникают обычные clipToBounds / maskToBounds конфликты.

Ответы [ 30 ]

1 голос
/ 29 декабря 2016

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

- (void)addShadowWithRadius:(CGFloat)shadowRadius withOpacity:(CGFloat)shadowOpacity withOffset:(CGSize)shadowOffset withColor:(UIColor *)shadowColor withCornerradius:(CGFloat)cornerRadius
{
    UIView *viewShadow = [[UIView alloc]initWithFrame:self.frame];
    viewShadow.backgroundColor = [UIColor whiteColor];
    viewShadow.layer.shadowColor = shadowColor.CGColor;
    viewShadow.layer.shadowOffset = shadowOffset;
    viewShadow.layer.shadowRadius = shadowRadius;
    viewShadow.layer.shadowOpacity = shadowOpacity;
    viewShadow.layer.cornerRadius = cornerRadius;
    viewShadow.layer.masksToBounds = NO;
    [self.superview insertSubview:viewShadow belowSubview:self];

    [viewShadow setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:viewShadow attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
    [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:viewShadow attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:viewShadow attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];
    [self layoutIfNeeded];

    self.layer.cornerRadius = cornerRadius;
    self.layer.masksToBounds = YES;
}
1 голос
/ 29 апреля 2014

Ответ Даниэля. Джинди выше помог мне! (+1 Даниэль) Однако мне пришлось внести незначительные корректировки - изменить размер shadowFrame, чтобы он соответствовал размеру кадра представления, и включить взаимодействие с пользователем. Вот обновленный код:

+ (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed

    // Modified this line
    shadowFrame.size = CGSizeMake(view.frame.size.width, view.frame.size.height);

    shadowFrame.origin.x = 0.f;
    shadowFrame.origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];

    // Modified this line
    shadow.userInteractionEnabled = YES;
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;

    [shadow addSubview:view];
    return shadow;
}

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

UIView *shadow = [self putView:vc.view 
         insideShadowWithColor:[UIColor blackColor]
                     andRadius:5.0 
                     andOffset:CGSizeMake(0.0, 0.0) 
                    andOpacity:1.0];
vc.view = shadow;
vc.view.layer.cornerRadius = 5.0;
vc.view.layer.masksToBounds = YES;
1 голос
/ 08 апреля 2015

Вам нужно использовать два UIViews для достижения этой цели.Один UIView будет работать как тень, а другой будет работать для скругленной границы.

Вот фрагмент кода Class Method с помощью protocol:

@implementation UIMethods

+ (UIView *)genComposeButton:(UIViewController <UIComposeButtonDelegate> *)observer;
{
    UIView *shadow = [[UIView alloc]init];
    shadow.layer.cornerRadius = 5.0;
    shadow.layer.shadowColor = [[UIColor blackColor] CGColor];
    shadow.layer.shadowOpacity = 1.0;
    shadow.layer.shadowRadius = 10.0;
    shadow.layer.shadowOffset = CGSizeMake(0.0f, -0.5f);

    UIButton *btnCompose = [[UIButton alloc]initWithFrame:CGRectMake(0, 0,60, 60)];
    [btnCompose setUserInteractionEnabled:YES];
    btnCompose.layer.cornerRadius = 30;
    btnCompose.layer.masksToBounds = YES;
    [btnCompose setImage:[UIImage imageNamed:@"60x60"] forState:UIControlStateNormal];
    [btnCompose addTarget:observer action:@selector(btnCompose_click:) forControlEvents:UIControlEventTouchUpInside];
    [shadow addSubview:btnCompose];
    return shadow;
}

В приведенном выше коде btnCompose_click: станет методом делегата @required, который будет срабатывать при нажатии кнопки.

И здесь я добавил кнопку к своему UIViewController следующим образом:

UIView *btnCompose = [UIMethods genComposeButton:self];
btnCompose.frame = CGRectMake(self.view.frame.size.width - 75,
                          self.view.frame.size.height - 75,
                          60, 60);
[self.view addSubview:btnCompose];

Результат будет выглядеть так:

enter image description here

1 голос
/ 28 августа 2014

Я делаю некоторые изменения в коде daniel.gindi

Это все, что вам нужно, чтобы он работал.

+ (void)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andBlur:         (CGFloat)blur andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame = view.frame;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.backgroundColor = [UIColor redColor];
    shadow.userInteractionEnabled = YES; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = blur;
    shadow.layer.cornerRadius = view.layer.cornerRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
}
0 голосов
/ 30 августа 2018
extension UIView {
    func dropRoundedShadowForAllSides() {
        let backgroundView = UIView(frame:self.frame)
        let radius = frame.height/2
        backgroundView.layer.masksToBounds = false
        self.layer.masksToBounds = true
        backgroundView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
        backgroundView.layer.shadowRadius = 4
        backgroundView.layer.shadowOpacity = 0.4

        let path = UIBezierPath()

        // Start at the Top Left Corner + radius distance
        path.move(to: CGPoint(x: 2*radius, y: 0.0))

        // Move to the Top Right Corner - radius distance
        path.addLine(to: CGPoint(x: backgroundView.frame.size.width - radius, y: 0.0))

        // Move to top right corner + radius down as curve
        let centerPoint1 = CGPoint(x:backgroundView.frame.size.width - radius,y:radius)
        path.addArc(withCenter: centerPoint1, radius: radius, startAngle: 3*(.pi/2), endAngle: 0, clockwise: true)

        // Move to the Bottom Right Corner - radius
        path.addLine(to: CGPoint(x: backgroundView.frame.size.width, y: backgroundView.frame.size.height - radius))

        // Move to top right corner + radius left as curve
        let centerPoint2 = CGPoint(x:backgroundView.frame.size.width - radius,y:backgroundView.frame.size.height - radius)
        path.addArc(withCenter: centerPoint2, radius: radius, startAngle: 0, endAngle: .pi/2, clockwise: true)

        // Move to the Bottom Left Corner - radius
        path.addLine(to: CGPoint(x: radius, y: backgroundView.frame.size.height))

        // Move to left right corner - radius up as curve
        let centerPoint3 = CGPoint(x:radius,y:backgroundView.frame.size.height - radius)
        path.addArc(withCenter: centerPoint3, radius: radius, startAngle: .pi/2, endAngle: .pi, clockwise: true)

        // Move to the top Left Corner - radius
        path.addLine(to: CGPoint(x: 0, y: radius))

        // Move to top right corner + radius down as curve
        let centerPoint4 = CGPoint(x:radius,y:radius)
        path.addArc(withCenter: centerPoint4, radius: radius, startAngle: .pi, endAngle: 3 * (.pi/2), clockwise: true)

        path.close()

        backgroundView.layer.shadowPath = path.cgPath
        if let superView = self.superview {
            superView.addSubview(backgroundView)
            superView.sendSubview(toBack: backgroundView)
            superView.bringSubview(toFront: self)
        }

    }
}
0 голосов
/ 23 апреля 2015

Вот как вы это делаете, с закругленными углами и закругленными тенями, не мешая дорожкам.

//Inner view with content
[imageView.layer setBorderColor:[[UIColor lightGrayColor] CGColor]];
[imageView.layer setBorderWidth:1.0f];
[imageView.layer setCornerRadius:8.0f];
[imageView.layer setMasksToBounds:YES];

//Outer view with shadow
UIView* shadowContainer = [[UIView alloc] initWithFrame:imageView.frame];
[shadowContainer.layer setMasksToBounds:NO];
[shadowContainer.layer setShadowColor:[[UIColor blackColor] CGColor]];
[shadowContainer.layer setShadowOpacity:0.6f];
[shadowContainer.layer setShadowRadius:2.0f];
[shadowContainer.layer setShadowOffset: CGSizeMake(0.0f, 2.0f)];

[shadowContainer addSubview:imageView];

Вид с содержимым, в моем случае UIImageView, имеет угловой радиус и поэтому должен маскироваться до границ.

Мы создаем другое представление одинакового размера для теней, устанавливаем для его maskToBounds значение NO, а затем добавляем представление содержимого в представление контейнера (например, shadowContainer).

0 голосов
/ 22 ноября 2013

Ответ, предоставленный Эваном Мулавски, будет работать отлично. Уловка в том, что вы должны установить цвет фона для представления clearColor, а свойство masksToBounds - NO.

Вы можете установить любой цвет, который вы хотите для вида, установить его как

v.layer.backgroundColor = your color;

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

0 голосов
/ 30 января 2018

Swift 4 Решение для создания UICollectionViewCell round и добавления Shadows , без каких-либо расширений и сложностей:)

Примечание: для простых представленийнапример кнопки.Смотрите ответ @ suragch в этом посте.https://stackoverflow.com/a/34984063/7698092. Успешно протестировано для кнопок

В случае, если какой-либо из них все еще борется до вокруг углов и добавить тени одновременно.Хотя это решение работает с UICollectionViewCell, его можно обобщить для любого представления.

Этот метод работал для меня без каких-либо расширений и всех сложных вещей.Я работаю с storyBoard.

Техника

Вы должны добавить UIView (скажем, «containerView») внутри UICollectionViewCell в storyBoard и добавить все необходимые представления (кнопки, изображения и т. Д.) Внутриэтот контейнер ViewView.Смотрите скриншот.Structure of Cell

Подключите розетку для контейнера.Добавьте следующие строки кода в делегатскую функцию CellforItemAtIndexPath.

//adds shadow to the layer of cell

cell.layer.cornerRadius = 3.0
    cell.layer.masksToBounds = false
    cell.layer.shadowColor = UIColor.black.cgColor
    cell.layer.shadowOffset = CGSize(width: 0, height: 0)
    cell.layer.shadowOpacity = 0.6

//makes the cell round 

let containerView = cell.containerView!
    containerView.layer.cornerRadius = 8
    containerView.clipsToBounds = true

Вывод

См. Снимок экрана симулятора Rounded corners with Shadows (UICollectionViewCell)

0 голосов
/ 11 апреля 2017

Я пишу этот метод категории UIView для решения этой проблемы, использует отдельные виды для тени и радиуса угла.

-(UIView *)shadowedWrapViewWithBounds:(CGRect)bounds {
UIView *baseView = [[UIView alloc] init];
baseView.bounds = bounds;
baseView.backgroundColor = [UIColor clearColor];
baseView.layer.shadowColor = [UIColor blackColor].CGColor;
baseView.layer.shadowOffset = CGSizeMake(0, 0);
baseView.layer.shadowOpacity = 0.7;
baseView.layer.shadowRadius = 4.0;

// improve performance
baseView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:baseView.bounds cornerRadius:4].CGPath;
baseView.layer.shouldRasterize = YES;
baseView.layer.rasterizationScale = [UIScreen mainScreen].scale;

[baseView addSubview:self];
//use Masonry autolayout, self can set corner radius
[self makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(baseView);
}];

return baseView;
}
0 голосов
/ 21 сентября 2017

Вам нужно добавить masksToBounds = true для комбинирования между corderRadius shadowRadius.

button.layer.masksToBounds = false;
...