Skip to content

Updated Widget is sized wrong (but placed correctly) #345

@afandria

Description

@afandria

This is similar to an old issue from the old issue tracker. This new issue surfaced because of that old issue's fix (c44dd17). When child.parentData = null; is removed again, then we no longer see this new issue's behavior (though we do see the old one's).

Anyway, the example is 2 stacks that can be tapped to move up or down on the screen. Notably, the lower part of the screen will also wrap the Stack in a Listener, which causes problems when a Disk widget is moved from the bottom stack back to the top stack.

This is lib/main.dart.

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class Disk extends StatefulComponent {
  String name;
  Function cb;

  Disk(String name, bool useKey, this.cb) :
    super(key: useKey ? new GlobalObjectKey(name) : null),
    name = name;

  DiskState createState() => new DiskState();
}

class DiskState extends State<Disk> {
  Point _oldLocation;

  @override
  void initState() {
    print("init ${config.name}");
    super.initState();
    _checkPosition();
  }

  void _checkPosition() {
    scheduler.requestPostFrameCallback((Duration d) {
      print("Post Frame Callback of ${config.name} ${d}");
      Point newLocation = getGlobalPosition();
      print("Moved from ${_oldLocation} to ${newLocation}");
      setState(() {
        _oldLocation = newLocation;
      });
    });
  }

  @override
  void didUpdateConfig(Disk oldConfig) {
    print("Update ${oldConfig.name} to ${config.name}");
    _checkPosition();
  }

  Point getGlobalPosition() {
    RenderBox box = context.findRenderObject();
    return box.localToGlobal(Point.origin);
  }

  Widget build(BuildContext context) {
    return new InkWell(
      onTap: config.cb,
      child: new Container(
        decoration: new BoxDecoration(backgroundColor: Colors.blue[500]),
        width: 30.0,
        height: 30.0,
        child: new Text(config.name)
      )
    );
  }
}


class Holder extends StatefulComponent {
  HolderState createState() => new HolderState();
}

class HolderState extends State<Holder> {
  Map<String, bool> data = new Map<String, bool>();

  void initState() {
    super.initState();

    data["a"] = true;
    data["b"] = true;

  }

  Function _makeChangeDataCb(String name) {
    return () {
      setState(() {
        data[name] = !data[name];
      });
    };
  }

  Widget build(BuildContext context) {
    // Note1: Set to false to see the effect go away. Set to true, to see the shifted effect in printouts.
    bool useKey = true;

    List<Widget> trueKids = new List<Widget>();
    List<Widget> falseKids = new List<Widget>();
    data.forEach((String name, bool isTop) {
      Disk disk = new Disk(name, useKey, _makeChangeDataCb(name));

      Widget k = disk;

      // Note2: If you add "|| true", then the effect disappears. The widget tree must misalign for the effect to occur.
      if (!isTop) {
        // Note3: This listener gets in the way of the position computation and makes the transform occur twice during localToGlobal. But only when there is a key.
        k = new Listener(
          child: disk
        );
      }

      Widget kid = new Positioned(
        top: 5.0,
        left: 5.0,
        child: k
      );

      if (isTop) {
        trueKids.add(kid);
      } else {
        falseKids.add(kid);
      }
    });

    return new Column([
      new Container(
        decoration: new BoxDecoration(backgroundColor: Colors.red[500]),
        child: new Stack(trueKids),
        width: 60.0,
        height: 60.0
      ),
      new Container(
        decoration: new BoxDecoration(backgroundColor: Colors.red[500]),
        child: new Stack(falseKids),
        width: 60.0,
        height: 60.0
      ),
      new FlatButton(child: new Text("Debug"), onPressed: debugDumpApp)
    ]);
  }
}

void main() {

  runApp(new Holder());
}

You can use this pubspec.yaml and pub run sky_tools start

name: keyedWidgetsPosition
dependencies:
  flutter: "0.0.18"
  sky_tools: any

Or you can run the example with the new way of launching flutter apps.

Metadata

Metadata

Assignees

Labels

c: regressionIt was better in the past than it is nowframeworkflutter/packages/flutter repository. See also f: labels.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions