Skip to content

Conversation

@korca0220
Copy link
Contributor

@korca0220 korca0220 commented Jul 21, 2025

Add non-uniform border radius support to TableBorder

This PR extends TableBorder to support border radius even when the outer border sides have different widths but the same color, similar to the non-uniform border support added to Border in #121921.

Changes

  • Enhanced border rendering logic: TableBorder can now apply border radius when outer border sides have uniform colors but non-uniform widths/styles
  • New helper methods: Added outerBorderIsUniform property and distinctVisibleOuterColors() method to determine border uniformity
  • Optimized paint method: Refactored the paint logic to handle three scenarios:
    1. Fully uniform borders (existing optimized path)
    2. Outer borders with uniform colors but non-uniform widths (new non-uniform border radius support)
    3. Completely non-uniform borders (fallback to standard border painting)

Before/After

  • Before: TableBorder with border radius required all sides (including inner borders) to be completely identical.
  • After: TableBorder with border radius only requires outer border colors to be the same, allowing different widths per side.

Example Usage

TableBorder(
  top: BorderSide(color: Colors.blue, width: 3.0),
  right: BorderSide(color: Colors.blue, width: 1.0),  // Different width
  bottom: BorderSide(color: Colors.blue, width: 2.0), // Different width  
  left: BorderSide.none,                              // No border
  horizontalInside: BorderSide(color: Colors.red, width: 1.0), // Different color OK
  verticalInside: BorderSide(color: Colors.red, width: 1.0),   // Different color OK
  borderRadius: BorderRadius.circular(8), // ✅ Now works!
)

Fixes: #173193

Pre-launch Checklist

@google-cla
Copy link

google-cla bot commented Jul 21, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions bot added the framework flutter/packages/flutter repository. See also f: labels. label Jul 21, 2025
@Piinks Piinks self-requested a review July 22, 2025 22:13
@Piinks Piinks force-pushed the add-non-uniform-table-border branch from 73f26b9 to 5948b48 Compare July 23, 2025 23:35
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @korca0220 welcome! Thank you for contributing.

verticalInside.width != topWidth) {
return false;
/// Whether all the outer sides of the border (excluding the inner sides) are identical.
bool get outerBorderIsUniform {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a special case. Can you share more about what it is for? Why not have innerBorderIsUniform?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the question! Let me explain the specific use case that drove this implementation.

The Problem I Faced

I needed to create complex table layouts where:

  1. Different corner radius configurations: Each of the 4 corners needed different radius values for proper visual styling
  2. Combining multiple tables: I had to combine two separate tables to appear as a single unified table

When combining two tables, making them look like a seamless single table requires fine-tuned customization of the borders. However, the existing isUniform condition was too restrictive - it required ALL borders (including inner borders) to be identical, which made this kind of customization impossible.

Why Only outerBorderIsUniform?

The key insight is that border radius only affects the outer edges of a table. Inner borders (horizontalInside, verticalInside) don't contribute to the corner rendering, so their uniformity is irrelevant for radius application.

By checking only outer border uniformity, we can:

  • Apply border radius when outer borders have the same color (but different widths)
  • Allow complete freedom for inner border styling
  • Enable the table combination use case I mentioned above

Why Not innerBorderIsUniform?

I didn't implement innerBorderIsUniform for two reasons:

  1. Personal need: My specific use case didn't require it
  2. General applicability: In typical table designs, I believe there are fewer scenarios where inner border uniformity checking would be necessary

However, you raise a good point - adding innerBorderIsUniform could enable even broader customization possibilities. If there's interest in that functionality, I'd be happy to add it in a follow-up or extend this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for filing an issue. I am not sure this public getter is necessary in order for TableBorder to support non-uniform borders. Can you remove it?

Copy link
Contributor Author

@korca0220 korca0220 Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, of course. I agree — it doesn’t necessarily need to be public. I only made it public to be consistent with isUniform

/// Returns the set of distinct visible colors from the outer border sides.
///
/// Only includes colors from border sides that are not [BorderStyle.none].
@visibleForTesting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point! I can make distinctVisibleOuterColors() private (rename to _distinctVisibleOuterColors()) and remove the @visibleForTesting annotation entirely.

The core functionality can be tested through the public API by:

  • Testing various TableBorder configurations with borderRadius
  • Verifying that border radius is applied when outer colors are uniform but widths differ
  • Ensuring border radius is not applied when outer colors differ

This way we test the actual behavior users care about rather than implementation details.

@Piinks Piinks force-pushed the add-non-uniform-table-border branch from 24e8649 to a3d4556 Compare July 31, 2025 19:50
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @korca0220 I just realized that there is not an open issue this is trying to resolve. I can see how this is similar to changes in #121921, although the addition of outerBorderIsUniform public api is still a bit curious.
Can you file an issues that better illustrates your use case that this would resolve? It will really help evaluate if this is the right fix. :)

@korca0220
Copy link
Contributor Author

Hey @korca0220 I just realized that there is not an open issue this is trying to resolve. I can see how this is similar to changes in #121921, although the addition of outerBorderIsUniform public api is still a bit curious. Can you file an issues that better illustrates your use case that this would resolve? It will really help evaluate if this is the right fix. :)

Hello @Piinks ,
Regarding your question about outerBorderIsUniform:
This property specifically focuses on the outer borders because borderRadius only affects the outer edges of a table. Inner borders (horizontalInside, verticalInside) don't contribute to corner rendering, so their uniformity is irrelevant for radius application.

By checking only outer border uniformity, we can apply border radius when outer borders have the same color but different widths, while allowing complete freedom for inner border styling.

In my specific use case, I needed to combine header and body tables to appear as a single unified table, with proper corner radius. The current isUniform constraint is too restrictive as it requires ALL borders (including inner borders) to be identical, resulting in undesirable thick borders between sections.
This enhancement follows the same pattern as the improvement made to Border class in PR #121921, but applied to TableBorder.

Example

image
Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      buildHeaderTable(shouldShowEmptyRows: !hasPlans),
      buildBodyTable(),
    ],
  ),
