如何从小部件传回数据?

时间:2019-09-20 19:07:18

标签: flutter dart

我有一个屏幕,用户可以在其中添加位置。在这里,我将所有小部件都分成了自己的文件,如下所示;

import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:fluttershare/pages/location/location_help_screen.dart';
import 'package:fluttershare/widgets/common_widgets/customDivider.dart';
import 'package:uuid/uuid.dart';

import '../../widgets/camp_type_select.dart';
import '../../widgets/extra_location_notes.dart';
import '../../widgets/location_input.dart';
import '../../widgets/opening_times.dart';
import '../../widgets/post_media.dart';
import '../../widgets/space_avalibility.dart';
import '../../widgets/utility_type_select.dart';
import '../../widgets/width_restriction.dart';
import '../../widgets/height_restriction.dart';
import '../../models/locations.dart';
import '../../models/user.dart';

import '../home.dart';

class AddNewLocation extends StatefulWidget {
  static const routeName = '/add-new-location';
  final User currentUser;
  AddNewLocation({this.currentUser});

  _AddNewLocationState createState() => _AddNewLocationState();
}

class _AddNewLocationState extends State<AddNewLocation> {
  String postId = Uuid().v4();
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  PlaceLocation _pickedLocation;
  int storyPostCount = 0;
  bool isLoading = false;

  void _selectPlace(double lat, double lng) {
    _pickedLocation = PlaceLocation(lattitude: lat, longitude: lng);
  }

  getLocationPostCount() async {
    setState(() {
      isLoading = true;
    });
    QuerySnapshot snapshot = await locationPostRef
        .document(currentUser.id)
        .collection('user_location_posts')
        .getDocuments();
    setState(() {
      storyPostCount = snapshot.documents.length;
    });
  }

  createLocationPostInFirestore(
      {String mediaUrl,
      String description,
      double heightRestriction,
      double widthRestriction}) {
    locationPostRef
        .document(currentUser.id)
        .collection("user_location_posts")
        .document(postId)
        .setData({
      "postId": postId,
      "ownerId": currentUser.id,
      "username": currentUser.username,
      "description": description,
      "timestamp": timestamp,
      "lattitude": _pickedLocation.lattitude,
      "longitude": _pickedLocation.longitude,
      "max_height": heightRestrictionValue.toStringAsFixed(0),
      "max_width": widthRestrictionValue.toStringAsFixed(0),
    });
  }

  handlePostSubmit() {
    createLocationPostInFirestore(
      heightRestriction: heightRestrictionValue,
      widthRestriction: widthRestrictionValue,
    );
    SnackBar snackbar = SnackBar(
      content: Text("Profile Updated"),
    );
    _scaffoldKey.currentState.showSnackBar(snackbar);
    setState(() {
      postId = Uuid().v4();
    });
  }

