【问题标题】:Flutter Switch with shared preference not working the first change具有共享偏好的 Flutter Switch 在第一次更改时不起作用
【发布时间】:2021-04-12 12:57:57
【问题描述】:

我需要另一个文件中的开关值信息(真或假)来计算一些东西。 当 Switch 为 false 并且我重新启动应用程序时,Switch 仍为 false,如果我单击它,该值将变为 true,并使用它执行计算。

现在我的问题: 如果我将开关打开为 true 并关闭应用程序并重新启动,则该值将保持为 true(这很好),但如果我现在单击 Switch,则第二个文件中的值应该变为 false,但它不会,因此计算是不使用这个假的。再点击开关2次后就完美了。

您有任何想法如何改变以及改变什么?非常感谢!

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

import 'package:ncrechner/Allgemein/state_widget.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Test extends StatefulWidget {
  @override
  DienstState createState() => DienstState();
}

@override
class DienstState extends State<Test> {
  Widget build(BuildContext context) {
    return DienstSwitch();
  }
}

class SwitchHelper with ChangeNotifier{
bool _switchValue;
final SharedPreferences prefs = SharedPreferences.getInstance();


updataValue() async{
_switchValue = await prefs.getBool("isSwitchedDienst1");
_switchValue = !_switchValue;
prefs.setBool("isSwitchedDienst1", _switchValue);
notifyListeners();

}
}
class DienstSwitch extends StatefulWidget {
  @override
  DienstSwitchState createState() => new DienstSwitchState();
}

bool isSwitchedDienst1 = false;

class DienstSwitchState extends State<DienstSwitch> {
  @override
  void initState() {
    super.initState();
    loadisSwitchedDienst();
  }

  loadisSwitchedDienst() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    isSwitchedDienst1 =
        (prefs.getBool("isSwitchedDienst1") ?? isSwitchedDienst1);
  }

  incrementisSwitchedDienst() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      isSwitchedDienst1 =
          (prefs.getBool('isSwitchedDienst1') ?? isSwitchedDienst1);
      prefs.setBool(("isSwitchedDienst1"), isSwitchedDienst1);
    });
  }

  removeisSwitchedDienst() async {
    final prefs = await SharedPreferences.getInstance();
    prefs.remove('isSwitchedDienst1');
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoSwitch(
      value: isSwitchedDienst1,
      onChanged: (bool value) {
        Provider.of<SwitchHelper>(context).updataValue();
        //removeisSwitchedDienst();
        //incrementisSwitchedDienst();
        /*setState(
          () {
            isSwitchedDienst1 = value;
            //final provider = StateInheritedWidget.of(context);
            //provider.changeSwitchDienst(isSwitchedDienst1);
          },
        );*/
      },
      activeColor: Colors.green,
    );
  }
}

我的主要看起来像:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ncrechner/DreamOn/Angaben/test.dart';
import 'package:ncrechner/nav.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'Allgemein/state_widget.dart';
import 'onboarding.dart';

int initScreen;
Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  SharedPreferences prefs = await SharedPreferences.getInstance();
  initScreen = prefs.getInt("initScreen");
  await prefs.setInt("initScreen", 1);
  await SystemChrome.setPreferredOrientations(
    [
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ],
  );

  runApp(MyApp());
}

/*class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => StateWidget(
        child: Builder(
          builder: (context) {
            return
*/
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [ChangeNotifierProvider(create: (context) => SwitchHelper())],
      child: MaterialApp(
        initialRoute: initScreen == 0 || initScreen == null ? "first" : "/",
        routes: {
          "/": (context) => Navigation(),
          "first": (context) => OnBoardingPage(),
        },
        theme: ThemeData(
          primaryColor: Colors.white,
          scaffoldBackgroundColor: Colors.white.withAlpha(150),
          accentColor: Colors.blue,
          backgroundColor: Colors.red,
          elevatedButtonTheme: ElevatedButtonThemeData(
            style: ElevatedButton.styleFrom(
              onPrimary: Colors.black,
              primary: Colors.white,
            ),
          ),
          toggleButtonsTheme: ToggleButtonsThemeData(
              color: Colors.black,
              selectedColor: Colors.black,
              fillColor: Colors.blue.withOpacity(0.4)),
        ),
        darkTheme: ThemeData(
          brightness: Brightness.dark,
          primarySwatch: Colors.blue,
          primaryColor: Colors.grey[900],
          buttonColor: Colors.grey[900],
          scaffoldBackgroundColor: Colors.black,
          accentColor: Colors.blue,
        ),
        themeMode: ThemeMode.system,
        /* ThemeMode.system to follow system theme, 
               ThemeMode.light for light theme, 
               ThemeMode.dark for dark theme
              */
        debugShowCheckedModeBanner: false,
      ),
    );
  }
}

