Created
January 14, 2016 15:00
-
-
Save paramaggarwal/b9baa00fd7bee9a2948f to your computer and use it in GitHub Desktop.
React Native Rigid Aspect Ratio Component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "RCTView.h" | |
@interface RNTRigidView : RCTView | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "RNTRigidView.h" | |
@implementation RNTRigidView | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "RCTViewManager.h" | |
@interface RNTRigidViewManager : RCTViewManager | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
What is the purpose of supplying the box width/height params? If width can be dynamic with flex: 1
and the height is computed by applying the box width/height ratio to the actual width, why not just supply an aspect ratio value instead? The supplied value could still be calculated by providing it as (320/240)
or 1.3333333
or (4/3)
all resulting in a 4:3
ratio value.
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
Here is the generic component I have been using to make an arbitrary container who's height is always in a particular ratio to its width. This width is equal to the width of the parent. Great for use with images where you want them to stick to a particular aspect ratio.
USAGE
First import all the necessary things.
Now you can first make a
RigidView
container that will always keep a given height in ratio with the width of its parent. This ratio is defined by thebox
property.where
box
is of the form:LICENSE: MIT
Feel free to use the code anywhere and also make it into an OSS component.