  buildUploadUserHeader() {
    return Container(
      margin: EdgeInsets.only(bottom: 10),
      height: 200,
      child: Row(
        children: <Widget>[
          Expanded(
            flex: 2,
            child: Container(
              color: Colors.blue,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  ListTile(
                    leading: CircleAvatar(
                        backgroundImage:
                            CachedNetworkImageProvider(currentUser.photoUrl)),
                  ),
                ],
              ),
            ),
          ),
          Expanded(
            flex: 6,
            child: Container(
              color: Colors.pink,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                mainAxisSize: MainAxisSize.max,
                children: <Widget>[
                  Text(currentUser.displayName),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  buildCampUploadForm() {
    return Container(
        child: SingleChildScrollView(
      child: Column(
        children: <Widget>[
          //buildUploadUserHeader(), //TODO: This is the profile header that is dissabled for now. Work on possibly a header in the future.
          Container(
            padding: EdgeInsets.all(15),
            child: Column(
              children: <Widget>[
                CampTypeSelect(),
                CustomDivider(),
                LocationInput(_selectPlace),
                CustomDivider(),
                HeightRestriction(),
                WidthRestriction(),
                SpaceAvalibility(),
                OpeningTimes(),
                CustomDivider(),
                PostMedia(),
                CustomDivider(),
                UtilityServices(),
                CustomDivider(),
                ExtraLocationNotes(),
                Container(
                  height: 80,
                  margin: EdgeInsets.only(top: 10, bottom: 10),
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: FlatButton(
                          color: Colors.black,
                          onPressed: () => handlePostSubmit(),
                          child: Text(
                            "SUBMIT",
                            style: Theme.of(context).textTheme.display2,
                          ),
                          padding: EdgeInsets.all(20),
                        ),
                      )
                    ],
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: const Text(
          'Add New Location',
          style: TextStyle(color: Colors.black),
        ),
        actions: <Widget>[
          // action button
          IconButton(
            icon: Icon(Icons.info_outline),
            color: Colors.black,
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                    fullscreenDialog: true,
                    builder: (context) => LocationSubmitHelpScreen()),
              );
            },
          ),
          // action button
          IconButton(
            icon: Icon(Icons.close),
            color: Colors.black,
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
        ],
      ),
      body: buildCampUploadForm(),
      backgroundColor: Colors.white,
    );
  }
}

我想做的是从小部件ExtraLocationNotes()返回数据  到函数createLocationPostInFirestore()。

对于上下文,这就是我的小部件的样子;

    import 'package:flutter/material.dart';

import 'common_widgets/custom_form_card.dart';

class ExtraLocationNotes extends StatefulWidget {
  _ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}

class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
  TextEditingController descriptionController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return CustomFormCard(
      child: Column(
        children: <Widget>[
          Container(
            child: Row(
              children: <Widget>[
                Text(
                  "EXTRA INFORMATION",
                  style: TextStyle(
                    fontSize: 18.0,
                    color: Colors.black,
                    fontWeight: FontWeight.w400,
                    letterSpacing: 2.0,
                  ),
                ),
              ],
            ),
          ),
          SizedBox(height: 20),
          TextFormField(
            controller: descriptionController,
            maxLines: 6,
            maxLength: 250,
            maxLengthEnforced: true,
            style:
                new TextStyle(fontSize: 18.0, height: 1.3, color: Colors.black),
            decoration: const InputDecoration(
              hintText:
                  "Please write a description of this location for fellow travellers.",
              alignLabelWithHint: true,
              border: OutlineInputBorder(
                borderRadius: BorderRadius.only(),
                borderSide: BorderSide(color: Colors.black),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

如何将数据传递回父窗口小部件?

2 个答案:

答案 0 :(得分:1)

您需要回调,该回调将在子窗口小部件中触发,然后值将在父窗口小部件中更新:

private static void sendSentences() {
        String sentence;
        try{
            try(
                    InputStream fis = new FileInputStream("C:\\Users\\.....tweets.txt");
                    InputStreamReader isr = new InputStreamReader(fis, Charset.forName("Cp1252"));
                    BufferedReader br = new BufferedReader(isr);
            ){
                while ((sentence = br.readLine()) != null){
                    sendTweet(sentence, thandle);
                    System.out.println("sent " + sentence + ".");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

然后在父窗口小部件内,您需要捕获从子窗口发送的数据:

// 1- Define a pointers to executable code in memory, which is the callback.
typedef void MyCallback(String val);

class ExtraLocationNotes extends StatefulWidget {
  // 2- You will pass it to this widget with the constructor.
  final MyCallback cb;
  // 3- ..pass it to this widget with the constructor
  ExtraLocationNotes({this.cb});

  _ExtraLocationNotesState createState() => _ExtraLocationNotesState();
}

class _ExtraLocationNotesState extends State<ExtraLocationNotes> {
  //..
  //...

  RaisedButton(
    //..
    // 4- in any event inside the child you can call the callback with
    // the data you want to send back to the parent widget:
    onPressed: () {
      widget.cb("Hello from the other side!");
    }
  ),

}

答案 1 :(得分:0)

您可以使用BuildContext对象来获取上下文小部件(可能不是父级!)无法全部读取,但据我了解,您需要将信息从子级传递给父级,你可以用这样的东西来做:-

(context.widget as MyType).doStuff();

注意。 请先使用

检查
print(context.widget.runtimeType);

但是为了提供更好的解决方案,需要将可变的数据对象从父级传递给子级,以便在发生更改时它会反映在父级上,因此您可以将业务逻辑与ui逻辑分开。