簡體   English   中英

在 Flutter 中將數據從一個頁面傳遞到另一個頁面

[英]Pass data from one page to another in Flutter

我知道有很多這樣的問題,但我是 Flutter 的新手,我還沒有找到適合我需求的帖子,或者我只是想錯了。

我基本上有settings.darthome.dart 現在,我想做的是基於米_isMetresChecked或英尺_isFeetChecked的復選框值,更改主屏幕上的單位,但不要立即切換到主屏幕,允許用戶繼續配置設置(最終還有更多內容要添加),當他們返回主屏幕時,它會更新。 我嘗試使用類SettingsData作為合並所有配置的一種方式,然后通過Navigator傳遞它,但盡管我沒有成功,但它不會讓我允許用戶停留在“設置”頁面上。

那么如何在不切換視圖的情況下在視圖之間傳遞數據呢?

家.dart

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

import 'applicationbar.dart';
import 'navigationdrawer.dart';
import 'bluetooth.dart';


class LuggageFollowerMain extends StatefulWidget {
  @override
  _LuggageFollowerMainState createState() => _LuggageFollowerMainState();
}

class _LuggageFollowerMainState extends State<LuggageFollowerMain> {
  String _string = '0m';  //so if _isFeetChecked is true in settings.dart this is '0ft'


  @override
  Widget build(BuildContext context) {

    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: ApplicationBar(title: 'Luggage Follower'),
      drawer: NavigationDrawer(),
      body:Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text('Luggage Status', style: Theme.of(context).textTheme.body2),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text('Paired', style: Theme.of(context).textTheme.body1),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 0),
            child: Divider(height: 3.0, color: Colors.pinkAccent, indent: 150, endIndent: 150),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text('Distance to Luggage', style: Theme.of(context).textTheme.body2),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text(_string, style: Theme.of(context).textTheme.body1), //dynamic text here
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: LuggageFollow(),
          ),
        ],
      ),
    );
  }
}

設置.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:audioplayers/audio_cache.dart';

import 'applicationbar.dart';
import 'navigationdrawer.dart';

class SettingsData {
  bool feet;
  bool metres;

  SettingsData({this.feet, this.metres});
}

class Settings extends StatefulWidget {
  @override
  _SettingsState createState() => _SettingsState();
}

class _SettingsState extends State<Settings> {
  static bool _isFeetChecked   = false;
  static bool _isMetersChecked = true;


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: ApplicationBar(title: 'Settings'),
      drawer: NavigationDrawer(),
      body: Column(
          //crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 20),
              child: Text('Distance Units')
            ),
            Divider(
              height: 3.0,
              color: Colors.pink,
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 0),
              child: CheckboxListTile(
                title: Text('Distance in feet', style: Theme.of(context).textTheme.body1),
                value: _isFeetChecked,
                onChanged: (bool value) {
                  setState(() {
                    _isFeetChecked = value; _isMetersChecked = !value;});
                },
                checkColor: Colors.white,
                activeColor: Colors.pink,
                subtitle: Text('1 foot ~ 0.3 metres',style: Theme.of(context).textTheme.display2),
              ),
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 0),
              child: CheckboxListTile(
                title: Text('Distance in metres', style: Theme.of(context).textTheme.body1),
                value: _isMetersChecked,
                onChanged: (bool value) {
                  setState(() { _isMetersChecked = value; _isFeetChecked = !value;updateData();});
                },
                checkColor: Colors.white,
                activeColor: Colors.pink,
                subtitle: Text('1 metre ~ 3 feet',style: Theme.of(context).textTheme.display2),
              ),
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 30.0,horizontal: 20),
              child: Text('Notifications')
            ),
            Divider(
                height: 3.0,
                color: Colors.pink,
            ),

              ),
            ),
          ],
      ),
    );
  }
}

我知道有很多這樣的問題,但是我對Flutter還是陌生的,我還沒有找到適合我需求的帖子,或者我只是在想錯了。

我基本上有settings.darthome.dart 現在,我要基於米_isMetresChecked或英尺_isFeetChecked的復選框值,在主屏幕上更改單位,但不要立即切換到主屏幕,允許用戶繼續配置設置(最終還有更多內容要添加),然后當他們返回主屏幕時,它就會更新。 我嘗試使用SettingsData類作為合並所有配置,然后通過Navigator傳遞它的一種方法,但是盡管我沒有成功,但不允許我讓用戶停留在“ Settings”頁面上。

那么,如何在視圖之間傳遞數據而又不切換視圖?

飛鏢

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

import 'applicationbar.dart';
import 'navigationdrawer.dart';
import 'bluetooth.dart';


