简体   繁体   English

Flutter 在滚动 SingleChildScrollView 的同时更改堆栈中可拖动小部件的偏移量

[英]Flutter change offset of draggable widgets in a stack at the same time as scrolling a SingleChildScrollView

I have a stack of widgets in Flutter.我在 Flutter 中有一堆小部件。 The lowest stack is a large image that is contained inside SingleChildScrollView.最低的堆栈是包含在 SingleChildScrollView 中的大图像。 I've set up a ScrollController so I know when the image has been horizontally scrolled in the view.我已经设置了一个 ScrollController,所以我知道图像何时在视图中水平滚动。

Next in the stack I have several Positioned widgets (these are draggable so that they can moved around independent of each other).接下来在堆栈中,我有几个定位小部件(这些是可拖动的,因此它们可以相互独立地移动)。

What I'd like to do is when the SingleChildScrollView is scrolled, I'd like to update the position of each of the positioned widgets higher up the stack.我想做的是当 SingleChildScrollView 滚动时,我想更新堆栈中每个定位的小部件的 position 。

I've considered Stream, rebuildAllChildren and ValueNotifier but all seem quite complex for what, on the face of it, should be quite a simple thing to achieve.我考虑过 Stream、rebuildAllChildren 和 ValueNotifier,但从表面上看,这一切似乎都相当复杂,但实现起来应该很简单。 I'm probably missing something very obvious somewhere!我可能在某处遗漏了一些非常明显的东西!

Here's my code so far:到目前为止,这是我的代码:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LayoutScreen extends StatefulWidget {
  LayoutScreen();

  @override
  _LayoutScreenState createState() => _LayoutScreenState();
}

class _LayoutScreenState extends State<LayoutScreen> {
  ScrollController _controller;
  Offset boxoneposition;
  BuildContext context;

  _scrollListener() {
    print(_controller.offset);
    boxoneposition=Offset(100.0, 100);
    setState(() {
      print(boxoneposition);
      // this was a test - the value of boxoneposition is updated, however the view isn't
    });
 }

  @override
  void initState() {
    _controller = ScrollController();
    _controller.addListener(_scrollListener);

    boxoneposition = Offset(0.0, 30);

    super.initState();
  }

  DragBox boxOne() {
    // Trying to set up outside of widget build
    return DragBox(boxoneposition, 'Box One Yep', Colors.blueAccent, 1);
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[

        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          controller: _controller,
          child: Container(
            width: 1000,
            height: 1000,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('assets/images/logo.png'),
                fit: BoxFit.cover,
                repeat: ImageRepeat.noRepeat,
              ),
            ),
          ),
        ),
        //DragBox(boxoneposition, 'Box One', Colors.blueAccent, 1),
        boxOne(),
        DragBox(Offset(200.0, 50.0), 'Box Two', Colors.orange, 2),
        DragBox(Offset(300.0, 80.0), 'Box Three', Colors.lightGreen, 3),
      ],
    );
  }
}

class DragBox extends StatefulWidget {
  final Offset initPos;
  final String label;
  final Color itemColor;
  final int boxnumber;

  DragBox(this.initPos, this.label, this.itemColor, this.boxnumber);

  @override
  DragBoxState createState() => DragBoxState();
}

class DragBoxState extends State<DragBox> {
  Offset position = Offset(0.0, 0.0);
  String imagePath="";

  @override
  void initState() {
    super.initState();
    position = widget.initPos;
  }

