Flutter Transform with challenges

  • using the container’s transform property
  • wrapping the container with a Transform widget
  • Scale
  • Skew
  • Translate

Table of Contents

Examples and theory

  • Definition
  • Constructor vs. transform property
  • Scale
    Transform.scale constructor
    • scale argument
    • alignment argument
    • Scale down (0.5) with the origin in the top-left corner
    • Scale down (0.5) with the origin in the bottom-right corner
    • Scale down (0.5) with the origin in the center
    • Scale-up (1.7) with the origin in the top-left corner
  • Skew
    • There is not a Transform.skew constructor
    • alignment argument
    • Before transforming…
    • Skew along the X-axis with positive alpha
    • Skew along the X-axis with negative alpha
    • Changing the origin of the skew
    • Skewing along the Y-axis
  • Translate
    Transform.translate constructor
    • scale argument
    • Before translating…
    • Translate in the X-axis
    • Translate in the Y-axis
    • Translate in both X and Y axes
    • Translate and compose

Challenges

EXAMPLES AND THEORY

Definition

Transform is a widget that applies a transformation before painting its child, which means the transformation is not taken into account when calculating how much space this widget’s child (and thus this widget) consumes.

Constructor vs. transform property

  • Transform.scale
  • Transform.translate
  • Transform.rotate (we will discuss it in the next story)

Scale

Transform.scale constructor

scale argument

The scale argument must not be null. It gives the scalar by which to multiply the x and y axes.

alignment argument

The alignment controls the origin of the scale; by default, this is the center of the box.

Before transforming…

Scale down (0.5) with the origin in the top-left corner

Transform.scale(
alignment: Alignment.topLeft,
scale: 0.50,
child: Container(
color: Colors.teal,
width: 180,
height: 180,
),
)
MaterialApp(
title: 'MyApp',
home: Scaffold(
appBar: AppBar(
title: Text('Translate'),
),
body: Transform.scale(
alignment: Alignment.topLeft,
scale: 0.50,
child: Container(
color: Colors.teal,
width: 180,
height: 180,
),
),
),
)

Scale down (0.5) with the origin in the bottom-right corner

Transform.scale(
alignment: Alignment.bottomRight,
scale: 0.50,
child: Container(
color: Colors.teal,
width: 180,
height: 180,
),
)

Scale down (0.5) with the origin in the center

Transform.scale(
alignment: Alignment.center,
scale: 0.50,
child: Container(
color: Colors.teal,
width: 180,
height: 180,
),
)

Scale-up (1.7) with the origin in the top-left corner

Black entities are informative, do not belong to the screenshot.
Transform.scale(
alignment: Alignment.topLeft,
scale: 1.70,
child: Container(
color: Colors.teal,
width: 180,
height: 180,
),
)

Skew

There is not a Transform.skew constructor.

alignment argument

The alignment controls the origin of the skew; by default, this is the top-left corner (unlike the origin of the scale which remember that was the center)

Before transforming…

Container( //grey-background container
margin: EdgeInsets.only(top: 60, left: 60),
color: Color(0xFFCCCCCC), //grey
width: double.infinity,
height: 240,
alignment: Alignment.topLeft, //align its child (blue-container)

child: Container( // blue container
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(10.0),
),
width: 220,
height: 120,
),
)

Skew along the X-axis with positive alpha

Black entities are informative, do not belong to the screenshot
Container( //grey-background container
margin: EdgeInsets.only(top: 60, left: 60),
color: Color(0xFFCCCCCC), //grey
width: double.infinity,
height: 240,
alignment: Alignment.topLeft, //align its child (blue-container)

child: Transform(
transform: Matrix4.skewX(0.3),
child: Container(
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(10.0),
),
width: 220,
height: 120,
),
),
)

Skew along the X-axis with negative alpha

Black entities are informative, do not belong to the screenshot.
Container( //grey-background container
margin: EdgeInsets.only(top: 60, left: 60),
color: Color(0xFFCCCCCC), //grey
width: double.infinity,
height: 240,
alignment: Alignment.topLeft, //align its child (blue-container)

child: Transform(
transform: Matrix4.skewX(-0.3),
child: Container(
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(10.0),
),
width: 220,
height: 120,
),
),
)

Changing the origin of the skew

Black entities are informative, do not belong to the screenshot.
Container( //grey-background container
margin: EdgeInsets.only(top: 60, left: 60),
color: Color(0xFFCCCCCC),
width: double.infinity,
height: 240,
alignment: Alignment.topLeft, //align its child (blue-container)
child: Transform(
transform: Matrix4.skewX(-0.3),
alignment: Alignment.bottomLeft, //changing the origin
child: Container(
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(10.0),
),
width: 220,
height: 120,
),
),
)

Skewing along the Y-axis

Black entities are informative, do not belong to the screenshot.
Container( //grey-background container
margin: EdgeInsets.only(top: 60, left: 60),
color: Color(0xFFCCCCCC),
width: double.infinity,
height: 240,
alignment: Alignment.topLeft, //align its child (blue-container)

child: Transform(
transform: Matrix4.skewY(0.3),
child: Container(
decoration: BoxDecoration(
color: Colors.lightBlue,
borderRadius: BorderRadius.circular(10.0),
),
width: 220,
height: 120,
),
),
)

Translate

Transform.translate constructor

offset argument

It must not be null. It specifies the translation.

Before translating…

Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
)

Translate in the X-axis

Black entities are informative, do not belong to the screenshot.
Transform.translate(
offset: Offset(100, 0),
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
),
)

Translate in the Y-axis

Black entities are informative, do not belong to the screenshot.
Transform.translate(
offset: Offset(0, 100),
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
),
)

Translate in both X and Y axes

Black entities are informative, do not belong to the screenshot.
Transform.translate(
offset: Offset(100, 100),
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
),
)

Translate and compose

Black entities are informative, do not belong to the screenshot.
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
child: Transform.translate(
offset: Offset(0, 60),
child: Container(
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
child: Transform.translate(
offset: Offset(0, 60),
child: Container(
decoration: BoxDecoration(
color: Colors.amber,
borderRadius: BorderRadius.circular(15.0),
),
width: 100,
height: 100,
),
),
),
),
)

CHALLENGES

The first part of the challenge

Left-design code:

Center(
child: Text(
'Scale',
style: TextStyle(
fontSize: 36,
color: Colors.black,
),
),
)

My solution

Center(
child: Transform.scale(
alignment: Alignment.center,
scale: 24,
child: Text(
'Scale',
style: TextStyle(
fontSize: 36,
color: Colors.black,
),
),
),
)

The second part of the challenge

My solution

Center(
child: Transform.scale(
alignment: Alignment.center,
scale: (1 / 24).toDouble(),
child: Transform.scale(
alignment: Alignment.center,
scale: 24,
child: Text(
'Scale',
style: TextStyle(
fontSize: 36,
color: Colors.black,
),
),
),
),
)

The challenge

const colors = [
Color(0xFF2257A3),
Color(0xFF2E22A3),
Color(0xFF6E22A3),
Color(0xFFA32296),
Color(0xFFA32357),
Color(0xFFA32D22)
];

My solution

class Challenge extends StatelessWidget {

final List<Color> colors;

Challenge(this.colors);
@override
Widget build(BuildContext context) {
return getWidget(0);
}

Widget getWidget(int index) {
if (index < colors.length) {
return Transform.translate(
offset: (index == 0) ? Offset(0, 0) : Offset(40, 40),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: colors[index],
),
width: 100,
height: 100,
child: getWidget(index + 1),
),
);
}
else
return null;
}
}
const kColors = [
Color(0xFF2257A3),
Color(0xFF2E22A3),
Color(0xFF6E22A3),
Color(0xFFA32296),
Color(0xFFA32357),
Color(0xFFA32D22)
];
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Challenge'),
),
body: Challenge(kColors),
),
),
);
}
If you have found this article enjoyable or it has helped you in some way, give me many 👏.Thanks for reading me!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store