class LuggageFollowerMain extends StatefulWidget {
  @override
  _LuggageFollowerMainState createState() => _LuggageFollowerMainState();
}

class _LuggageFollowerMainState extends State<LuggageFollowerMain> {
  String _string = '0m';  //so if _isFeetChecked is true in settings.dart this is '0ft'


  @override
  Widget build(BuildContext context) {

    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: ApplicationBar(title: 'Luggage Follower'),
      drawer: NavigationDrawer(),
      body:Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text('Luggage Status', style: Theme.of(context).textTheme.body2),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text('Paired', style: Theme.of(context).textTheme.body1),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 0),
            child: Divider(height: 3.0, color: Colors.pinkAccent, indent: 150, endIndent: 150),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text('Distance to Luggage', style: Theme.of(context).textTheme.body2),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: Text(_string, style: Theme.of(context).textTheme.body1), //dynamic text here
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10,horizontal: 0),
            child: LuggageFollow(),
          ),
        ],
      ),
    );
  }
}

settings.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:audioplayers/audio_cache.dart';

import 'applicationbar.dart';
import 'navigationdrawer.dart';

class SettingsData {
  bool feet;
  bool metres;

  SettingsData({this.feet, this.metres});
}

class Settings extends StatefulWidget {
  @override
  _SettingsState createState() => _SettingsState();
}

class _SettingsState extends State<Settings> {
  static bool _isFeetChecked   = false;
  static bool _isMetersChecked = true;


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: ApplicationBar(title: 'Settings'),
      drawer: NavigationDrawer(),
      body: Column(
          //crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 20),
              child: Text('Distance Units')
            ),
            Divider(
              height: 3.0,
              color: Colors.pink,
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 0),
              child: CheckboxListTile(
                title: Text('Distance in feet', style: Theme.of(context).textTheme.body1),
                value: _isFeetChecked,
                onChanged: (bool value) {
                  setState(() {
                    _isFeetChecked = value; _isMetersChecked = !value;});
                },
                checkColor: Colors.white,
                activeColor: Colors.pink,
                subtitle: Text('1 foot ~ 0.3 metres',style: Theme.of(context).textTheme.display2),
              ),
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0,horizontal: 0),
              child: CheckboxListTile(
                title: Text('Distance in metres', style: Theme.of(context).textTheme.body1),
                value: _isMetersChecked,
                onChanged: (bool value) {
                  setState(() { _isMetersChecked = value; _isFeetChecked = !value;updateData();});
                },
                checkColor: Colors.white,
                activeColor: Colors.pink,
                subtitle: Text('1 metre ~ 3 feet',style: Theme.of(context).textTheme.display2),
              ),
            ),
            Padding(
              padding: EdgeInsets.symmetric(vertical: 30.0,horizontal: 20),
              child: Text('Notifications')
            ),
            Divider(
                height: 3.0,
                color: Colors.pink,
            ),

              ),
            ),
          ],
      ),
    );
  }
}

因此,首先您只需要 1 個布爾值即可進行測量。 它要么是英尺,要么是米。 所以這簡化了一些事情。 這是一個使用回調函數設置父小部件中狀態更改的示例。 這只是可以完成的許多方法中的一種,可能還有其他您可能更喜歡的方法。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LuggageFollowerMain(),
    );
  }
}


class Settings extends StatefulWidget {

  //Static references to our parent widget varibles
  final bool isM;
  final changeMeeters;

  Settings(bool isM, changeMeeters(bool meeters)):
  this.isM = isM,
  this.changeMeeters = changeMeeters
  ;

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

class _SettingsState extends State<Settings> {
  @override
  void initState() { 
    super.initState();
    //set our varible state to be that of the parent screen
    //isMeeters is a local var to Settings and is changeable. 
    //isM is a static and can't be changed. isM was passed in 
    //from our home screen. We need a changeable var or the 
    //checkboxes won't update correctly. Thats why we need 
    //isMeeters (lol bad spelling). When the settings screen 
    //first loads we use initState to take the value of 
    //isM(from our home screen) and copy it into isMeeters 
    //as it's initial value before it is built and shown 
    //to the user for the first time. 
    isMeeters = widget.isM;
  }

  //our varible to use for our check boxes
  var isMeeters;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Padding(
              padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20),
              child: Text('Distance Units')),
          Divider(
            height: 3.0,
            color: Colors.pink,
          ),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 0),
            child: CheckboxListTile(
              title: Text('Distance in feet',
                  style: Theme.of(context).textTheme.body1),
              //use the local var change when tapped
              value: isMeeters,
              onChanged: (bool value) {
                setState(() {
                  isMeeters = true;
                });
                //call back to the parent widget so it can be updated
                widget.changeMeeters(true);
              },
              checkColor: Colors.white,
              activeColor: Colors.pink,
              subtitle: Text('1 foot ~ 0.3 metres',
                  style: Theme.of(context).textTheme.display2),
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 0),
            child: CheckboxListTile(
              title: Text('Distance in metres',
                  style: Theme.of(context).textTheme.body1),
              //use the local var change when tapped. Use ! to invert the bool. This way only one is needed.
              value: !isMeeters,
              onChanged: (bool value) {
                setState(() {
                  isMeeters = false;
                });
                //call back to the parent widget so it can be updated
                widget.changeMeeters(false);
              },
              checkColor: Colors.white,
              activeColor: Colors.pink,
              subtitle: Text('1 metre ~ 3 feet',
                  style: Theme.of(context).textTheme.display2),
            ),
          ),
          Padding(
              padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 20),
              child: Text('Notifications')),
          Divider(
            height: 3.0,
            color: Colors.pink,
          ),
        ],
      ),
    );
  }
}

class LuggageFollowerMain extends StatefulWidget {
  @override
  _LuggageFollowerMainState createState() => _LuggageFollowerMainState();
}

class _LuggageFollowerMainState extends State<LuggageFollowerMain> {
      //store the distance as a number not a string
      double distance = 0.0;
      //store the measurement type setting
      bool isMeeters = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => Settings(isMeeters, (newMeeters){
              //when we get our callback from settings we set the change to the home screen var here
              setState(() {
                isMeeters = newMeeters;
              });

            })),
          );
        },
      ),
      backgroundColor: Colors.grey[900],
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
            child: Text('Luggage Status',
                style: Theme.of(context).textTheme.body2),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
            child: Text('Paired', style: Theme.of(context).textTheme.body1),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 0),
            child: Divider(
                height: 3.0,
                color: Colors.pinkAccent,
                indent: 150,
                endIndent: 150),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
            child: Text('Distance to Luggage',
                style: Theme.of(context).textTheme.body2),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
            //use the new number var and change it's suffix m or f depending on what our setting is.
            child: Text(distance.toString() + (isMeeters ? "m" : "f"),
                style: Theme.of(context).textTheme.body1), //dynamic text here
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
          ),
        ],
      ),
    );
  }
}

要將數據從一個頁面傳遞到另一個頁面,您可以使用向命名路由傳遞參數

下面是通過參數的方式在設置頁面之間傳遞布爾值的最小示例。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
      routes: {
        "home": (BuildContext homeContext) => HomePage(),
        "settings": (BuildContext settingsContext) => SettingsPage(),
      },
      initialRoute: "home",
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _isMetersAccordingToHomePage = false;

  void _updateIsMetersAccordingToHomePage(bool _value) {
    setState(() {
      _isMetersAccordingToHomePage = _value ?? _isMetersAccordingToHomePage;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Home Page")),
      body: Column(
        children: <Widget>[
          Text("Is Displayed in meters? $_isMetersAccordingToHomePage"),
          RaisedButton(
            onPressed: () {
              // This is the important part
              Navigator.of(context)
                  .pushNamed(
                "settings",
                // we are passing a value to the settings page
                arguments: _isMetersAccordingToHomePage,
              )
                  // and then, when we `pop` from the settings page,
                  // we will get back an updated value
                  .then(
                (_isMetersAccordingToSettingsPage) {
                  _updateIsMetersAccordingToHomePage(
                      _isMetersAccordingToSettingsPage);
                },
              );
            },
            child: Text("Go to Settings Page"),
          ),
        ],
      ),
    );
  }
}

class SettingsPage extends StatefulWidget {
  @override
  _SettingsPageState createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  bool _isMetersAccordingToSettingsPage;

  void _updateIsMetersAccordingToSettingsPage(bool _value) {
    setState(() {
      _isMetersAccordingToSettingsPage = _value;
    });
  }

  @override
  Widget build(BuildContext context) {
    bool _isMetersAccordingToHomePage =
        ModalRoute.of(context).settings.arguments;

    return Scaffold(
      appBar: AppBar(
        title: Text("Setting Page"),
        leading: IconButton(
          icon: Icon(Icons.arrow_back_ios),
          onPressed: () {
            Navigator.of(context).pop<bool>(_isMetersAccordingToSettingsPage);
          },
        ),
      ),
      body: Column(
        children: <Widget>[
          CheckboxListTile(
            value: _isMetersAccordingToSettingsPage ??
                _isMetersAccordingToHomePage ??
                false,
            onChanged: _updateIsMetersAccordingToSettingsPage,
            title: Text("Display in meters?"),
          ),
        ],
      ),
    );
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM