[React Native] [FRC - Don't accept] View border support
This commit is contained in:
parent
d2206d492d
commit
330c1abbff
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('react-native');
|
||||||
|
var {
|
||||||
|
StyleSheet,
|
||||||
|
View
|
||||||
|
} = React;
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
box: {
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
border1: {
|
||||||
|
borderWidth: 10,
|
||||||
|
borderColor: 'brown',
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
borderWidth: 10,
|
||||||
|
borderRadius: 10,
|
||||||
|
borderColor: 'cyan',
|
||||||
|
},
|
||||||
|
border2: {
|
||||||
|
borderWidth: 10,
|
||||||
|
borderTopColor: 'red',
|
||||||
|
borderRightColor: 'yellow',
|
||||||
|
borderBottomColor: 'green',
|
||||||
|
borderLeftColor: 'blue',
|
||||||
|
},
|
||||||
|
border3: {
|
||||||
|
borderColor: 'purple',
|
||||||
|
borderTopWidth: 10,
|
||||||
|
borderRightWidth: 20,
|
||||||
|
borderBottomWidth: 30,
|
||||||
|
borderLeftWidth: 40,
|
||||||
|
},
|
||||||
|
border4: {
|
||||||
|
borderTopWidth: 10,
|
||||||
|
borderTopColor: 'red',
|
||||||
|
borderRightWidth: 20,
|
||||||
|
borderRightColor: 'yellow',
|
||||||
|
borderBottomWidth: 30,
|
||||||
|
borderBottomColor: 'green',
|
||||||
|
borderLeftWidth: 40,
|
||||||
|
borderLeftColor: 'blue',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.title = 'Border';
|
||||||
|
exports.description = 'View borders';
|
||||||
|
exports.examples = [
|
||||||
|
{
|
||||||
|
title: 'Equal-Width / Same-Color',
|
||||||
|
description: 'borderWidth & borderColor',
|
||||||
|
render() {
|
||||||
|
return <View style={[styles.box, styles.border1]} />;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Equal-Width / Same-Color',
|
||||||
|
description: 'borderWidth & borderColor',
|
||||||
|
render() {
|
||||||
|
return <View style={[styles.box, styles.borderRadius]} />;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Equal-Width Borders',
|
||||||
|
description: 'borderWidth & border*Color',
|
||||||
|
render() {
|
||||||
|
return <View style={[styles.box, styles.border2]} />;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Same-Color Borders',
|
||||||
|
description: 'border*Width & borderColor',
|
||||||
|
render() {
|
||||||
|
return <View style={[styles.box, styles.border3]} />;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Custom Borders',
|
||||||
|
description: 'border*Width & border*Color',
|
||||||
|
render() {
|
||||||
|
return <View style={[styles.box, styles.border4]} />;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
|
@ -55,6 +55,7 @@ var APIS = [
|
||||||
require('./AlertIOSExample'),
|
require('./AlertIOSExample'),
|
||||||
require('./AppStateIOSExample'),
|
require('./AppStateIOSExample'),
|
||||||
require('./AsyncStorageExample'),
|
require('./AsyncStorageExample'),
|
||||||
|
require('./BorderExample'),
|
||||||
require('./CameraRollExample.ios'),
|
require('./CameraRollExample.ios'),
|
||||||
require('./GeolocationExample'),
|
require('./GeolocationExample'),
|
||||||
require('./LayoutExample'),
|
require('./LayoutExample'),
|
||||||
|
|
|
@ -437,9 +437,6 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName)
|
||||||
completion(YES);
|
completion(YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deprecate this
|
|
||||||
[view reactSetBorders];
|
|
||||||
|
|
||||||
// Animate view creation
|
// Animate view creation
|
||||||
BOOL shouldAnimateCreation = isNew && ![parentsAreNew[ii] boolValue];
|
BOOL shouldAnimateCreation = isNew && ![parentsAreNew[ii] boolValue];
|
||||||
RCTAnimation *createAnimation = _layoutAnimation.createAnimation;
|
RCTAnimation *createAnimation = _layoutAnimation.createAnimation;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(selected, BOOL);
|
RCT_EXPORT_VIEW_PROPERTY(selected, BOOL);
|
||||||
RCT_EXPORT_VIEW_PROPERTY(icon, NSString);
|
RCT_EXPORT_VIEW_PROPERTY(icon, NSString);
|
||||||
RCT_REMAP_VIEW_PROPERTY(selectedIcon, barItem.selectedImage, NSString);
|
RCT_REMAP_VIEW_PROPERTY(selectedIcon, barItem.selectedImage, UIImage);
|
||||||
RCT_REMAP_VIEW_PROPERTY(badgeValue, barItem.badgeValue, NSString);
|
RCT_REMAP_VIEW_PROPERTY(badgeValue, barItem.badgeValue, NSString);
|
||||||
RCT_CUSTOM_VIEW_PROPERTY(title, NSString, RCTTabBarItem)
|
RCT_CUSTOM_VIEW_PROPERTY(title, NSString, RCTTabBarItem)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,13 @@
|
||||||
|
|
||||||
#import "RCTPointerEvents.h"
|
#import "RCTPointerEvents.h"
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSInteger, RCTBorderSide) {
|
||||||
|
RCTBorderSideTop,
|
||||||
|
RCTBorderSideRight,
|
||||||
|
RCTBorderSideBottom,
|
||||||
|
RCTBorderSideLeft
|
||||||
|
};
|
||||||
|
|
||||||
@protocol RCTAutoInsetsProtocol;
|
@protocol RCTAutoInsetsProtocol;
|
||||||
|
|
||||||
@interface RCTView : UIView
|
@interface RCTView : UIView
|
||||||
|
@ -48,4 +55,22 @@
|
||||||
*/
|
*/
|
||||||
- (void)updateClippedSubviews;
|
- (void)updateClippedSubviews;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Border colors.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) CGColorRef borderTopColor;
|
||||||
|
@property (nonatomic, assign) CGColorRef borderRightColor;
|
||||||
|
@property (nonatomic, assign) CGColorRef borderBottomColor;
|
||||||
|
@property (nonatomic, assign) CGColorRef borderLeftColor;
|
||||||
|
@property (nonatomic, assign) CGColorRef borderColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Border widths.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) CGFloat borderTopWidth;
|
||||||
|
@property (nonatomic, assign) CGFloat borderRightWidth;
|
||||||
|
@property (nonatomic, assign) CGFloat borderBottomWidth;
|
||||||
|
@property (nonatomic, assign) CGFloat borderLeftWidth;
|
||||||
|
@property (nonatomic, assign) CGFloat borderWidth;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
#import "UIView+ReactKit.h"
|
#import "UIView+ReactKit.h"
|
||||||
|
|
||||||
|
static const RCTBorderSide RCTBorderSideCount = 4;
|
||||||
|
|
||||||
@implementation UIView (RCTViewUnmounting)
|
@implementation UIView (RCTViewUnmounting)
|
||||||
|
|
||||||
- (void)react_remountAllSubviews
|
- (void)react_remountAllSubviews
|
||||||
|
@ -91,6 +93,8 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||||
@implementation RCTView
|
@implementation RCTView
|
||||||
{
|
{
|
||||||
NSMutableArray *_reactSubviews;
|
NSMutableArray *_reactSubviews;
|
||||||
|
CAShapeLayer *_borderLayers[RCTBorderSideCount];
|
||||||
|
CGFloat _borderWidths[RCTBorderSideCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)accessibilityLabel
|
- (NSString *)accessibilityLabel
|
||||||
|
@ -106,7 +110,7 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||||
_pointerEvents = pointerEvents;
|
_pointerEvents = pointerEvents;
|
||||||
self.userInteractionEnabled = (pointerEvents != RCTPointerEventsNone);
|
self.userInteractionEnabled = (pointerEvents != RCTPointerEventsNone);
|
||||||
if (pointerEvents == RCTPointerEventsBoxNone) {
|
if (pointerEvents == RCTPointerEventsBoxNone) {
|
||||||
self.accessibilityViewIsModal = NO; // TODO: find out what this is for
|
self.accessibilityViewIsModal = NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,9 +372,193 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
|
||||||
// to updateClippedSubviews manually after loading
|
// to updateClippedSubviews manually after loading
|
||||||
|
|
||||||
[super layoutSubviews];
|
[super layoutSubviews];
|
||||||
|
|
||||||
if (_reactSubviews) {
|
if (_reactSubviews) {
|
||||||
[self updateClippedSubviews];
|
[self updateClippedSubviews];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (RCTBorderSide side = 0; side < RCTBorderSideCount; side++) {
|
||||||
|
if (_borderLayers[side]) [self updatePathForShapeLayerForSide:side];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSublayersOfLayer:(CALayer *)layer
|
||||||
|
{
|
||||||
|
[super layoutSublayersOfLayer:layer];
|
||||||
|
|
||||||
|
const CGRect bounds = layer.bounds;
|
||||||
|
for (RCTBorderSide side = 0; side < RCTBorderSideCount; side++) {
|
||||||
|
_borderLayers[side].frame = bounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)getTrapezoidPoints:(CGPoint[4])outPoints forSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
const CGRect bounds = self.layer.bounds;
|
||||||
|
const CGFloat minX = CGRectGetMinX(bounds);
|
||||||
|
const CGFloat maxX = CGRectGetMaxX(bounds);
|
||||||
|
const CGFloat minY = CGRectGetMinY(bounds);
|
||||||
|
const CGFloat maxY = CGRectGetMaxY(bounds);
|
||||||
|
|
||||||
|
#define BW(SIDE) [self borderWidthForSide:RCTBorderSide##SIDE]
|
||||||
|
|
||||||
|
switch (side) {
|
||||||
|
case RCTBorderSideRight:
|
||||||
|
outPoints[0] = CGPointMake(maxX - BW(Right), maxY - BW(Bottom));
|
||||||
|
outPoints[1] = CGPointMake(maxX - BW(Right), minY + BW(Top));
|
||||||
|
outPoints[2] = CGPointMake(maxX, minY);
|
||||||
|
outPoints[3] = CGPointMake(maxX, maxY);
|
||||||
|
break;
|
||||||
|
case RCTBorderSideBottom:
|
||||||
|
outPoints[0] = CGPointMake(minX + BW(Left), maxY - BW(Bottom));
|
||||||
|
outPoints[1] = CGPointMake(maxX - BW(Right), maxY - BW(Bottom));
|
||||||
|
outPoints[2] = CGPointMake(maxX, maxY);
|
||||||
|
outPoints[3] = CGPointMake(minX, maxY);
|
||||||
|
break;
|
||||||
|
case RCTBorderSideLeft:
|
||||||
|
outPoints[0] = CGPointMake(minX + BW(Left), minY + BW(Top));
|
||||||
|
outPoints[1] = CGPointMake(minX + BW(Left), maxY - BW(Bottom));
|
||||||
|
outPoints[2] = CGPointMake(minX, maxY);
|
||||||
|
outPoints[3] = CGPointMake(minX, minY);
|
||||||
|
break;
|
||||||
|
case RCTBorderSideTop:
|
||||||
|
outPoints[0] = CGPointMake(maxX - BW(Right), minY + BW(Top));
|
||||||
|
outPoints[1] = CGPointMake(minX + BW(Left), minY + BW(Top));
|
||||||
|
outPoints[2] = CGPointMake(minX, minY);
|
||||||
|
outPoints[3] = CGPointMake(maxX, minY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CAShapeLayer *)createShapeLayerIfNotExistsForSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
CAShapeLayer *borderLayer = _borderLayers[side];
|
||||||
|
if (!borderLayer) {
|
||||||
|
borderLayer = [CAShapeLayer layer];
|
||||||
|
borderLayer.fillColor = self.layer.borderColor;
|
||||||
|
[self.layer addSublayer:borderLayer];
|
||||||
|
_borderLayers[side] = borderLayer;
|
||||||
|
}
|
||||||
|
return borderLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updatePathForShapeLayerForSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
CAShapeLayer *borderLayer = [self createShapeLayerIfNotExistsForSide:side];
|
||||||
|
|
||||||
|
CGPoint trapezoidPoints[4];
|
||||||
|
[self getTrapezoidPoints:trapezoidPoints forSide:side];
|
||||||
|
|
||||||
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
|
CGPathAddLines(path, NULL, trapezoidPoints, 4);
|
||||||
|
CGPathCloseSubpath(path);
|
||||||
|
borderLayer.path = path;
|
||||||
|
CGPathRelease(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateBorderLayers
|
||||||
|
{
|
||||||
|
BOOL widthsAndColorsSame = YES;
|
||||||
|
CGFloat width = _borderWidths[0];
|
||||||
|
CGColorRef color = _borderLayers[0].fillColor;
|
||||||
|
for (RCTBorderSide side = 1; side < RCTBorderSideCount; side++) {
|
||||||
|
CAShapeLayer *layer = _borderLayers[side];
|
||||||
|
if (_borderWidths[side] != width || (layer && !CGColorEqualToColor(layer.fillColor, color))) {
|
||||||
|
widthsAndColorsSame = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (widthsAndColorsSame) {
|
||||||
|
|
||||||
|
// Set main layer border
|
||||||
|
if (width) {
|
||||||
|
_borderWidth = self.layer.borderWidth = width;
|
||||||
|
}
|
||||||
|
if (color) {
|
||||||
|
self.layer.borderColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove border layers
|
||||||
|
for (RCTBorderSide side = 0; side < RCTBorderSideCount; side++) {
|
||||||
|
[_borderLayers[side] removeFromSuperlayer];
|
||||||
|
_borderLayers[side] = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Clear main layer border
|
||||||
|
self.layer.borderWidth = 0;
|
||||||
|
|
||||||
|
// Set up border layers
|
||||||
|
for (RCTBorderSide side = 0; side < RCTBorderSideCount; side++) {
|
||||||
|
[self updatePathForShapeLayerForSide:side];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)borderWidthForSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
return _borderWidths[side] ?: _borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBorderWidth:(CGFloat)width forSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
_borderWidths[side] = width;
|
||||||
|
[self updateBorderLayers];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BORDER_WIDTH(SIDE) \
|
||||||
|
- (CGFloat)border##SIDE##Width { return [self borderWidthForSide:RCTBorderSide##SIDE]; } \
|
||||||
|
- (void)setBorder##SIDE##Width:(CGFloat)width { [self setBorderWidth:width forSide:RCTBorderSide##SIDE]; }
|
||||||
|
|
||||||
|
BORDER_WIDTH(Top)
|
||||||
|
BORDER_WIDTH(Right)
|
||||||
|
BORDER_WIDTH(Bottom)
|
||||||
|
BORDER_WIDTH(Left)
|
||||||
|
|
||||||
|
- (CGColorRef)borderColorForSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
return _borderLayers[side].fillColor ?: self.layer.borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBorderColor:(CGColorRef)color forSide:(RCTBorderSide)side
|
||||||
|
{
|
||||||
|
[self createShapeLayerIfNotExistsForSide:side].fillColor = color;
|
||||||
|
[self updateBorderLayers];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BORDER_COLOR(SIDE) \
|
||||||
|
- (CGColorRef)border##SIDE##Color { return [self borderColorForSide:RCTBorderSide##SIDE]; } \
|
||||||
|
- (void)setBorder##SIDE##Color:(CGColorRef)color { [self setBorderColor:color forSide:RCTBorderSide##SIDE]; }
|
||||||
|
|
||||||
|
BORDER_COLOR(Top)
|
||||||
|
BORDER_COLOR(Right)
|
||||||
|
BORDER_COLOR(Bottom)
|
||||||
|
BORDER_COLOR(Left)
|
||||||
|
|
||||||
|
- (void)setBorderWidth:(CGFloat)borderWidth
|
||||||
|
{
|
||||||
|
_borderWidth = borderWidth;
|
||||||
|
for (RCTBorderSide side = 0; side < RCTBorderSideCount; side++) {
|
||||||
|
_borderWidths[side] = borderWidth;
|
||||||
|
}
|
||||||
|
[self updateBorderLayers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBorderColor:(CGColorRef)borderColor
|
||||||
|
{
|
||||||
|
self.layer.borderColor = borderColor;
|
||||||
|
for (RCTBorderSide side = 0; side < RCTBorderSideCount; side++) {
|
||||||
|
_borderLayers[side].fillColor = borderColor;
|
||||||
|
}
|
||||||
|
[self updateBorderLayers];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGColorRef)borderColor
|
||||||
|
{
|
||||||
|
return self.layer.borderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -81,9 +81,6 @@ RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor, CGColor);
|
||||||
RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize);
|
RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize);
|
||||||
RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, CGFloat)
|
RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, CGFloat)
|
||||||
RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat)
|
RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat)
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderColor, layer.borderColor, CGColor);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderRadius, layer.cornerRadius, CGFloat)
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderWidth, layer.borderWidth, CGFloat)
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(transformMatrix, layer.transform, CATransform3D)
|
RCT_REMAP_VIEW_PROPERTY(transformMatrix, layer.transform, CATransform3D)
|
||||||
RCT_CUSTOM_VIEW_PROPERTY(overflow, css_overflow, RCTView)
|
RCT_CUSTOM_VIEW_PROPERTY(overflow, css_overflow, RCTView)
|
||||||
{
|
{
|
||||||
|
@ -122,6 +119,42 @@ RCT_CUSTOM_VIEW_PROPERTY(removeClippedSubviews, BOOL, RCTView)
|
||||||
view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews;
|
view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
RCT_REMAP_VIEW_PROPERTY(borderRadius, layer.cornerRadius, CGFloat)
|
||||||
|
RCT_CUSTOM_VIEW_PROPERTY(borderColor, CGColor, RCTView)
|
||||||
|
{
|
||||||
|
if ([view respondsToSelector:@selector(setBorderColor:)]) {
|
||||||
|
view.borderColor = json ? [RCTConvert CGColor:json] : defaultView.borderColor;
|
||||||
|
} else {
|
||||||
|
view.layer.borderColor = json ? [RCTConvert CGColor:json] : defaultView.layer.borderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RCT_CUSTOM_VIEW_PROPERTY(borderWidth, CGFloat, RCTView)
|
||||||
|
{
|
||||||
|
if ([view respondsToSelector:@selector(setBorderWidth:)]) {
|
||||||
|
view.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.borderWidth;
|
||||||
|
} else {
|
||||||
|
view.layer.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.layer.borderWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RCT_VIEW_BORDER_PROPERTY(SIDE) \
|
||||||
|
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Width, CGFloat, RCTView) \
|
||||||
|
{ \
|
||||||
|
if ([view respondsToSelector:@selector(setBorder##SIDE##Width:)]) { \
|
||||||
|
view.border##SIDE##Width = json ? [RCTConvert CGFloat:json] : defaultView.border##SIDE##Width; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Color, UIColor, RCTView) \
|
||||||
|
{ \
|
||||||
|
if ([view respondsToSelector:@selector(setBorder##SIDE##Color:)]) { \
|
||||||
|
view.border##SIDE##Color = json ? [RCTConvert CGColor:json] : defaultView.border##SIDE##Color; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
RCT_VIEW_BORDER_PROPERTY(Top)
|
||||||
|
RCT_VIEW_BORDER_PROPERTY(Right)
|
||||||
|
RCT_VIEW_BORDER_PROPERTY(Bottom)
|
||||||
|
RCT_VIEW_BORDER_PROPERTY(Left)
|
||||||
|
|
||||||
#pragma mark - ShadowView properties
|
#pragma mark - ShadowView properties
|
||||||
|
|
||||||
|
@ -169,15 +202,4 @@ RCT_CUSTOM_SHADOW_PROPERTY(backgroundColor, UIColor, RCTShadowView)
|
||||||
view.isBGColorExplicitlySet = json ? YES : defaultView.isBGColorExplicitlySet;
|
view.isBGColorExplicitlySet = json ? YES : defaultView.isBGColorExplicitlySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Border properties - to be deprecated
|
|
||||||
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderTopWidth, reactBorderTop.width, CGFloat);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderRightWidth, reactBorderRight.width, CGFloat);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderBottomWidth, reactBorderBottom.width, CGFloat);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderLeftWidth, reactBorderLeft.width, CGFloat);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderTopColor, reactBorderTop.color, UIColor);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderRightColor, reactBorderRight.color, UIColor);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderBottomColor, reactBorderBottom.color, UIColor);
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(borderLeftColor, reactBorderLeft.color, UIColor);
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -42,12 +42,3 @@
|
||||||
- (BOOL)reactRespondsToTouch:(UITouch *)touch;
|
- (BOOL)reactRespondsToTouch:(UITouch *)touch;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface UIView (ReactKitBorders)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Borders stuff - pay no attention to this, it's going away (#6548297)
|
|
||||||
*/
|
|
||||||
- (void)reactSetBorders;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
|
@ -119,156 +119,3 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#pragma mark - Borders
|
|
||||||
|
|
||||||
// Note: the value of this enum determines their relative zPosition
|
|
||||||
typedef NS_ENUM(NSUInteger, RCTBorderSide) {
|
|
||||||
RCTBorderSideTop = 0,
|
|
||||||
RCTBorderSideRight = 1,
|
|
||||||
RCTBorderSideBottom = 2,
|
|
||||||
RCTBorderSideLeft = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
@interface RCTSingleSidedBorder : NSObject
|
|
||||||
|
|
||||||
@property (nonatomic, readwrite, assign) CGFloat width;
|
|
||||||
@property (nonatomic, readwrite, strong) UIColor *color;
|
|
||||||
@property (nonatomic, readonly, assign) RCTBorderSide side;
|
|
||||||
|
|
||||||
- (instancetype)initWithSide:(RCTBorderSide)side superlayer:(CALayer *)superlayer;
|
|
||||||
|
|
||||||
- (void)superLayerBoundsDidChange;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation RCTSingleSidedBorder
|
|
||||||
{
|
|
||||||
CALayer *_borderLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithSide:(RCTBorderSide)side superlayer:(CALayer *)superlayer
|
|
||||||
{
|
|
||||||
if (self = [super init]) {
|
|
||||||
_side = side;
|
|
||||||
|
|
||||||
_borderLayer = [CALayer layer];
|
|
||||||
_borderLayer.delegate = self;
|
|
||||||
_borderLayer.zPosition = INT_MAX - _side;
|
|
||||||
|
|
||||||
[superlayer insertSublayer:_borderLayer atIndex:0];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
|
||||||
{
|
|
||||||
_borderLayer.delegate = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setWidth:(CGFloat)width
|
|
||||||
{
|
|
||||||
_width = width;
|
|
||||||
[_borderLayer setNeedsLayout];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setColor:(UIColor *)color
|
|
||||||
{
|
|
||||||
_color = color;
|
|
||||||
_borderLayer.backgroundColor = _color.CGColor;
|
|
||||||
[_borderLayer setNeedsLayout];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)superLayerBoundsDidChange
|
|
||||||
{
|
|
||||||
[_borderLayer setNeedsLayout];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - CALayerDelegate
|
|
||||||
|
|
||||||
- (void)layoutSublayersOfLayer:(CALayer *)layer
|
|
||||||
{
|
|
||||||
CGSize superlayerSize = layer.superlayer.frame.size;
|
|
||||||
|
|
||||||
CGFloat xPosition = 0.0f;
|
|
||||||
CGFloat yPosition = 0.0f;
|
|
||||||
|
|
||||||
// Note: we ensure side layers are below top & bottom for snapshot test consistency
|
|
||||||
|
|
||||||
switch (self.side) {
|
|
||||||
case RCTBorderSideTop:
|
|
||||||
layer.frame = CGRectMake(xPosition, yPosition, superlayerSize.width, self.width);
|
|
||||||
break;
|
|
||||||
case RCTBorderSideRight:
|
|
||||||
xPosition = superlayerSize.width - self.width;
|
|
||||||
layer.frame = CGRectMake(xPosition, yPosition, self.width, superlayerSize.height);
|
|
||||||
[layer.superlayer insertSublayer:layer atIndex:0];
|
|
||||||
break;
|
|
||||||
case RCTBorderSideBottom:
|
|
||||||
yPosition = superlayerSize.height - self.width;
|
|
||||||
layer.frame = CGRectMake(xPosition, yPosition, superlayerSize.width, self.width);
|
|
||||||
break;
|
|
||||||
case RCTBorderSideLeft:
|
|
||||||
layer.frame = CGRectMake(xPosition, yPosition, self.width, superlayerSize.height);
|
|
||||||
[layer.superlayer insertSublayer:layer atIndex:0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable animations for layer
|
|
||||||
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
|
|
||||||
{
|
|
||||||
return (id)[NSNull null];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation UIView (ReactKitBorders)
|
|
||||||
|
|
||||||
- (void)reactSetBorders
|
|
||||||
{
|
|
||||||
NSMutableDictionary *borders = objc_getAssociatedObject(self, @selector(_createOrGetBorderWithSide:));
|
|
||||||
if (borders) {
|
|
||||||
for (RCTSingleSidedBorder *border in [borders allValues]) {
|
|
||||||
[border superLayerBoundsDidChange];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (RCTSingleSidedBorder *)reactBorderTop
|
|
||||||
{
|
|
||||||
return [self _createOrGetBorderWithSide:RCTBorderSideTop];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (RCTSingleSidedBorder *)reactBorderRight
|
|
||||||
{
|
|
||||||
return [self _createOrGetBorderWithSide:RCTBorderSideRight];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (RCTSingleSidedBorder *)reactBorderBottom
|
|
||||||
{
|
|
||||||
return [self _createOrGetBorderWithSide:RCTBorderSideBottom];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (RCTSingleSidedBorder *)reactBorderLeft
|
|
||||||
{
|
|
||||||
return [self _createOrGetBorderWithSide:RCTBorderSideLeft];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (RCTSingleSidedBorder *)_createOrGetBorderWithSide:(RCTBorderSide)side
|
|
||||||
{
|
|
||||||
NSMutableDictionary *borders = objc_getAssociatedObject(self, _cmd);
|
|
||||||
if (!borders) {
|
|
||||||
borders = [[NSMutableDictionary alloc] init];
|
|
||||||
objc_setAssociatedObject(self, _cmd, borders, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
RCTSingleSidedBorder *border = [borders objectForKey:@(side)];
|
|
||||||
if (!border) {
|
|
||||||
border = [[RCTSingleSidedBorder alloc] initWithSide:side superlayer:self.layer];
|
|
||||||
[borders setObject:border forKey:@(side)];
|
|
||||||
}
|
|
||||||
return border;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
Loading…
Reference in New Issue