Skip to content

[Feature] Add EdgeInsets.some + exceptTop/Left/Right/Bottom constructors #176470

@Mohamed-7018

Description

@Mohamed-7018

Use case

Summary: Add convenience const constructors to EdgeInsets:

  • a general constructor to set a default for most sides (EdgeInsets.some or EdgeInsets.except), and
  • four single-side convenience constructors: EdgeInsets.exceptTop, EdgeInsets.exceptLeft, EdgeInsets.exceptRight, EdgeInsets.exceptBottom.

These reduce boilerplate in patterns like “padding 16 all around except top = 8” while remaining const and simple.


Motivation

Common patterns:

  • EdgeInsets.all(16) — same on all sides
  • EdgeInsets.only(top: 8, left: 16, right: 16, bottom: 16) — “all except top” (verbose)
  • EdgeInsets.all(16).copyWith(top: 8) — not const

New constructors express intent more clearly and provide const sugar.

We propose small, explicit constructors that let you express intent directly and keep const contexts:

  • EdgeInsets.some(rest: 16, top: 8) — set rest = 16 for unspecified sides, override top

  • EdgeInsets.exceptTop(16) — set 16 for left/right/bottom, top = 0 (or EdgeInsets.exceptTop(16, 8) to set top = 8)

These are trivial wrappers around EdgeInsets.only(...) so there is zero runtime overhead.


Proposal

Proposed API

EdgeInsets.some

/// Creates edge insets where `rest` is applied to unspecified sides,
/// and any explicitly provided sides override `rest`.
///
/// Example:
///   EdgeInsets.some(rest: 16, top: 8) // top=8, left/right/bottom=16
const EdgeInsets.some({
  double rest = 0.0,
  double? left,
  double? top,
  double? right,
  double? bottom,
});


Single-side convenience constructors

/// Apply [value] to left/right/bottom; top defaults to 0.0 or can be overridden.
const EdgeInsets.exceptTop(double value, [double top = 0.0]);

/// Apply [value] to top/right/bottom; left defaults to 0.0 or can be overridden.
const EdgeInsets.exceptLeft(double value, [double left = 0.0]);

/// Apply [value] to left/top/bottom; right defaults to 0.0 or can be overridden.
const EdgeInsets.exceptRight(double value, [double right = 0.0]);

/// Apply [value] to left/top/right; bottom defaults to 0.0 or can be overridden.
const EdgeInsets.exceptBottom(double value, [double bottom = 0.0]);

Directional variants (for RTL-aware code)

Add mirror constructors to EdgeInsetsDirectional:

const EdgeInsetsDirectional.some({
  double rest = 0.0,
  double? start,
  double? top,
  double? end,
  double? bottom,
});

const EdgeInsetsDirectional.exceptStart(double value, [double start = 0.0]);
const EdgeInsetsDirectional.exceptEnd(double value, [double end = 0.0]);

Implementation Sketch

Add these constructors in edge_insets.dart inside class EdgeInsets (trivial forwarding to only keeps const):

// General
const EdgeInsets.some({
  double rest = 0.0,
  double? left,
  double? top,
  double? right,
  double? bottom,
}) : this.only(
        left: left ?? rest,
        top: top ?? rest,
        right: right ?? rest,
        bottom: bottom ?? rest,
      );

const EdgeInsets.except({
  double value = 0.0,
  double? left,
  double? top,
  double? right,
  double? bottom,
}) : this.only(
        left: left ?? value,
        top: top ?? value,
        right: right ?? value,
        bottom: bottom ?? value,
      );

// Single-side helpers
const EdgeInsets.exceptTop(double value, [double top = 0.0])
    : this.only(left: value, top: top, right: value, bottom: value);

const EdgeInsets.exceptLeft(double value, [double left = 0.0])
    : this.only(left: left, top: value, right: value, bottom: value);

const EdgeInsets.exceptRight(double value, [double right = 0.0])
    : this.only(left: value, top: value, right: right, bottom: value);

const EdgeInsets.exceptBottom(double value, [double bottom = 0.0])
    : this.only(left: value, top: value, right: value, bottom: bottom);

Directional variants (in EdgeInsetsDirectional):

const EdgeInsetsDirectional.some({
  double rest = 0.0,
  double? start,
  double? top,
  double? end,
  double? bottom,
}) : this.only(
        start: start ?? rest,
        top: top ?? rest,
        end: end ?? rest,
        bottom: bottom ?? rest,
      );

const EdgeInsetsDirectional.exceptStart(double value, [double start = 0.0])
    : this.only(start: start, top: value, end: value, bottom: value);

const EdgeInsetsDirectional.exceptEnd(double value, [double end = 0.0])
    : this.only(start: value, top: value, end: end, bottom: value);

Implementation note: These constructors are pure sugar and compile to EdgeInsets.only, so they have no runtime allocation cost beyond what EdgeInsets.only already h

Tests

void main() {
  test('EdgeInsets.some uses rest for unspecified sides', () {
    const e = EdgeInsets.some(rest: 10, top: 4);
    expect(e.left, 10);
    expect(e.right, 10);
    expect(e.bottom, 10);
    expect(e.top, 4);
  });

  test('EdgeInsets.except equals equivalent EdgeInsets.only', () {
    const a = EdgeInsets.except(value: 16, top: 8);
    const b = EdgeInsets.only(left: 16, top: 8, right: 16, bottom: 16);
    expect(a, equals(b));
  });

  test('EdgeInsets.exceptTop single-arg equals expected values', () {
    const e = EdgeInsets.exceptTop(12);
    expect(e.left, 12);
    expect(e.right, 12);
    expect(e.bottom, 12);
    expect(e.top, 0);
  });

  test('EdgeInsets.exceptTop with override', () {
    const e = EdgeInsets.exceptTop(20, 6);
    const expected = EdgeInsets.only(left: 20, top: 6, right: 20, bottom: 20);
    expect(e, equals(expected));
  });

  test('EdgeInsetsDirectional.some resolves correctly LTR/RTL', () {
    const d = EdgeInsetsDirectional.some(rest: 8, start: 4);
    final resolvedLTR = d.resolve(TextDirection.ltr);
    expect(resolvedLTR.left, 4);
    expect(resolvedLTR.right, 8);

    final resolvedRTL = d.resolve(TextDirection.rtl);
    expect(resolvedRTL.left, 8);
    expect(resolvedRTL.right, 4);
  });

  test('except helpers are const-constructible', () {
    const p = EdgeInsets.exceptLeft(8, 0);
    expect(p, isNotNull);
  });
}

Backwards compatibility & design notes

  • Additive change: these constructors are new, do not change any existing API semantics.

  • const constructors preserve compile-time construction.

  • The constructors are thin wrappers (delegate to EdgeInsets.only ) — trivial to review and low risk.

  • Directional variants handle RTL via the existing resolve machinery.

Request for Assignment

I would like to contribute this feature to Flutter by implementing it myself.
If this proposal is accepted, I kindly request the Flutter team to assign this issue to me so I can begin working on the implementation and submit a PR.

Next steps I can help with

  • Draft a PR patch (code + tests) you can apply to a fork.
  • Draft the GitHub issue text ready to post (or comment on an existing issue).
  • Implement the EdgeInsetsDirectional variants as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projectc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterframeworkflutter/packages/flutter repository. See also f: labels.team-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework teamworkaround availableThere is a workaround available to overcome the issuewould be a good packageSeparate Flutter package should be made for this

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions