|
| 1 | +# v1.0.0 Migration Guide |
| 2 | + |
| 3 | +The legacy ResponsiveWrapper combined multiple features into one widget. This made it difficult to use at times when custom behavior was required. The updated V1 implementation separates each feature into its own widget. |
| 4 | + |
| 5 | +**Before** |
| 6 | + |
| 7 | +- ResponsiveWrapper |
| 8 | + |
| 9 | +**After** |
| 10 | +- ResponsiveBreakpoints |
| 11 | +- ResponsiveScaledBox |
| 12 | +- MaxWidthBox |
| 13 | + |
| 14 | +## Example |
| 15 | + |
| 16 | +**Before** |
| 17 | + |
| 18 | +```dart |
| 19 | +MaterialApp( |
| 20 | + builder: (context, child) => ResponsiveWrapper.builder( |
| 21 | + BouncingScrollWrapper.builder(context, child!), |
| 22 | + maxWidth: 1200, |
| 23 | + minWidth: 450, |
| 24 | + defaultScale: true, |
| 25 | + breakpoints: [ |
| 26 | + const ResponsiveBreakpoint.resize(450, name: MOBILE), |
| 27 | + const ResponsiveBreakpoint.autoScale(800, name: TABLET), |
| 28 | + const ResponsiveBreakpoint.resize(1920, name: DESKTOP), |
| 29 | + const ResponsiveBreakpoint.autoScale(2460, name: "4K"), |
| 30 | + ], |
| 31 | + background: Container(color: const Color(0xFFF5F5F5))), |
| 32 | +); |
| 33 | +``` |
| 34 | + |
| 35 | +**After** |
| 36 | + |
| 37 | +```dart |
| 38 | +MaterialApp( |
| 39 | + builder: (context, child) => ResponsiveBreakpoints.builder( |
| 40 | + child: child!, |
| 41 | + breakpoints: [ |
| 42 | + const Breakpoint(start: 0, end: 450, name: MOBILE), |
| 43 | + const Breakpoint(start: 451, end: 800, name: TABLET), |
| 44 | + const Breakpoint(start: 801, end: 1920, name: DESKTOP), |
| 45 | + const Breakpoint(start: 1921, end: double.infinity, name: '4K'), |
| 46 | + ], |
| 47 | + ), |
| 48 | + onGenerateRoute: (RouteSettings settings) { |
| 49 | + return MaterialPageRoute(builder: (context) { |
| 50 | + // The following code implements the legacy ResponsiveWrapper AutoScale functionality |
| 51 | + // using the new ResponsiveScaledBox. The ResponsiveScaledBox widget preserves |
| 52 | + // the legacy ResponsiveWrapper behavior, scaling the UI instead of resizing. |
| 53 | + // |
| 54 | + // **MaxWidthBox** - A widget that limits the maximum width. |
| 55 | + // This is used to create a gutter area on either side of the content. |
| 56 | + // |
| 57 | + // **ResponsiveScaledBox** - A widget that renders its child |
| 58 | + // with a FittedBox set to the `width` value. Set the fixed width value |
| 59 | + // based on the active breakpoint. |
| 60 | + return MaxWidthBox( |
| 61 | + maxWidth: 1200, |
| 62 | + background: Container(color: const Color(0xFFF5F5F5)), |
| 63 | + child: ResponsiveScaledBox( |
| 64 | + width: ResponsiveValue<double>(context, conditionalValues: [ |
| 65 | + Condition.equals(name: MOBILE, value: 450), |
| 66 | + Condition.between(start: 800, end: 1100, value: 800), |
| 67 | + Condition.between(start: 1000, end: 1200, value: 1000), |
| 68 | + // There are no conditions for width over 1200 |
| 69 | + // because the `maxWidth` is set to 1200 via the MaxWidthBox. |
| 70 | + ]).value, |
| 71 | + child: BouncingScrollWrapper.builder( |
| 72 | + context, buildPage(settings.name ?? ''), |
| 73 | + dragWithMouse: true), |
| 74 | + ), |
| 75 | + ); |
| 76 | + }); |
| 77 | + }, |
| 78 | +); |
| 79 | +``` |
| 80 | + |
| 81 | + |
| 82 | +#### ResponsiveScaledBox |
| 83 | +> ResponsiveScaledBox(width: width, child: child); |
| 84 | +
|
| 85 | +Replaces the core AutoScale functionality of ResponsiveWrapper. ResponsiveScaledBox renders the `child` widget with the specified `width`. |
| 86 | + |
| 87 | +This widget wraps the Flutter `FittedBox` widget with a `LayoutBuilder` and `MediaQuery`. |
| 88 | + |
| 89 | +**Why should you use a `ResponsiveScaledBox`?** |
| 90 | + |
| 91 | +Use a `ResponsiveScaledBox` instead of a `FittedBox` if the layout is full screen as the widget helps calculate correctly scaled `MediaQueryData`. |
| 92 | + |
| 93 | +#### MaxWidthBox |
| 94 | +> MaxWidthBox(maxWidth: maxWidth, background: background, child: child); |
| 95 | +
|
| 96 | +Limit the `child` widget to the `maxWidth` and paints an optional `background` behind the widget. |
| 97 | + |
| 98 | +This widget is helpful for limiting the content width on large desktop displays and creating gutters on the left and right side of the page. |
| 99 | + |
| 100 | +## Walkthrough |
| 101 | + |
| 102 | +### Core Concept |
| 103 | + |
| 104 | +The v0.2.0 ResponsiveWrapper is deprecated and the old `AutoScale` functionality has been moved to `ResponsiveScaledBox`. |
| 105 | +Now, breakpoints and `AutoScale` behavior are separated. This enables "page-level" responsiveness and more customizability in v1.0.0 which was a limitation of v0.2.0. |
| 106 | + |
| 107 | +The `maxWidth` feature has been moved to `MaxWidthBox`. |
| 108 | + |
| 109 | +### Step 1: Migrate ResponsiveWrapper to ResponsiveBreakpoints |
| 110 | + |
| 111 | +```dart |
| 112 | +ResponsiveBreakpoints.builder( |
| 113 | + child: child!, |
| 114 | + breakpoints: [ |
| 115 | + const Breakpoint(start: 0, end: 450, name: MOBILE), |
| 116 | + const Breakpoint(start: 451, end: 800, name: TABLET), |
| 117 | + const Breakpoint(start: 801, end: 1920, name: DESKTOP), |
| 118 | + const Breakpoint(start: 1921, end: double.infinity, name: '4K'), |
| 119 | + ], |
| 120 | +) |
| 121 | +``` |
| 122 | + |
| 123 | +#### Breakpoints |
| 124 | + |
| 125 | +**Old** |
| 126 | +```dart |
| 127 | +const ResponsiveBreakpoint.resize(450, name: MOBILE) |
| 128 | +``` |
| 129 | + |
| 130 | +**New** |
| 131 | +```dart |
| 132 | +const Breakpoint(start: 0, end: 450, name: MOBILE) |
| 133 | +``` |
| 134 | + |
| 135 | +In v1.0.0, breakpoints are explicit and clearly define a `start` and `end`. |
| 136 | +It's highly recommended to create contiguous breakpoints from `0` to `double.infinity`. |
| 137 | + |
| 138 | +#### Tags |
| 139 | + |
| 140 | +**Old** |
| 141 | +```dart |
| 142 | +const ResponsiveBreakpoint.tag(900, name: 'EXPAND_SIDE_PANEL') |
| 143 | +``` |
| 144 | + |
| 145 | +**New** |
| 146 | +```dart |
| 147 | +const Breakpoint(start: 900, end: 900, name: 'EXPAND_SIDE_PANEL') |
| 148 | +``` |
| 149 | + |
| 150 | +To create a "TAG", set the start and end breakpoints to the same value. |
| 151 | +For example, if you're building a Material 3 Navigation Rail and want to expand the menu to full width once there is enough room, you can add a custom `EXPAND_SIDE_PANEL` breakpoint. |
| 152 | + |
| 153 | +Then, in your code, show the Rail based on the breakpoint condition. |
| 154 | + |
| 155 | +> expand: ResponsiveBreakpoints.of(context).largerThan('EXPAND_SIDE_PANEL') |
| 156 | +
|
| 157 | +## Step 2: Migrate AutoScale to ResponsiveScaledBox |
| 158 | + |
| 159 | +The `ResponsiveScaledBox` replaces the AutoScale functionality from `ResponsiveWrapper`. |
| 160 | + |
| 161 | +**Before** |
| 162 | + |
| 163 | +```dart |
| 164 | +ResponsiveWrapper.builder( |
| 165 | + child: child, |
| 166 | + maxWidth: 1200, |
| 167 | + minWidth: 450, |
| 168 | + defaultScale: true, |
| 169 | + breakpoints: [...], |
| 170 | +) |
| 171 | +``` |
| 172 | + |
| 173 | +**After** |
| 174 | + |
| 175 | +```dart |
| 176 | +ResponsiveScaledBox( |
| 177 | + width: ResponsiveValue<double>(context, conditionalValues: [ |
| 178 | + Condition.equals(name: MOBILE, value: 450), |
| 179 | + Condition.between(start: 800, end: 1100, value: 800), |
| 180 | + Condition.between(start: 1000, end: 1200, value: 1000), |
| 181 | + ]).value, |
| 182 | + child: child, |
| 183 | +) |
| 184 | +``` |
| 185 | + |
| 186 | +The ResponsiveScaledBox takes a ResponsiveValue<double> for its width property. The ResponsiveValue looks up the value based on breakpoint conditions. |
| 187 | + |
| 188 | +For example: |
| 189 | + |
| 190 | +> Condition.equals(name: MOBILE, value: 450), |
| 191 | +
|
| 192 | +The first condition checks if the active breakpoint name equals "MOBILE". If true, it will return the value 450. |
| 193 | + |
| 194 | +When the MOBILE breakpoint is active (the screen width is between 0 and 450), this condition will match and the ResponsiveScaledBox width will be set to 450. This is useful for AutoScaling on screens that are too small and avoiding layout errors. |
| 195 | + |
| 196 | +The ResponsiveValue allows you to define different width values for each breakpoint. It will find the first condition that matches the current active breakpoint, and return that conditional value. |
| 197 | + |
| 198 | +Define fixed width values per breakpoint with Conditions. `Condition.equals()`, `Condition.between()`, etc. |
| 199 | + |
| 200 | +## Step 3: Migrate MaxWidth to MaxWidthBox |
| 201 | +The `MaxWidthBox` replaces the maxWidth property from `ResponsiveWrapper`. |
| 202 | + |
| 203 | +**Before** |
| 204 | + |
| 205 | +```dart |
| 206 | +ResponsiveWrapper.builder( |
| 207 | + maxWidth: 1200, |
| 208 | + child: child |
| 209 | +) |
| 210 | +``` |
| 211 | + |
| 212 | +**After** |
| 213 | + |
| 214 | +```dart |
| 215 | +MaxWidthBox( |
| 216 | + maxWidth: 1200, |
| 217 | + child: child |
| 218 | +) |
| 219 | +``` |
| 220 | + |
| 221 | +Wrap the `MaxWidthBox` around a page to limit the max width. |
0 commit comments