---
title: Resizing
---

# Resizing

`TransformableBox` is used to resize its content by default. [Transformable Box][transformableBox] utilizes
[Box Transform][boxTransform] to create a fully-featured Flutter implementation of the [Box Transform][boxTransform] API.

```dart title="Resizable widget"
  Stack(
    children: [
      TransformableBox(
        rect: rect,
        flip: flip,
        onChanged: (event) {
          setState(() {
            this.rect = event.rect;
            this.flip = event.flip;
          });
        },
        contentBuilder: (context, rect, flip) => Image.asset( // your widget goes here.
          'assets/images/landscape.jpg',
          width: rect.width,
          height: rect.height,
          fit: BoxFit.fill,
        ),
      ),
    ],
  );
```

<Info>The **_onChanged_** callback is a general callback that is called whenever a change is made to the box. To listen
to specific changes, you can use **_onResized_** and **_onMoved_** callbacks for resizing and moving respectively.
There are also more granular callbacks if desired.</Info>

By default, resizing allows flipping the rect horizontally and vertically. Flipping is done by using the
`Transform.scale` widget with negative scale values.

Resizing is freeform by default, meaning that the user can resize the box in any direction and in any size.

## Controlling Resize Modes

The `resizeModeResolver` is a callback that is called whenever a resize operation is about to be performed on a
given [Transformable Box][transformableBox]. This allows you to define the resize behavior at the time of the resize
operation. This is useful when you want to change the resize behavior based on the state of the application.

The most common use case for this is **keyboard shortcuts**. A `defaultResizeModeResolver` function is used by
default when resizing, and it's job is to listen to keyboard meta keys to change the `ResizeMode`.

### Default Resize Mode:

1. ResizeMode.freeform: **Default** mode. When no keys are pressed.
2. ResizeMode.scale: When `Shift` key is pressed.
3. ResizeMode.symmetric: When `Alt` or `Option` key is pressed.
4. ResizeMode.symmetricScale: When both `Shift` and `Alt`/`Option` keys are pressed.

See [ResizeModes](/resize_modes) page for more information on the different resize modes.

Override this default behavior by providing `resizeModeResolver` in `TransformableBox` constructor to customize
resizing to your liking. This can also be used to allow only certain resize modes.

```dart title="Resizing with preseving aspect ratio"
  TransformableBox(
    rect: rect,
    flip: flip,
    resizeModeResolver: () => ResizeMode.scale,
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```
This will resize the box such that the **aspect ratio** is preserved at all times.

## Flipping

By default, resizing allows flipping the rect horizontally and vertically. Flipping is done by using the
`Transform.scale` widget with negative scale values internally. There are two kinds of flipping involved in resizing:

### Flipping the rect while resizing
While resizing, the rect can be flipped horizontally and vertically whenever the user drags a handle beyond the opposite
side of the rect. This allows more freedom when resizing a box. However, this is not responsible for flipping the
content of the box.

This behavior can be disabled by setting `flipRectWhileResizing` to `false`.

```dart title="Disable flipping the rect while resizing"
  TransformableBox(
    rect: rect,
    flip: flip,
    flipRectWhileResizing: false,
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```

### Flipping the content of the box
This is done by using the `Transform.scale` widget with negative scale values. This is done to allow the content to be
flipped horizontally and vertically.

This behavior can be disabled by setting `allowContentFlipping` to `false`.

```dart title="Disable flipping the child/content of the box"
  TransformableBox(
    rect: rect,
    flip: flip,
    allowContentFlipping: false,
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```

You can set both `flipRectWhileResizing` and `allowContentFlipping` to `false` to disable flipping completely.
The result will be a box that stops shrinking once it reaches a size of zero, as if it hit a wall.

## Constraints

Resizing can be constrained by providing any desirable combination of `minHeight`, `minWidth`, `maxHeight` and
`maxWidth` using the `constraints` property.

```dart title="Resizable widget with constrained resizing"
  TransformableBox(
    rect: rect,
    flip: flip,
    constraints: BoxConstraints(
      minWidth: 100,
      minHeight: 100,
      maxWidth: 500,
      maxHeight: 500,
    ),
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```
This will disallow the box from growing or shrinking beyond 100x100 and 500x500 pixels.

### Constraint callbacks

You can listen to callbacks to listen to when the box reaches the minimum or maximum size. This is useful when you want
to react to these events to show some UI indication like showing a message or changing border color.

You can listen to the `onTerminalSizeReached` callback to listen to when the box reaches some terminal size, vertically
or horizontally to a minimum or maximum size. This is useful when you want to show a message to the user that the box
has reached some resizing limit.

<Info>A **terminal size** is a size that is either the **minimum** or **maximum** size of the box on either axis.
    This can happen when the user tries to resize the box beyond the given **constraints** or the size reaches the
    `clampingRect` size.</Info>

There are more granular terminal callback functions if desired. You can use `onMinWidthReached`, `onMaxWidthReached`,
`onMinHeightReached` and `onMaxHeightReached` callbacks to listen to the individual terminal size events.
You can also use `onTerminalWidthReached` and `onTerminalHeightReached` to listen to combined terminal width and height
events respectively.

```dart title="onTerminalSizeReached callback"
  TransformableBox(
    rect: rect,
    flip: flip,
    constraints: BoxConstraints(
      minWidth: 100,
      minHeight: 100,
      maxWidth: 500,
      maxHeight: 500,
    ),
    onTerminalSizeReached: (
        bool reachedMinWidth,
        bool reachedMaxWidth,
        bool reachedMinHeight,
        bool reachedMaxHeight,
      ) {
        // do something here.
    },
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```

## Handle visibility

Resizing can be disabled completely by setting the `resizable` property to `false`.

```dart title="Disable resizing with the resizable bool"
  TransformableBox(
    rect: rect,
    flip: flip,
    resizable: false,
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```

You can alternatively selectively hide handles by providing your own `visibleHandles` set.

```dart title="Using the visibleHandles set to hide handles"
  TransformableBox(
    rect: rect,
    flip: flip,
    visibleHandles: {HandlePosition.right, HandlePosition.bottom, HandlePosition.bottomRight},
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```

## Handle Interaction

You can selectively disable handles but keep them visible at the same time by providing your own `enabledHandles` set.

```dart title="Using the enabledHandles set to disable handles"
  TransformableBox(
    rect: rect,
    flip: flip,
    enabledHandles: {HandlePosition.right, HandlePosition.bottom, HandlePosition.bottomRight},
    onChanged: (event) {...},
    contentBuilder: (context, rect, flip) {...},
  );
```

<Info>You can provide an empty set to disable all the handles but keep them visible and vice versa.</Info>


[boxTransform]: https://github.com/hyper-designed/box_transform/tree/main/packages/box_transform
[transformableBox]: https://github.com/hyper-designed/box_transform/blob/main/packages/flutter_box_transform/lib/src/transformable_box.dart