  getBoxPic() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      String key='picture'+widget.boxnumber.toString();
      imagePath=prefs.getString(key);
    });
    print(imagePath);
    return File(imagePath);
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: position.dx,
      top: position.dy,
      child: Draggable(
        data: widget.itemColor,
        child: Container(
          width: 100.0,
          height: 100.0,
          color: widget.itemColor,
          child: Center(
            child: 
            Image.asset('assets/images/logo.png')
          ),
        ),
        onDragStarted: () {
          setState(() {
            print("Foobar");
          });
        },
        onDraggableCanceled: (velocity, offset) {
          setState(() {
            position = offset;
            if (widget.boxnumber==1) {
              print("Wibble");
            }
          });
        },
        feedback: Container(
          width: 120.0,
          height: 120.0,
          color: widget.itemColor.withOpacity(0.5),
          child: Center(
            child: Text(
              widget.label,
              style: TextStyle(
                color: Colors.white,
                decoration: TextDecoration.none,
                fontSize: 18.0,
              ),
            ),
          ),
        ),
      )
    );
  }
}

Any help greatly appreciated!非常感谢任何帮助!

I was being a fool.我是个傻瓜。 Funny how walking away from something overnight and coming back to it clears the fog!有趣的是如何在一夜之间离开某事并回到它清除迷雾!

I sorted this out by simply placing an entire stack into the SingleChildScrollView.我通过简单地将整个堆栈放入 SingleChildScrollView 来解决这个问题。 The scrollview is wider and horizontally scrollable and the rest of the elements in the stack correctly maintain their positons even if the scrollview is moved and they disappear off screen.滚动视图更宽且可水平滚动,并且堆栈中元素的 rest 正确地保持其位置,即使滚动视图被移动并且它们从屏幕上消失。

The solution was very simple.解决方案非常简单。 For completeness, here's the updated code:为了完整起见,这里是更新的代码:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LayoutScreen extends StatefulWidget {
  LayoutScreen();

  @override
  _LayoutScreenState createState() => _LayoutScreenState();
}

class _LayoutScreenState extends State<LayoutScreen> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Arrange your images'),
        backgroundColor: Colors.orange,
      ),
      body: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Stack(
          children: <Widget>[
            Container(
              width: 1000,
              height: 1000,
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: AssetImage('assets/images/background.jpg'),
                  fit: BoxFit.cover,
                  repeat: ImageRepeat.noRepeat,
                ),
              ),
            ),
            DragBox(Offset(100.0, 10.0), 'Box One', Colors.blueAccent, 1),
            DragBox(Offset(200.0, 50.0), 'Box Two', Colors.orange, 2),
            DragBox(Offset(300.0, 80.0), 'Box Three', Colors.lightGreen, 3),
          ]
        ),
      )
    );
  }
}

class DragBox extends StatefulWidget {
  final Offset initPos;
  final String label;
  final Color itemColor;
  final int boxnumber;

  DragBox(this.initPos, this.label, this.itemColor, this.boxnumber);

  @override
  DragBoxState createState() => DragBoxState();
}

class DragBoxState extends State<DragBox> {
  Offset position = Offset(0.0, 0.0);
  String imagePath="";

  @override
  void initState() {
    super.initState();
    position = widget.initPos;
  }

  getBoxPic() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      String key='picture'+widget.boxnumber.toString();
      imagePath=prefs.getString(key);
    });
    print(imagePath);
    return File(imagePath);
  }
@override
  Widget build(BuildContext context) {
    return Positioned(
      left: position.dx,
      top: position.dy,
      child: Draggable(
        data: widget.itemColor,
        child: Container(
          width: 100.0,
          height: 100.0,
          color: widget.itemColor,
          child: Center(
            child: 
            Image.asset('assets/images/logo.png')
          ),
        ),
        onDragStarted: () {
          setState(() {
            print("Foobar");
          });
        },
        onDraggableCanceled: (velocity, offset) {
          setState(() {
            position = offset;
            if (widget.boxnumber==1) {
              print("Wibble");
            }
          });
        },
        feedback: Container(
          width: 120.0,
          height: 120.0,
          color: widget.itemColor.withOpacity(0.5),
          child: Center(
            child: Text(
              widget.label,
              style: TextStyle(
                color: Colors.white,
                decoration: TextDecoration.none,
                fontSize: 18.0,
              ),
            ),
          ),
        ),
      )
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM