flutter 当我们使用LongPressDraggable拖动小部件时,流数据从StreamBuilder中消失

vqlkdk9b  于 2023-06-30  发布在  Flutter
关注(0)|答案(1)|浏览(147)
  • 我使用LongPressDraggable创建了一个小部件。当我执行拖动操作时,流数据(StreamBuilder)从屏幕上消失。附加代码供您参考。*
    main.dart

在main.dart中,我定义了一个Stack小部件。在Stack小部件中,我定义了一个BaseWidget。基本小部件将TextStream小部件作为参数

import 'package:example/base_widget.dart';
import 'package:example/text_stream.dart';
import 'package:example/widget_view_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
      MultiProvider(providers: [
        ChangeNotifierProvider<WidgetViewModel>(
          create: (context) => WidgetViewModel(),
        ),
      ], child: const MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {

    WidgetViewModel widgetViewModel = context.read<WidgetViewModel>();

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Stack(
          children: <Widget>[
            BaseWidget(widgetItem: TextStream(value: widgetViewModel.textStream))
            ]
        ),
      ),
    );
  }
}

text_stream.dart

在text_stream.dart中,我定义了一个StreamBuilder,它将字符串的Stream作为它的参数。StreamBuilder在找到快照数据时返回TextWidget

import 'package:example/text_widget.dart';
import 'package:flutter/material.dart';

class TextStream extends StatefulWidget {
  final Stream<String> value;

  const TextStream({Key? key, required this.value}) : super(key: key);

  @override
  State<TextStream> createState() => _TextStreamState();
}

class _TextStreamState extends State<TextStream> {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<String>(
        stream: widget.value,
        builder: (context, snapshot) {
          if(snapshot.hasData){
            return TextWidget(text: snapshot.data!);
          }
          else {
            return const TextWidget(text: "Unknown");
          }
        });
  }
}

base_widget.dart

base_widget.dart包含LongPressDraggable和Positioned widget的实现。

import 'package:flutter/material.dart';

class BaseWidget extends StatefulWidget {
  final Widget widgetItem;

  const BaseWidget({Key? key, required this.widgetItem}) : super(key: key);

  @override
  State<BaseWidget> createState() => _BaseWidgetState();
}

class _BaseWidgetState extends State<BaseWidget> {
  double _x = 0.0;
  double _y = 0.0;

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: _x,
      top: _y,
      child: LongPressDraggable(
          feedback: widget.widgetItem,
          childWhenDragging: const SizedBox(),
          onDragEnd: (details) {
            setState(() {
              _x = details.offset.dx;
              _y = details.offset.dy;
            });
          },
          child: widget.widgetItem,

          ),
    );
  }
}

widget_view_model.dart

它包含EventChannel(客户端)的实现,它从Android主机获取值。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';

class WidgetViewModel extends ChangeNotifier {
  static const textEvent = EventChannel("com.example.example");

  Stream<String> textStream = textEvent.receiveBroadcastStream().distinct().map((event) {
    return event as String;
  });
}

text_widget.dart

它包含容器和文本小部件的实现。TextStream类将String值作为其输入参数。

import 'package:flutter/material.dart';

class TextWidget extends StatefulWidget {
  final String text;
  const TextWidget({Key? key, required this.text}) : super(key: key);

  @override
  State<TextWidget> createState() => _TextWidgetState();
}

class _TextWidgetState extends State<TextWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.amber,
      height: 100.0,
      width: 100.0,
      child: Text(
        widget.text,
        style: const TextStyle(fontSize: 20.0),
      ),
    );
  }
}

MainActivity.kt

它实现了EventChannel流处理程序和事件接收器,以在Flutter端传递值。

package com.example.example

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel

class MainActivity: FlutterActivity() {
    private val textEvent = "com.example.example"

    private var textEventSink: EventChannel.EventSink? = null

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        EventChannel(flutterEngine.dartExecutor.binaryMessenger,textEvent).setStreamHandler(
            object: EventChannel.StreamHandler {
                override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
                    textEventSink = events
                    textEventSink?.success("Harsh")
                }

                override fun onCancel(arguments: Any?) {
                    textEventSink?.success("Harsh")
                    textEventSink = null
                }

            }
        )
    }
}
dl5txlt9

dl5txlt91#

流数据(StreamBuilder)没有消失,只是正在重建并等待流的下一个值,但您的textStream在第一次构建后没有发出任何值,如果流继续发出值,您的代码就很好。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'example/base_widget.dart';
import 'example/text_stream.dart';
import 'example/widget_view_model.dart';

