Skip to content

Instantly share code, notes, and snippets.

@paramaggarwal
Created January 14, 2016 15:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paramaggarwal/b9baa00fd7bee9a2948f to your computer and use it in GitHub Desktop.
Save paramaggarwal/b9baa00fd7bee9a2948f to your computer and use it in GitHub Desktop.
React Native Rigid Aspect Ratio Component
#import "RCTShadowView.h"
@interface RNTRigidShadowView : RCTShadowView
/**
* Makes the box rigid, and sizes itself in flex with the
* defined aspect ratio of the CGSize rectangle.
*/
@property (nonatomic, assign) CGSize box;
@end
#import "RNTRigidShadowView.h"
@implementation RNTRigidShadowView
/*
* Sets the measure function on the cssNode, when the `box` rectangle is
* set. This helps calculate the height of the node based on width of the parent
* and maintains the aspect ratio of the node.
*/
static css_dim_t RCTBoxMeasure(void *context, float width)
{
RNTRigidShadowView *shadowView = (__bridge RNTRigidShadowView *)context;
if (isnan(width)) {
width = shadowView.box.width;
}
CGFloat computedHeight = 0.0f;
if (shadowView.box.width > 0) {
computedHeight = width * (shadowView.box.height / shadowView.box.width);
}
css_dim_t result;
result.dimensions[CSS_WIDTH] = width;
result.dimensions[CSS_HEIGHT] = computedHeight;
return result;
}
- (void)setBox:(CGSize)box
{
_box = box;
self.cssNode->measure = (box.width && box.height) ? RCTBoxMeasure : nil;
[self dirtyLayout];
}
@end
#import "RCTView.h"
@interface RNTRigidView : RCTView
@end
#import "RNTRigidView.h"
@implementation RNTRigidView
@end
#import "RCTViewManager.h"
@interface RNTRigidViewManager : RCTViewManager
@end
#import "RNTRigidViewManager.h"
#import "RNTRigidView.h"
#import "RNTRigidShadowView.h"
@implementation RNTRigidViewManager
RCT_EXPORT_MODULE();
- (RNTRigidView *)view
{
return [[RNTRigidView alloc] initWithFrame:CGRectZero];
}
- (RNTRigidShadowView *)shadowView
{
return [[RNTRigidShadowView alloc] init];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_SHADOW_PROPERTY(box, CGSize)
@end
@polarathene
Copy link

I'm not familiar with the codebase, did you specify to only have access to width or is that a limitation? If you could get height of the element passed in too, then you could do something like the following to support sizing the opposite dimension based on only one being defined.

Here is some JS pseudo-code:

let dimensions = [ {dimension: CSS_WIDTH, value: width}, {dimension: CSS_HEIGHT, value: height} ];
// If no height value default to width, else use height as the base
const base = (isnan(height) || height <= 0) ? dimensions.splice(0,1) : dimensions.splice(1,1); // or shift()/pop()

// If base is width verify a valid value. I don't feel good about this, since it'd check height twice, 
// presumably you'd verify at least one dimension was valid prior to running the function, 
// providing a default should belong to a min-width/height property, should either be 0 or throw an error
if (isnan(base.value) || base.value <= 0) {
    base.value = 0
}

// removed the base object, leaving the other to be the computed object
let computed = dimensions[0];
computed.value = base.value / aspectRatio; // eg 320 / 1.3333333 = 240


// return snippet now refers to base/computed dimension property and value to set CSS_WIDTH/HEIGHT props.
css_dim_t result;
result.dimensions[base.dimension] = base.value;
result.dimensions[computed.dimension] = computed.value;
return result;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment