颤动一次介绍屏幕?

时间:2018-06-02 06:34:26

标签: android dart sharedpreferences flutter flutter-layout

我的应用程序有一个简介屏幕,但每次打开应用程序时都会显示 我需要第一次显示 怎么做?

//ThIS IS THE SCREEN COMES 1ST WHEN OPENING THE APP (SPLASHSCREEN)

class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
@override
void initState() 
{
super.initState();

//After 2seconds of time the Introscreen will e opened by bellow code
Timer(Duration(seconds: 2), () => MyNavigator.goToIntroscreen(context));
}

//The below code has the text to show for the spalshing screen
@override
Widget build(BuildContext context)
{
return Scaffold
(
body: new Center(child:Text('SPLASH SCREEN'),)
);
}
}

此屏幕始终打开内部屏幕,延迟时间为2秒。 但我只是第一次想要如何使用共享偏好? 请添加所需的代码pls ....

7 个答案:

答案 0 :(得分:13)

如果您希望仅首次显示介绍屏幕,则需要在本地保存此用户已经看过的介绍。

对于这样的事情你可以使用Shared Preference。您可以使用共享首选项flutter package

<强> EDITED

请参阅以下完整测试代码以了解如何使用

import 'dart:async';

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

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return new MaterialApp(
    color: Colors.blue,
    home: new Splash(),
    );
}
}

class Splash extends StatefulWidget {
@override
SplashState createState() => new SplashState();
}

class SplashState extends State<Splash> {
Future checkFirstSeen() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool _seen = (prefs.getBool('seen') ?? false);

    if (_seen) {
    Navigator.of(context).pushReplacement(
        new MaterialPageRoute(builder: (context) => new Home()));
    } else {
    prefs.setBool('seen', true);
    Navigator.of(context).pushReplacement(
        new MaterialPageRoute(builder: (context) => new IntroScreen()));
    }
}

@override
void initState() {
    super.initState();
    new Timer(new Duration(milliseconds: 200), () {
    checkFirstSeen();
    });
}

@override
Widget build(BuildContext context) {
    return new Scaffold(
    body: new Center(
        child: new Text('Loading...'),
    ),
    );
}
}

class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return new Scaffold(
    appBar: new AppBar(
        title: new Text('Hello'),
    ),
    body: new Center(
        child: new Text('This is the second page'),
    ),
    );
}
}

class IntroScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return new Scaffold(
    body: new Center(
        child: new Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
            new Text('This is the intro page'),
            new MaterialButton(
            child: new Text('Gogo Home Page'),
            onPressed: () {
                Navigator.of(context).pushReplacement(
                    new MaterialPageRoute(builder: (context) => new Home()));
            },
            )
        ],
        ),
    ),
    );
}
}

答案 1 :(得分:1)

我只需要做完全一样的事情,这就是我的做事方式: 首先,在我的main方法中,打开常规主页教程:

MaterialApp(
        title: 'myApp',
        onGenerateInitialRoutes: (_) => [MaterialPageRoute(builder: mainPageRoute), MaterialPageRoute(builder: tutorialSliderRoute)],
)

...然后仅在必要时使用FutureBuilder来构建本教程:

var tutorialSliderRoute = (context) => FutureBuilder(
      future: Provider.of<UserConfiguration>(context, listen: false).loadShowTutorial()  // does a lookup using Shared Preferences
          .timeout(Duration(seconds: 3), onTimeout: () => false),
      initialData: null,
      builder: (context, snapshot){
        if (snapshot.data == null){
          return CircularProgressIndicator();   // This is displayed for up to 3 seconds, in case data loading doesn't return for some reason...
        } else if (snapshot.data == true){
          return TutorialSlider();   // The Tutorial, implemented using IntroSlider()
        } else {
          // In case the tutorial shouldn't be shown, just return an empty Container and immediately pop it again so that the app's main page becomes visible.
          SchedulerBinding.instance.addPostFrameCallback((_){Navigator.of(context).pop();});
          return Container(width: 0, height: 0);
        }
      },
    );

此外,我认为应该在用户未完成本教程的情况下再次显示该教程,因此,一旦用户完成(或跳过)该变量,我只会将变量showTutorial设置为false。教程:

class TutorialSlider extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => TutorialSliderState();
}

class TutorialSliderState extends State<TutorialSlider> {
  ...
  @override
  Widget build(BuildContext context) => IntroSlider(
      ...
      onDonePress: (){
        Provider.of<UserConfiguration>(context, listen: false).setShowTutorial(false);
        Navigator.of(context).pop();
      }
  );
}

答案 2 :(得分:1)

我能够不使用after_layout软件包和Mixins而使用FutureBuilder。

from seleniumwire import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
def get_firefox():
    options = webdriver.FirefoxOptions()
    options.add_argument("-headless")
    profile = webdriver.FirefoxProfile()  
    profile.accept_untrusted_certs = True  
    profile.set_preference("network.proxy.type", 1)
    profile.set_preference('network.proxy.socks', 'proxy')
    profile.set_preference('network.proxy.socks_port', 1080)
    profile.update_preferences()
    driver = webdriver.Firefox(firefox_profile=profile,options=options)   
    return driver

driver = get_firefox()

答案 3 :(得分:0)

每次启动应用程序时,您都需要存储布尔值。为此,您需要使用shared preferences

首先,我们为共享首选项创建自定义类,因此您可以从任何页面访问它。

import 'package:shared_preferences/shared_preferences.dart';
 
class MySharedPreferences {
  MySharedPreferences._privateConstructor();
 
  static final MySharedPreferences instance =
      MySharedPreferences._privateConstructor();
 
  setBooleanValue(String key, bool value) async {
    SharedPreferences myPrefs = await SharedPreferences.getInstance();
    myPrefs.setBool(key, value);
  }
 
  Future<bool> getBooleanValue(String key) async {
    SharedPreferences myPrefs = await SharedPreferences.getInstance();
    return myPrefs.getBool(key) ?? false;
  }
 
}

然后,我们需要在每次启动应用程序时检查布尔值。如果value为false,则必须显示简介屏幕,否则显示主屏幕。

import 'package:flutter/material.dart';
import 'my_shared_preferences.dart';
import 'intro.dart';
import 'home.dart';
 
void main() {
  runApp(MyApp());
}
 
class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return MyAppState();
  }
}
 
class MyAppState extends State<MyApp> {
  // This widget is the root of your application.
 
  bool isFirstTimeOpen = false;
 
  MyAppState() {
    MySharedPreferences.instance
        .getBooleanValue("firstTimeOpen")
        .then((value) => setState(() {
              isFirstTimeOpen = value;
            }));
  }
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: isFirstTimeOpen ? Home() : Intro());
  }
}

还将布尔值true存储在简介屏幕中,因此不会每次都显示简介屏幕。您也可以在here上参考示例。

 MySharedPreferences.instance.setBooleanValue("firstTimeOpen", true);

答案 4 :(得分:0)

我采取了另一种方法。我同意其他答案,您应该通过isFirstRun保存SharedPreferences状态。然后,棘手的部分是如何以正确的方式显示正确的小部件,这样当您回弹时就可以正确关闭应用程序,依此类推。我首先尝试通过在构建{{1 }},但这实际上导致了一些奇怪的SplashWidget错误。

相反,我最终视情况使用不同的小部件多次调用HomePageWidget。当我需要关闭Navigator而不是将其弹出时,我再次调用runApp(),这次以我的SplashWidget作为runApp()属性。即使根据启动画面,也可以根据this issue多次呼叫HomePageWidget,这很安全。

所以看起来像这样(明显简化了):

child

我在runApp()上有一个Future<void> main() async { bool needsFirstRun = await retrieveNeedsFirstRunFromPrefs(); if (needsFirstRun) { // This is will probably be an async method but no need to // delay the first widget. saveFirstRunSeen(); runApp(child: SplashScreenWidget(isFirstRun: true)); } else { runApp(child: HomePageWidget()); } } 属性,因为我可以通过两种方式启动它:一次是一个真正的启动屏幕,一次是从设置启动的,以便用户根据需要再次看到它。然后,我在isFirstRun中进行检查,以确定应该如何返回应用程序。

SplashScreenWidget

答案 5 :(得分:0)

使用shared_preferences

完整代码:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  var prefs = await SharedPreferences.getInstance();
  var boolKey = 'isFirstTime';
  var isFirstTime = prefs.getBool(boolKey) ?? true;

  runApp(MaterialApp(home: isFirstTime ? IntroScreen(prefs, boolKey) : RegularScreen()));
}

class IntroScreen extends StatelessWidget {
  final SharedPreferences prefs;
  final String boolKey;
  IntroScreen(this.prefs, this.boolKey);

  Widget build(BuildContext context) {
    prefs.setBool(boolKey, false); // You might want to save this on a callback.
    return Scaffold();
  }
}

class RegularScreen extends StatelessWidget {
  Widget build(BuildContext context) => Scaffold();
}

答案 6 :(得分:0)

我总是尝试使用最小数量的包,因为将来它可能会与 ios 或 android 冲突。所以我没有任何包的简单解决方案:

class SplashScreen extends StatefulWidget {
 @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  final splashDelay = 2;

  @override
  void initState() {
    super.initState();

    _loadWidget();
  }

  _loadWidget() async {
    var _duration = Duration(seconds: splashDelay);
    return Timer(_duration, checkFirstSeen);
  }

  Future checkFirstSeen() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool _introSeen = (prefs.getBool('intro_seen') ?? false);
    
    Navigator.pop(context);
    if (_introSeen) {
      Navigator.pushNamed(context, Routing.HomeViewRoute);
    } else {
      await prefs.setBool('intro_seen', true);
      Navigator.pushNamed(context, Routing.IntroViewRoute);
    }
  }

  @override
  Widget build(BuildContext context) {
  //your splash screen code
  }
}