【问题讨论】:

    标签: flutter switch-statement sharedpreferences persistence


    【解决方案1】:

    我认为 setState() 没有按照您的指示工作。我也是颤振的新手。但我认为如果您使用提供程序,它将解决您的问题。

    您需要按此顺序创建一个新类。

    class SwitchHelper with ChangeNotifier{
    bool_switchValue;
    final SharedPreferences prefs = SharedPreferences.getInstance();
    
    
    updataValue() async{
    _switchValue = await prefs.getBool("isSwitchedDienst1");
    _switchValue = !_switchValue;
    prefs.setBool("isSwitchedDienst1", _switchValue);
    notifyListeners();
    
    }
    }
    

    所以基本上它会从SharedPrefernces 获取值,然后将其存储在变量中。方法updateValue 将在点击开关或您的按钮时被调用。一旦调用该方法,它将更改bool 变量的值并将其值设置为sharedPreferences。如果bool _switchValue 的先前值为真,则使用条件_switchValue = !_switchValue 将其设置为假,反之亦然,然后将其反映到sharedPreferences 中。

    要使用这些值,您需要导入包“Provider”https://pub.dev/packages/provider 参考文档。

    使用提供者包装您的材料应用程序。 并创建一个ChangeNotifier 并将子级分配为materialApp。 并创建参数create : (context) =&gt; SwitchHelper()

    像这样。并且您可以在 GestureDetectoronTap 方法中访问方法中的任何一个。如:Provider.of&lt;SwitchHelper&gt;(context).updateValue();

    我认为这会起作用。

    编辑: 你的主要方法:

        void main(){
        runApp(MyApp());}
        class MyApp extends StatelessWidget{
        @override
          Widget build(BuildContext context) {
            return MultiProvider(
        providers: 
    [ 
    ChangeNotifierProvider(
        create: (context)=> SwitchHelper())]
    child: MaterialApp()...
    

    假设你想改变点击按钮的开关。

    ElevatedButton(
    child: Text("click to switch"),
    onPressed: (){
    Provider.of<SwitchHelper>(context).updateValue();
    }
    ),
    

    这样您就可以调用提供程序行,该行将访问该函数并更新用户界面,而无需使用 setState()。

    【讨论】:

    • 现在我在上面显示的代码中包含了您的代码,并且我还像这样包装了我的材料应用程序:return ChangeNotifierProvider( create: (context) => SwitchHelper(), child: MaterialApp( . .....现在我收到一条错误消息:/C:/Users/Public/flutter/.pub-cache/hosted/pub.dartlang.org/provider-3.2.0/lib/src/delegate_widget.dart:194 :18: 错误:超类没有名为 'inheritFromElement' 的方法。返回 super.inheritFromElement(ancestor, aspect: aspect); ^^^^^^^^^^^^^^^^
    • 我已经编辑了答案检查。并且您是否导入了提供程序包?如果您使用的是提供者,则不需要设置状态..
    • 现在我收到此错误消息:错误:无法将“Future”类型的值分配给“SharedPreferences”类型的变量。 - 'Future' 来自 'dart:async'。
    • initScreen = await prefs.getInt("initScreen");在这一行中使用 await。 'Future 来自 'dart:async' 由于更新的软件包而显示其警告。只需点击 Future 关键字的建议并导入 dart:async 包。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-20
    • 2021-04-01
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 2019-03-18
    • 2021-03-23
    相关资源
    最近更新 更多