// buildHeaderTable...
Table(
    border: TableBorder.all(
      color: DColors.lightGray.color,
      borderRadius: BorderRadius.only(
        topLeft: const Radius.circular(3),
        topRight: const Radius.circular(3),
        bottomLeft: shouldShowEmptyRows ? const Radius.circular(3) : Radius.zero,
        bottomRight: shouldShowEmptyRows ? const Radius.circular(3) : Radius.zero,
      ),
    ),
  • First, I used a combination of two Table. While using just one Table could solve the problem I encountered, I used two tables because of potential future needs. Our business planning requires more diverse table variations, which is why I used two separate tables.
  • Like the border property of Table, I used TableBorder.all. This was the only way to use BorderRadius, but it resulted in an undesired outcome.
  • As shown in the image, my desired result is to remove the bottom border of the "title row." However, the moment I remove it, I can no longer use BorderRadius.
  • In conclusion, one might ask, "Why not just use a single Table?" While that's possible, as briefly mentioned above, I believe we need more flexible control over borders to accommodate more customization in the future.

@Piinks
Copy link
Contributor

Piinks commented Aug 1, 2025

@korca0220 as mentioned previously, and listed in the PR description, there should be an open issue this is resolving. You checked off that it is closing an issue but have not provided what issue that is:

image

This is also not identical to #121921 as described. And is failing many tests. Until these are resolved this change cannot move forward.

@korca0220
Copy link
Contributor Author

@korca0220 as mentioned previously, and listed in the PR description, there should be an open issue this is resolving. You checked off that it is closing an issue but have not provided what issue that is:

image This is also not identical to #121921 as described. And is failing many tests. Until these are resolved this change cannot move forward.

Sorry about that, I will update the information.

@@ -0,0 +1 @@
f85f6b62b6db2a8725cafa75360ec960d581a809
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes look unrelated. Can you revert them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you. I’ll revert the unnecessary changes.

}

/// Inflates an [RRect] by the given [EdgeInsets].
static RRect _inflateRRect(RRect rect, EdgeInsets insets) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are _inflateRect and _deflateRect here the same as the methods defined in BoxBorder? Perhaps those should be made reusable and @protected in the base class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll check it and make the necessary corrections

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a new RRectUtils utility class to address the code duplication between TableBorder and BoxBorder. Since these classes have different base classes (TableBorder is standalone while BoxBorder extends ShapeBorder), we can't easily share the methods through inheritance.

The new utility class provides static methods for inflating and deflating RRects, which are now used by both TableBorder and BoxBorder. This eliminates code duplication while maintaining the existing class hierarchy.

I've also added comprehensive tests for the RRectUtils class to ensure it works correctly in all scenarios.

expect(nonUniformOuter.outerBorderIsUniform, isFalse);
});

test('TableBorder with non-uniform widths but uniform colors applies border radius', () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test that follows this uses the same name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirmed. I’ll clean it up

import 'edge_insets.dart';

/// Utility methods for manipulating [RRect] objects.
abstract final class RRectUtils {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know that we need a new class and file for these methods. I was thinking more along the lines of a mixin. :) That could be defined in box_border.dart. Also, the docs should be clearer about the use case and how radius is incorporated into this. The docs should also link to the associated classed that are using it.

Copy link
Contributor Author

@korca0220 korca0220 Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve moved the shared methods into borders.dart as a public RRectUtils class so both BoxBorder and TableBorder (in separate libraries) can use them without duplicating code.
Since they are in different libraries, a library-private helper wasn’t accessible from both.
I also added complete Dartdoc describing the use case, radius handling, and related classes, per the review feedback.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, I see, I see. Sorry about that mix up.
Now that I am not thinking about these as private, I think they should go into the EdgeInsets class, where inflateRect and deflateRect are defined. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree! Since EdgeInsets class already has similar functions like inflateRect and deflateRect, placing these methods within the same class would improve cohesion.
I'll update the PR to move the RRect utility methods to the EdgeInsets class, keeping them consistent with the existing naming pattern.

@justinmc justinmc requested a review from Piinks August 26, 2025 22:09
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience while I was away on a business trip. 🙏

Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flutter_LGTM

Thank you for working so hard on this to find the right solution for those methods. 🎊

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 Thanks for your persistence on this!

expect(deflatedThenInflated.right, closeTo(original.right, 0.001));
expect(deflatedThenInflated.bottom, closeTo(original.bottom, 0.001));
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing non-widget unit tests for these new methods, this is good.

top.strokeOutset,
right.strokeOutset,
bottom.strokeOutset,
).inflateRRect(borderRect);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a lot cleaner with the new insets methods 👍

@Piinks Piinks added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 22, 2025
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 22, 2025
@auto-submit
Copy link
Contributor

auto-submit bot commented Sep 22, 2025

autosubmit label was removed for flutter/flutter/172441, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@Piinks
Copy link
Contributor

Piinks commented Sep 22, 2025

@korca0220 can you rebase this PR with tip of tree? We should be able to land it once that is done. Thanks!

…72406)

# Improve SweepGradient and TileMode Documentation

## Description
This PR enhances the documentation for `SweepGradient` and `TileMode` to
provide clearer guidance on how angles are measured and how tile modes
affect sweep gradient rendering.

### Changes
1. **SweepGradient Documentation**:
   - Clarified angle measurement in radians from the positive x-axis
   - Documented angle normalization behavior for values outside [0, 2π]
- Added detailed explanations of how each `TileMode` affects rendering
outside the angular sector

2. **Gradient.sweep Constructor**:
   - Improved parameter documentation
- Added a practical example showing how to create a 90-degree sweep
gradient
   - Clarified the relationship between color stops and angles

3. **TileMode Documentation**:
   - Added sweep gradient-specific behavior to each `TileMode` variant
- Clarified how each mode (clamp, repeated, mirror, decal) affects
rendering outside the angular sector
   - Improved overall documentation structure for gradient edge behavior

## Related Issues
Fixes flutter#166206

## Testing
- Verified documentation changes by reviewing the generated API docs
- Ensured all examples compile and render as expected

## Breaking Changes
None - this is purely a documentation improvement.

## Additional Notes
The changes make it much clearer how `startAngle` and `endAngle`
interact with different `TileMode` values, which was a source of
confusion in the original issue.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.


