transform_test.dart 11.1 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Hixie's avatar
Hixie committed
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7 8
import 'dart:math' as math;

Adam Barth's avatar
Adam Barth committed
9
import 'package:flutter_test/flutter_test.dart';
10
import 'package:flutter/rendering.dart';
11
import 'package:flutter/widgets.dart';
12
import 'package:vector_math/vector_math_64.dart';
13 14

void main() {
15
  testWidgets('Transform origin', (WidgetTester tester) async {
16
    bool didReceiveTap = false;
17
    await tester.pumpWidget(
18
      Directionality(
19
        textDirection: TextDirection.ltr,
20
        child: Stack(
21
          children: <Widget>[
22
            Positioned(
23 24
              top: 100.0,
              left: 100.0,
25
              child: Container(
26 27 28 29
                width: 100.0,
                height: 100.0,
                color: const Color(0xFF0000FF),
              ),
30
            ),
31
            Positioned(
32 33
              top: 100.0,
              left: 100.0,
34
              child: Container(
35 36
                width: 100.0,
                height: 100.0,
37 38
                child: Transform(
                  transform: Matrix4.diagonal3Values(0.5, 0.5, 1.0),
39
                  origin: const Offset(100.0, 50.0),
40
                  child: GestureDetector(
41 42 43
                    onTap: () {
                      didReceiveTap = true;
                    },
44
                    child: Container(
45 46
                      color: const Color(0xFF00FFFF),
                    ),
47 48 49 50
                  ),
                ),
              ),
            ),
51 52
          ],
        ),
53
      ),
54
    );
55

56
    expect(didReceiveTap, isFalse);
57
    await tester.tapAt(const Offset(110.0, 110.0));
58
    expect(didReceiveTap, isFalse);
59
    await tester.tapAt(const Offset(190.0, 150.0));
60
    expect(didReceiveTap, isTrue);
61
  });
Hixie's avatar
Hixie committed
62

63
  testWidgets('Transform alignment', (WidgetTester tester) async {
64
    bool didReceiveTap = false;
65
    await tester.pumpWidget(
66
      Directionality(
67
        textDirection: TextDirection.ltr,
68
        child: Stack(
69
          children: <Widget>[
70
            Positioned(
71 72
              top: 100.0,
              left: 100.0,
73
              child: Container(
74 75 76 77
                width: 100.0,
                height: 100.0,
                color: const Color(0xFF0000FF),
              ),
78
            ),
79
            Positioned(
80 81
              top: 100.0,
              left: 100.0,
82
              child: Container(
83 84
                width: 100.0,
                height: 100.0,
85 86
                child: Transform(
                  transform: Matrix4.diagonal3Values(0.5, 0.5, 1.0),
87
                  alignment: const Alignment(1.0, 0.0),
88
                  child: GestureDetector(
89 90 91
                    onTap: () {
                      didReceiveTap = true;
                    },
92
                    child: Container(
93 94
                      color: const Color(0xFF00FFFF),
                    ),
95 96 97 98
                  ),
                ),
              ),
            ),
99 100
          ],
        ),
101
      ),
102
    );
Hixie's avatar
Hixie committed
103

104
    expect(didReceiveTap, isFalse);
105
    await tester.tapAt(const Offset(110.0, 110.0));
106
    expect(didReceiveTap, isFalse);
107
    await tester.tapAt(const Offset(190.0, 150.0));
108
    expect(didReceiveTap, isTrue);
Hixie's avatar
Hixie committed
109 110
  });

111 112 113 114
  testWidgets('Transform AlignmentDirectional alignment', (WidgetTester tester) async {
    bool didReceiveTap = false;

    Widget buildFrame(TextDirection textDirection, AlignmentGeometry alignment) {
115
      return Directionality(
116
        textDirection: textDirection,
117
        child: Stack(
118
          children: <Widget>[
119
            Positioned(
120 121
              top: 100.0,
              left: 100.0,
122
              child: Container(
123 124 125 126 127
                width: 100.0,
                height: 100.0,
                color: const Color(0xFF0000FF),
              ),
            ),
128
            Positioned(
129 130
              top: 100.0,
              left: 100.0,
131
              child: Container(
132 133
                width: 100.0,
                height: 100.0,
134 135
                child: Transform(
                  transform: Matrix4.diagonal3Values(0.5, 0.5, 1.0),
136
                  alignment: alignment,
137
                  child: GestureDetector(
138 139 140
                    onTap: () {
                      didReceiveTap = true;
                    },
141
                    child: Container(
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
                      color: const Color(0xFF00FFFF),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      );
    }

    await tester.pumpWidget(buildFrame(TextDirection.ltr, AlignmentDirectional.centerEnd));
    didReceiveTap = false;
    await tester.tapAt(const Offset(110.0, 110.0));
    expect(didReceiveTap, isFalse);
    await tester.tapAt(const Offset(190.0, 150.0));
    expect(didReceiveTap, isTrue);

    await tester.pumpWidget(buildFrame(TextDirection.rtl, AlignmentDirectional.centerStart));
    didReceiveTap = false;
    await tester.tapAt(const Offset(110.0, 110.0));
    expect(didReceiveTap, isFalse);
    await tester.tapAt(const Offset(190.0, 150.0));
    expect(didReceiveTap, isTrue);

    await tester.pumpWidget(buildFrame(TextDirection.ltr, AlignmentDirectional.centerStart));
    didReceiveTap = false;
    await tester.tapAt(const Offset(190.0, 150.0));
    expect(didReceiveTap, isFalse);
    await tester.tapAt(const Offset(110.0, 150.0));
    expect(didReceiveTap, isTrue);

    await tester.pumpWidget(buildFrame(TextDirection.rtl, AlignmentDirectional.centerEnd));
    didReceiveTap = false;
    await tester.tapAt(const Offset(190.0, 150.0));
    expect(didReceiveTap, isFalse);
    await tester.tapAt(const Offset(110.0, 150.0));
    expect(didReceiveTap, isTrue);
  });

182
  testWidgets('Transform offset + alignment', (WidgetTester tester) async {
183
    bool didReceiveTap = false;
184
    await tester.pumpWidget(
185
      Directionality(
186
        textDirection: TextDirection.ltr,
187
        child: Stack(
188
          children: <Widget>[
189
            Positioned(
190 191
              top: 100.0,
              left: 100.0,
192
              child: Container(
193 194 195 196 197
                width: 100.0,
                height: 100.0,
                color: const Color(0xFF0000FF),
              ),
            ),
198
            Positioned(
199 200
              top: 100.0,
              left: 100.0,
201
              child: Container(
202 203
                width: 100.0,
                height: 100.0,
204 205
                child: Transform(
                  transform: Matrix4.diagonal3Values(0.5, 0.5, 1.0),
206
                  origin: const Offset(100.0, 0.0),
207
                  alignment: const Alignment(-1.0, 0.0),
208
                  child: GestureDetector(
209 210 211
                    onTap: () {
                      didReceiveTap = true;
                    },
212
                    child: Container(
213 214 215
                      color: const Color(0xFF00FFFF),
                    ),
                  ),
216 217 218
                ),
              ),
            ),
219
          ],
220
        ),
221 222
      ),
    );
Hixie's avatar
Hixie committed
223

224
    expect(didReceiveTap, isFalse);
225
    await tester.tapAt(const Offset(110.0, 110.0));
226
    expect(didReceiveTap, isFalse);
227
    await tester.tapAt(const Offset(190.0, 150.0));
228
    expect(didReceiveTap, isTrue);
Hixie's avatar
Hixie committed
229
  });
230 231 232

  testWidgets('Composited transform offset', (WidgetTester tester) async {
    await tester.pumpWidget(
233 234
      Center(
        child: SizedBox(
235 236
          width: 400.0,
          height: 300.0,
237 238 239 240
          child: ClipRect(
            child: Transform(
              transform: Matrix4.diagonal3Values(0.5, 0.5, 1.0),
              child: Opacity(
241
                opacity: 0.9,
242
                child: Container(
243
                  color: const Color(0xFF00FF00),
244 245 246 247 248 249 250 251
                ),
              ),
            ),
          ),
        ),
      ),
    );

252
    final List<Layer> layers = tester.layers
253 254 255
      ..retainWhere((Layer layer) => layer is TransformLayer);
    expect(layers.length, 2);
    // The first transform is from the render view.
256
    final TransformLayer layer = layers[1] as TransformLayer;
257
    final Matrix4 transform = layer.transform;
258
    expect(transform.getTranslation(), equals(Vector3(100.0, 75.0, 0.0)));
259
  });
260 261 262

  testWidgets('Transform.rotate', (WidgetTester tester) async {
    await tester.pumpWidget(
263
      Transform.rotate(
264
        angle: math.pi / 2.0,
265
        child: Opacity(opacity: 0.5, child: Container()),
266 267 268 269 270 271 272
      ),
    );

    final List<Layer> layers = tester.layers
      ..retainWhere((Layer layer) => layer is TransformLayer);
    expect(layers.length, 2);
    // The first transform is from the render view.
273
    final TransformLayer layer = layers[1] as TransformLayer;
274 275 276 277 278 279 280 281
    final Matrix4 transform = layer.transform;
    expect(transform.storage, <dynamic>[
      moreOrLessEquals(0.0), 1.0, 0.0, 0.0,
      -1.0, moreOrLessEquals(0.0), 0.0, 0.0,
      0.0, 0.0, 1.0, 0.0,
      700.0, -100.0, 0.0, 1.0,
    ]);
  });
282 283 284

  testWidgets('applyPaintTransform of Transform in Padding', (WidgetTester tester) async {
    await tester.pumpWidget(
285
      Padding(
286 287 288 289 290 291
        padding: const EdgeInsets.only(
          left: 30.0,
          top: 20.0,
          right: 50.0,
          bottom: 70.0,
        ),
292 293
        child: Transform(
          transform: Matrix4.diagonal3Values(2.0, 2.0, 2.0),
294 295 296 297 298 299
          child: const Placeholder(),
        ),
      ),
    );
    expect(tester.getTopLeft(find.byType(Placeholder)), const Offset(30.0, 20.0));
  });
300 301 302

  testWidgets('Transform.translate', (WidgetTester tester) async {
    await tester.pumpWidget(
303
      Transform.translate(
304
        offset: const Offset(100.0, 50.0),
305
        child: Opacity(opacity: 0.5, child: Container()),
306 307 308 309 310 311 312 313 314 315 316 317
      ),
    );

    // This should not cause a transform layer to be inserted.
    final List<Layer> layers = tester.layers
      ..retainWhere((Layer layer) => layer is TransformLayer);
    expect(layers.length, 1); // only the render view
    expect(tester.getTopLeft(find.byType(Container)), const Offset(100.0, 50.0));
  });

  testWidgets('Transform.scale', (WidgetTester tester) async {
    await tester.pumpWidget(
318
      Transform.scale(
319
        scale: 2.0,
320
        child: Opacity(opacity: 0.5, child: Container()),
321 322 323 324 325 326 327
      ),
    );

    final List<Layer> layers = tester.layers
      ..retainWhere((Layer layer) => layer is TransformLayer);
    expect(layers.length, 2);
    // The first transform is from the render view.
328
    final TransformLayer layer = layers[1] as TransformLayer;
329 330 331 332 333 334 335 336 337
    final Matrix4 transform = layer.transform;
    expect(transform.storage, <dynamic>[
      // These are column-major, not row-major.
      2.0, 0.0, 0.0, 0.0,
      0.0, 2.0, 0.0, 0.0,
      0.0, 0.0, 1.0, 0.0,
      -400.0, -300.0, 0.0, 1.0, // it's 1600x1200, centered in an 800x600 square
    ]);
  });
Emmanuel Garcia's avatar
Emmanuel Garcia committed
338 339

  testWidgets('Translated child into translated box - hit test', (WidgetTester tester) async {
340
    final GlobalKey key1 = GlobalKey();
Emmanuel Garcia's avatar
Emmanuel Garcia committed
341 342
    bool _pointerDown = false;
    await tester.pumpWidget(
343
      Transform.translate(
Emmanuel Garcia's avatar
Emmanuel Garcia committed
344
        offset: const Offset(100.0, 50.0),
345
        child: Transform.translate(
Emmanuel Garcia's avatar
Emmanuel Garcia committed
346
          offset: const Offset(1000.0, 1000.0),
347
          child: Listener(
Emmanuel Garcia's avatar
Emmanuel Garcia committed
348 349 350
            onPointerDown: (PointerDownEvent event) {
              _pointerDown = true;
            },
351
            child: Container(
Emmanuel Garcia's avatar
Emmanuel Garcia committed
352 353
              key: key1,
              color: const Color(0xFF000000),
354 355 356
            ),
          ),
        ),
Emmanuel Garcia's avatar
Emmanuel Garcia committed
357 358 359 360 361 362
      ),
    );
    expect(_pointerDown, isFalse);
    await tester.tap(find.byKey(key1));
    expect(_pointerDown, isTrue);
  });
363
}