void main() {
  /// stack overflow:
  /// https://stackoverflow.com/questions/76571124/stream-data-disappears-from-streambuilder-when-we-drag-a-widget-using-longpressd
  ///
  runApp(MultiProvider(providers: [
    ChangeNotifierProvider<WidgetViewModel>(
      create: (context) => WidgetViewModel(),
    ),
  ], child: const MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    WidgetViewModel widgetViewModel = context.read<WidgetViewModel>();
    
    /// [edit]
    Stream<String> countStream(int to) async* {
      for (int i = 1; i <= to; i++) {
        await Future.delayed(const Duration(seconds: 3));
        yield 'Seconds-> $i';
      }
    }
   /// [end edit]
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Stack(children: <Widget>[
          BaseWidget(widgetItem: TextStream(value: widgetViewModel.textStream)),
          BaseWidget(
              widgetItem:
                  TextStream(value: countStream(30).asBroadcastStream())) // listen custom stream
        ]),
      ),
    );
  }

//下面是我修改的一些代码,用于存储流值。
main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'example/base_widget.dart';
import 'example/text_stream.dart';
import 'example/widget_view_model.dart';

void main() {
  /// solve the stack overflow:
  /// https://stackoverflow.com/questions/76571124/stream-data-disappears-from-streambuilder-when-we-drag-a-widget-using-longpressd
  ///
  runApp(MultiProvider(providers: [
    ChangeNotifierProvider<WidgetViewModel>(
      create: (context) => WidgetViewModel(),
    ),
  ], child: const MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    WidgetViewModel widgetViewModel = context.read<WidgetViewModel>();

    Stream<String> countStream(int to) async* {
      for (int i = 1; i <= to; i++) {
        await Future.delayed(const Duration(seconds: 3));
        yield 'Seconds-> $i';
      }
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Stack(children: <Widget>[
          // BaseWidget(widgetItem: TextStream(value: widgetViewModel.textStream)),
          BaseWidget(
              valueMessenger:
                  ValueMessenger(value: widgetViewModel.textStream)),
          BaseWidget(
            valueMessenger: ValueMessenger(value: countStream(300)),
          ),
        ]),
      ),
    );
  }
}

text_widget.dart

import 'package:flutter/material.dart';

/// no any state in this widget.
class TextWidget extends StatelessWidget {
  final String text;
  const TextWidget({Key? key, required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.amber,
      height: 100.0,
      width: 100.0,
      child: Text(
        text,
        style: const TextStyle(fontSize: 20.0),
      ),
    );
  }
}

text_stream.dart

import 'package:flutter/material.dart';

import 'text_widget.dart';

class ValueMessenger extends ChangeNotifier {
  Widget? _currentWidget;
  final Stream<String> value;
  ValueMessenger({required this.value}) {
    value.listen((event) {
      setCurrentWidget(TextWidget(text: event));
    });
  }

  void setCurrentWidget(Widget widget) {
    _currentWidget = widget;
    notifyListeners();
  }

  Widget getCurrentWidget() {
    return _currentWidget ?? const TextWidget(text: 'Unknown');
  }
}

base_widget.dart

import 'package:flutter/material.dart';
import 'package:stack_overflow_stream/example/text_stream.dart';

class BaseWidget extends StatefulWidget {
  final ValueMessenger valueMessenger;

  const BaseWidget({Key? key, required this.valueMessenger}) : super(key: key);

  @override
  State<BaseWidget> createState() => _BaseWidgetState();
}

class _BaseWidgetState extends State<BaseWidget> {
  double _x = 0.0;
  double _y = 0.0;
  late Widget widgetItem;
  @override
  void initState() {

    widgetItem = widget.valueMessenger.getCurrentWidget();
    widget.valueMessenger.addListener(() {
      setState(() {
        widgetItem = widget.valueMessenger.getCurrentWidget();
      });
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: _x,
      top: _y,
      child: LongPressDraggable(
        feedback: widgetItem,
        childWhenDragging: const SizedBox(),
        onDragEnd: (details) {
          setState(() {
            _x = details.offset.dx;
            _y = details.offset.dy;
          });
        },
        child: widgetItem,
      ),
    );
  }
}

text_widget.dart

import 'package:flutter/material.dart';

/// no any state in this widget.
class TextWidget extends StatelessWidget {
  final String text;
  const TextWidget({Key? key, required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.amber,
      height: 100.0,
      width: 100.0,
      child: Text(
        text,
        style: const TextStyle(fontSize: 20.0),
      ),
    );
  }
}

注意!!此方法在onDrag期间仍然无法更新“feedback”参数。

相关问题