<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Victor Sanni <[email protected]>
@github-actions github-actions bot added f: cupertino flutter/packages/flutter/cupertino repository platform-windows Building on or for Windows specifically d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: routes Navigator, Router, and related APIs. f: gestures flutter/packages/flutter/gestures repository. platform-web Web applications specifically platform-linux Building on or for Linux specifically a: desktop Running on desktop team-infra Owned by Infrastructure team f: focus Focus traversal, gaining or losing focus f: integration_test The flutter/packages/integration_test plugin c: tech-debt Technical debt, code quality, testing, etc. e: impeller Impeller rendering backend issues and features requests team-android Owned by Android platform team team-ios Owned by iOS platform team team-tool Owned by Flutter Tool team d: docs/ flutter/flutter/docs, for contributors platform-macos labels Sep 22, 2025
@korca0220 korca0220 force-pushed the add-non-uniform-table-border branch from ec3128b to 027042c Compare September 22, 2025 14:50
korca0220 added a commit to korca0220/flutter that referenced this pull request Sep 22, 2025
Recreates the implementation from PR flutter#172441 on a clean branch
after resolving rebase issues. Enables border radius when outer
border sides have uniform colors but different widths/styles.

Also adds inflateRRect and deflateRRect methods to EdgeInsets
for consistent handling of rounded rectangles.
korca0220 added a commit to korca0220/flutter that referenced this pull request Sep 22, 2025
@korca0220 korca0220 mentioned this pull request Sep 22, 2025
9 tasks
@korca0220
Copy link
Contributor Author

@Piinks @justinmc Sorry... I've encountered issues while attempting to rebase this PR with the tip of tree. During the rebase process, many unrelated commits were accidentally included, significantly increasing the PR size

Rather than trying to fix this PR directly, I've created a new clean PR #175773 with the same implementation.
I'll close this PR in favor of the new one. Thank you for your review and patience!

@korca0220 korca0220 closed this Sep 22, 2025
Piinks pushed a commit to korca0220/flutter that referenced this pull request Sep 22, 2025
Recreates the implementation from PR flutter#172441 on a clean branch
after resolving rebase issues. Enables border radius when outer
border sides have uniform colors but different widths/styles.

Also adds inflateRRect and deflateRRect methods to EdgeInsets
for consistent handling of rounded rectangles.
Piinks pushed a commit to korca0220/flutter that referenced this pull request Sep 22, 2025
github-merge-queue bot pushed a commit that referenced this pull request Sep 24, 2025
Re-implementation of PR #172441

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

## Add non-uniform border radius support to TableBorder
This PR extends TableBorder to support border radius even when the outer
border sides have different widths but the same color, similar to the
non-uniform border support added to Border in #121921.

### Changes
- Enhanced border rendering logic: TableBorder can now apply border
radius when outer border sides have uniform colors but non-uniform
widths/styles
- New helper methods: Added `outerBorderIsUniform` property and
`distinctVisibleOuterColors()` method to determine border uniformity
- Optimized paint method: Refactored the paint logic to handle three
scenarios:
  1. Fully uniform borders (existing optimized path)
2. Outer borders with uniform colors but non-uniform widths (new
non-uniform border radius support)
3. Completely non-uniform borders (fallback to standard border painting)

### Before/After
- Before: TableBorder with border radius required all sides (including
inner borders) to be completely identical.
- After: TableBorder with border radius only requires outer border
colors to be the same, allowing different widths per side.

### Example Usage
```dart
TableBorder(
  top: BorderSide(color: Colors.blue, width: 3.0),
  right: BorderSide(color: Colors.blue, width: 1.0),  // Different width
  bottom: BorderSide(color: Colors.blue, width: 2.0), // Different width  
  left: BorderSide.none,                              // No border
  horizontalInside: BorderSide(color: Colors.red, width: 1.0), // Different color OK
  verticalInside: BorderSide(color: Colors.red, width: 1.0),   // Different color OK
  borderRadius: BorderRadius.circular(8), // ✅ Now works!
)
```
Fixes: #173193


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Jaineel-Mamtora pushed a commit to Jaineel-Mamtora/flutter_forked that referenced this pull request Sep 24, 2025
Re-implementation of PR flutter#172441

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

## Add non-uniform border radius support to TableBorder
This PR extends TableBorder to support border radius even when the outer
border sides have different widths but the same color, similar to the
non-uniform border support added to Border in flutter#121921.

### Changes
- Enhanced border rendering logic: TableBorder can now apply border
radius when outer border sides have uniform colors but non-uniform
widths/styles
- New helper methods: Added `outerBorderIsUniform` property and
`distinctVisibleOuterColors()` method to determine border uniformity
- Optimized paint method: Refactored the paint logic to handle three
scenarios:
  1. Fully uniform borders (existing optimized path)
2. Outer borders with uniform colors but non-uniform widths (new
non-uniform border radius support)
3. Completely non-uniform borders (fallback to standard border painting)

### Before/After
- Before: TableBorder with border radius required all sides (including
inner borders) to be completely identical.
- After: TableBorder with border radius only requires outer border
colors to be the same, allowing different widths per side.

### Example Usage
```dart
TableBorder(
  top: BorderSide(color: Colors.blue, width: 3.0),
  right: BorderSide(color: Colors.blue, width: 1.0),  // Different width
  bottom: BorderSide(color: Colors.blue, width: 2.0), // Different width  
  left: BorderSide.none,                              // No border
  horizontalInside: BorderSide(color: Colors.red, width: 1.0), // Different color OK
  verticalInside: BorderSide(color: Colors.red, width: 1.0),   // Different color OK
  borderRadius: BorderRadius.circular(8), // ✅ Now works!
)
```
Fixes: flutter#173193


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
reidbaker pushed a commit to AbdeMohlbi/flutter that referenced this pull request Dec 10, 2025
Re-implementation of PR flutter#172441

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

## Add non-uniform border radius support to TableBorder
This PR extends TableBorder to support border radius even when the outer
border sides have different widths but the same color, similar to the
non-uniform border support added to Border in flutter#121921.

### Changes
- Enhanced border rendering logic: TableBorder can now apply border
radius when outer border sides have uniform colors but non-uniform
widths/styles
- New helper methods: Added `outerBorderIsUniform` property and
`distinctVisibleOuterColors()` method to determine border uniformity
- Optimized paint method: Refactored the paint logic to handle three
scenarios:
  1. Fully uniform borders (existing optimized path)
2. Outer borders with uniform colors but non-uniform widths (new
non-uniform border radius support)
3. Completely non-uniform borders (fallback to standard border painting)

### Before/After
- Before: TableBorder with border radius required all sides (including
inner borders) to be completely identical.
- After: TableBorder with border radius only requires outer border
colors to be the same, allowing different widths per side.

### Example Usage
```dart
TableBorder(
  top: BorderSide(color: Colors.blue, width: 3.0),
  right: BorderSide(color: Colors.blue, width: 1.0),  // Different width
  bottom: BorderSide(color: Colors.blue, width: 2.0), // Different width  
  left: BorderSide.none,                              // No border
  horizontalInside: BorderSide(color: Colors.red, width: 1.0), // Different color OK
  verticalInside: BorderSide(color: Colors.red, width: 1.0),   // Different color OK
  borderRadius: BorderRadius.circular(8), // ✅ Now works!
)
```
Fixes: flutter#173193


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) a: desktop Running on desktop a: internationalization Supporting other languages or locales. (aka i18n) a: tests "flutter test", flutter_test, or one of our tests a: text input Entering text in a text field or keyboard related problems c: contributor-productivity Team-specific productivity, code health, technical debt. c: tech-debt Technical debt, code quality, testing, etc. d: api docs Issues with https://api.flutter.dev/ d: docs/ flutter/flutter/docs, for contributors d: examples Sample code and demos e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels. f: cupertino flutter/packages/flutter/cupertino repository f: focus Focus traversal, gaining or losing focus f: gestures flutter/packages/flutter/gestures repository. f: integration_test The flutter/packages/integration_test plugin f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. platform-android Android applications specifically platform-fuchsia Fuchsia code specifically platform-ios iOS applications specifically platform-linux Building on or for Linux specifically platform-macos platform-web Web applications specifically platform-windows Building on or for Windows specifically team-android Owned by Android platform team team-infra Owned by Infrastructure team team-ios Owned by iOS platform team team-tool Owned by Flutter Tool team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TableBorder should support border radius with non-uniform border widths