1

How do I position content in a CALayer so that it scales to fit the width (preserving aspect ratio) and is positioned at the top of the layer?

More specifically, I'm trying to achieve this positioning with an AVCaptureVideoPreviewLayer. If I set the preview layer's videoGravity to AVLayerVideoGravityResizeAspectFill then it fills the width but centers the content vertically in the frame (cutting off the top and bottom).

scttnlsn
  • 2,976
  • 1
  • 33
  • 39

3 Answers3

2

Try to use .contentGravity property -

A constant that specifies how the layer's contents are positioned or scaled within its bounds

<CALayer>.contentsGravity = kCAGravityResizeAspect;

Possible

CA_EXTERN NSString * const kCAGravityCenter
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityTop
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityBottom
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityLeft
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityRight
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityTopLeft
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityTopRight
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityBottomLeft
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityBottomRight
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityResize
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityResizeAspect
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString * const kCAGravityResizeAspectFill
    __OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
hbk
  • 10,908
  • 11
  • 91
  • 124
  • thumb up for this simple answer! – Jiulong Zhao Jan 30 '16 at 00:32
  • 1
    kCAGravityResizeAspect might not fill the full width (depending on the height). kCAGravityResizeAspectFill does align the centers - not to the top. So I am still wondering how to have kCAGravityResizeAspectFill and top. – tcurdt Sep 21 '16 at 18:08
0

Try using this set of code:

Add this line to the initial layout of the layer:

[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

Then add these:

- (void) viewDidLayoutSubviews
{
    [self layoutPreviewInView:_photoImageView];
}

-(void)layoutPreviewInView:(UIView *) aView
{
    AVCaptureVideoPreviewLayer *layer = [self previewInView:aView];
    if (!layer) return;

    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    CATransform3D transform = CATransform3DIdentity;
    if (orientation == UIDeviceOrientationPortrait) ;
    else if (orientation == UIDeviceOrientationLandscapeLeft)
        transform = CATransform3DMakeRotation(-M_PI_2, 0.0f, 0.0f, 1.0f);
    else if (orientation == UIDeviceOrientationLandscapeRight)
        transform = CATransform3DMakeRotation(M_PI_2, 0.0f, 0.0f, 1.0f);
    else if (orientation == UIDeviceOrientationPortraitUpsideDown)
        transform = CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f);

    layer.transform = transform;
    layer.frame = aView.bounds;
}

-(AVCaptureVideoPreviewLayer *) previewInView: (UIView *) view
{
    for (CALayer *layer in view.layer.sublayers)
    {
        if ([layer isKindOfClass:[AVCaptureVideoPreviewLayer class]])
            return (AVCaptureVideoPreviewLayer *) layer;
    }
    return nil;
}
skorow
  • 1
0

I usually do it with autolayout and this:

-(void)awakeFromNib{
  [super awakeFromNib];
  self.backgroundColor = [UIColor clearColor];
  CAGradientLayer* gradient = (CAGradientLayer*) self.layer;
  gradient.frame = self.bounds;
  gradient.colors = [NSArray arrayWithObjects:
                     (id)[UIColor colorWithRed:0 green:0 blue:0 alpha:0].CGColor,
                     (id)[UIColor colorWithRed:0 green:0 blue:0 alpha:1].CGColor, nil];

}

+ (Class) layerClass {
  return [CAGradientLayer class];
}
rob180
  • 901
  • 1
  • 9
  • 29