Skip to content

Commit 70962ef

Browse files
a-klotz-p8facebook-github-bot
authored andcommitted
Added support for multiple widths with dashed and dotted borders on iOS (facebook#51770)
Summary: This change allows for dashed and dotted borders to have different widths for each of the sides on iOS. This issue was described in facebook#51658. This allows for better dashed lines and moves the implementation of borders closer to how it is handled on web/android. Resolves facebook#51658 (related facebook#39088) ## Changelog: [IOS] [ADDED] - Add support for different borderWidths Pull Request resolved: facebook#51770 Test Plan: - yarn test - yarn lint Reviewed By: NickGerleman Differential Revision: D76145887 Pulled By: jorge-cab fbshipit-source-id: 3716e84799b44d2ff0994cc673a2172ee85bd9e6
1 parent 46eab9c commit 70962ef

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

packages/react-native/React/Views/RCTBorderDrawing.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ typedef struct {
3535
UIColor *right;
3636
} RCTBorderColors;
3737

38+
/**
39+
* Determine the largest border inset value.
40+
*/
41+
RCT_EXTERN CGFloat RCTMaxBorderInset(UIEdgeInsets borderInsets);
42+
3843
/**
3944
* Determine if the border widths, colors and radii are all equal.
4045
*/

packages/react-native/React/Views/RCTBorderDrawing.m

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010

1111
static const CGFloat RCTViewBorderThreshold = 0.001;
1212

13+
CGFloat RCTMaxBorderInset(UIEdgeInsets borderInsets)
14+
{
15+
return MAX(MAX(borderInsets.top, borderInsets.left), MAX(borderInsets.bottom, borderInsets.right));
16+
}
17+
1318
BOOL RCTBorderInsetsAreEqual(UIEdgeInsets borderInsets)
1419
{
1520
return ABS(borderInsets.left - borderInsets.right) < RCTViewBorderThreshold &&
@@ -415,8 +420,8 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn
415420
return image;
416421
}
417422

418-
// Currently, the dashed / dotted implementation only supports a single colour +
419-
// single width, as that's currently required and supported on Android.
423+
// Currently, the dashed / dotted implementation only supports a single colour,
424+
// as that's currently required and supported on Android.
420425
//
421426
// Supporting individual widths + colours on each side is possible by modifying
422427
// the current implementation. The idea is that we will draw four different lines
@@ -486,12 +491,12 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn
486491
{
487492
NSCParameterAssert(borderStyle == RCTBorderStyleDashed || borderStyle == RCTBorderStyleDotted);
488493

489-
if (!RCTBorderColorsAreEqual(borderColors) || !RCTBorderInsetsAreEqual(borderInsets)) {
494+
if (!RCTBorderColorsAreEqual(borderColors)) {
490495
RCTLogWarn(@"Unsupported dashed / dotted border style");
491496
return nil;
492497
}
493498

494-
const CGFloat lineWidth = borderInsets.top;
499+
const CGFloat lineWidth = RCTMaxBorderInset(borderInsets);
495500
if (lineWidth <= 0.0) {
496501
return nil;
497502
}
@@ -519,6 +524,34 @@ static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCorn
519524
CGPathRef path =
520525
RCTPathCreateWithRoundedRect(pathRect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL, NO);
521526

527+
if (!RCTBorderInsetsAreEqual(borderInsets)) {
528+
CGContextSaveGState(context);
529+
{
530+
// Create a path representing the full rect
531+
CGMutablePathRef outerPath = CGPathCreateMutable();
532+
CGPathAddRect(outerPath, NULL, rect);
533+
534+
CGRect insetRect = CGRectMake(
535+
rect.origin.x + borderInsets.left,
536+
rect.origin.y + borderInsets.top,
537+
rect.size.width - borderInsets.left - borderInsets.right,
538+
rect.size.height - borderInsets.top - borderInsets.bottom);
539+
540+
// The padding edge (inner border) radius is the outer border radius minus the corresponding border thickness
541+
CGPathRef innerRoundedRect =
542+
RCTPathCreateWithRoundedRect(insetRect, RCTGetCornerInsets(cornerRadii, borderInsets), NULL, NO);
543+
544+
// Add both paths to outerPath
545+
CGPathAddPath(outerPath, NULL, innerRoundedRect);
546+
547+
// Clip using even-odd
548+
CGContextAddPath(context, outerPath);
549+
CGContextEOClip(context);
550+
CGPathRelease(outerPath);
551+
CGPathRelease(innerRoundedRect);
552+
}
553+
}
554+
522555
CGFloat dashLengths[2];
523556
dashLengths[0] = dashLengths[1] = (borderStyle == RCTBorderStyleDashed ? 3 : 1) * lineWidth;
524557

0 commit comments

Comments
 (0)