user401183
user401183

Reputation: 2570

How to make a UIView shadow stretch when device is rotated?

In a custom tableview cell, I'm drawing a simple rectangle with a shadow like this:

photoBorder = [[[UIView alloc] initWithFrame:CGRectMake(4, 4, self.frame.size.width-8, 190)] autorelease];
photoBorder.autoresizingMask = UIViewAutoresizingFlexibleWidth;
photoBorder.backgroundColor = [UIColor whiteColor];
photoBorder.layer.masksToBounds = NO;
photoBorder.layer.shadowOffset = CGSizeMake(0, 1);
photoBorder.layer.shadowRadius = 4;
photoBorder.layer.shadowOpacity = 1.0;
photoBorder.layer.shadowColor = [UIColor darkGrayColor].CGColor;
photoBorder.layer.shouldRasterize = YES;
photoBorder.layer.shadowPath = [UIBezierPath bezierPathWithRect:photoBorder.bounds].CGPath; // this line seems to be causing the problem

This works fine when the view first loads. However, when you rotate the device, the shadow stays the same size. I'd really like it to stretch to the new width of "photoBorder".

I can get it to work by removing the shadowPath, but the tableview takes a noticeable performance hit.

Anyone have any tips on making a shadow, on a UIView, that can stretch, without losing performance?

Upvotes: 2

Views: 2011

Answers (3)

Paul Solt
Paul Solt

Reputation: 8395

You need to create a subclass of UIView so that you can get the new bounds in the layoutSubviews() method.

Note: If you try to add this code in a ViewController that owns the subview, the bounds will remain static as you rotate, which results in the wrong shadowPath.

import UIKit

class BackgroundView: UIView {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        updateShadow(on: self)
    }

    func updateShadow(on background: UIView) {
        let layer = background.layer
        layer.shadowPath = UIBezierPath(rect: background.bounds).cgPath
        layer.masksToBounds = false
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOffset = CGSize(width: 0, height: 2)
        layer.shadowRadius = 4
        layer.shadowOpacity = 0.22
    }

}
  1. Make sure you call super.layoutSubviews() to handle any Auto Layout constraints.

  2. You can set a custom class in a Storyboard file.

Upvotes: 3

user401183
user401183

Reputation: 2570

After searching for a few hours and not finding anything, I posted this. Then found an answer a few minutes later.

The simple solution for me appears to be simply moving the shadowPath into layoutSubviews.

- (void)layoutSubviews{
    photoBorder.layer.shadowPath = [UIBezierPath bezierPathWithRect:photoBorder.bounds].CGPath;
}

Upvotes: 6

Mohammad Rabi
Mohammad Rabi

Reputation: 1412

for performance enhancement you can draw an inner shadow using Core Graphics.

Inner shadow effect on UIView layer

Upvotes: 0

Related Questions