diff --git a/README.md b/README.md index 5c20c39..c8d8206 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # lazy_indexed_stack -懒加载IndexedStack +LazyIndexedStack works similar to the `IndexedStack` widget, but adds the ability to load widgets lazily and supports Fade animation when switching between widgets. ## Getting Started @@ -16,13 +16,12 @@ import 'package:lazy_indexed_stack/lazy_indexed_stack.dart'; 使用方法: ``` -new LazyIndexedStack( - reuse: false, - index: index, - itemBuilder: (c,i){ - return LoadingPage(); - }, - itemCount: 4, - - ) +LazyIndexedStack( + reuse: false, + index: selectedIndex, + itemBuilder: (context, index){ + return LoadingPage(); + }, + itemCount: 4, +) ``` \ No newline at end of file diff --git a/example/lib/loading_page.dart b/example/lib/loading_page.dart new file mode 100644 index 0000000..b3899ee --- /dev/null +++ b/example/lib/loading_page.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; + +class LoadingPage extends StatefulWidget { + @override + _LoadingPageState createState() => _LoadingPageState(); +} + +class _LoadingPageState extends State { + bool _loading = true; + + @override + void initState() { + Future.delayed(Duration(seconds: 1)).then((e) { + setState(() { + _loading = false; + }); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Center( + child: _loading + ? Container( + child: Text( + "Loading....", + style: TextStyle( + fontSize: 30.0, + color: Colors.blue, + ), + ), + ) + : Container( + child: Text( + "Loaded", + style: TextStyle( + fontSize: 30.0, + color: Colors.green, + ), + ), + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 62deb14..fa7d4eb 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,27 +2,19 @@ import 'package:flutter/material.dart'; import 'package:lazy_indexed_stack/lazy_indexed_stack.dart'; +import 'loading_page.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( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. primarySwatch: Colors.blue, ), - home: MyHomePage(title: 'Flutter Demo Home Page'), + home: MyHomePage(title: 'LazyIndexedStack demo'), ); } } @@ -36,78 +28,50 @@ class MyHomePage extends StatefulWidget { _MyHomePageState createState() => _MyHomePageState(); } -class LoadingPage extends StatefulWidget { - @override - _LoadingPageState createState() => _LoadingPageState(); -} - -class _LoadingPageState extends State { - bool loading = true; - - @override - void initState() { - Future.delayed(new Duration(seconds: 2)).then((e) { - setState(() { - loading = false; - }); - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return loading - ? new Container( - child: new Text("loading...."), - ) - : Container( - child: new Text("load success"), - ); - } -} - class _MyHomePageState extends State { - int _counter = 0; - int index = 0; + int _selectedIndex = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), - body: new LazyIndexedStack( + body: LazyIndexedStack( reuse: false, - index: index, + index: _selectedIndex, itemBuilder: (c, i) { return LoadingPage(); }, itemCount: 4, ), - bottomNavigationBar: new BottomNavigationBar( + bottomNavigationBar: BottomNavigationBar( + type: BottomNavigationBarType.fixed, + backgroundColor: Colors.blueGrey, + selectedItemColor: Colors.amber, + unselectedItemColor: Colors.white70, items: [ - new BottomNavigationBarItem( - icon: new Icon( - Icons.add, - color: Colors.black38, - ), - title: new Text("add")), - new BottomNavigationBarItem( - icon: new Icon(Icons.add, color: Colors.black38), - title: new Text("add")), - new BottomNavigationBarItem( - icon: new Icon(Icons.add, color: Colors.black38), - title: new Text("add")), - new BottomNavigationBarItem( - icon: new Icon(Icons.add, color: Colors.black38), - title: new Text("add")), + BottomNavigationBarItem( + icon: Icon(Icons.add, color: Colors.white), + title: Text("one"), + ), + BottomNavigationBarItem( + icon: Icon(Icons.add, color: Colors.white), + title: Text("two"), + ), + BottomNavigationBarItem( + icon: Icon(Icons.add, color: Colors.white), + title: Text("three"), + ), + BottomNavigationBarItem( + icon: Icon(Icons.add, color: Colors.white), + title: Text("four"), + ), ], - currentIndex: index, + currentIndex: _selectedIndex, onTap: (i) { setState(() { - index = i; + _selectedIndex = i; }); }, ), diff --git a/example/pubspec.lock b/example/pubspec.lock index 31c29ca..b9a345f 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,41 +1,62 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "1.6.0" async: dependency: transitive description: name: async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.4.1" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "2.0.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" collection: dependency: transitive description: name: collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" - cupertino_icons: - dependency: "direct main" + version: "1.14.12" + convert: + dependency: transitive description: - name: cupertino_icons - url: "https://pub.flutter-io.cn" + name: convert + url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -46,6 +67,13 @@ packages: description: flutter source: sdk version: "0.0.0" + image: + dependency: transitive + description: + name: image + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.12" lazy_indexed_stack: dependency: "direct main" description: @@ -57,37 +85,37 @@ packages: dependency: transitive description: name: matcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.5" + version: "0.12.6" meta: dependency: transitive description: name: meta - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.7" + version: "1.1.8" path: dependency: transitive description: name: path - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.6.4" - pedantic: + petitparser: dependency: transitive description: - name: pedantic - url: "https://pub.flutter-io.cn" + name: petitparser + url: "https://pub.dartlang.org" source: hosted - version: "1.8.0+1" + version: "2.4.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.3" sky_engine: dependency: transitive description: flutter @@ -97,57 +125,64 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.7.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.9.3" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.5" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.2.5" + version: "0.2.15" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.8" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.1" sdks: - dart: ">=2.2.2 <3.0.0" + dart: ">=2.6.0 <3.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bb18e99..cd01f88 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,5 +1,5 @@ name: example -description: A new Flutter project. +description: LazyIndexedStack example. # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -20,10 +20,6 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - lazy_indexed_stack: path: ../ @@ -41,35 +37,4 @@ flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages + uses-material-design: true \ No newline at end of file diff --git a/lib/lazy_indexed_stack.dart b/lib/lazy_indexed_stack.dart index 3967f05..54c7710 100644 --- a/lib/lazy_indexed_stack.dart +++ b/lib/lazy_indexed_stack.dart @@ -2,36 +2,44 @@ library lazy_indexed_stack; import 'package:flutter/widgets.dart'; +/// Lazy animated IndexedStack. The widgets are created lazily when the index changes. class LazyIndexedStack extends StatefulWidget { final AlignmentGeometry alignment; final TextDirection textDirection; final StackFit sizing; final int index; - //reuse the created view + /// If false then the [itemBuilder] will be called each time the index changes. final bool reuse; final int itemCount; final IndexedWidgetBuilder itemBuilder; - LazyIndexedStack( - {Key key, - this.alignment = AlignmentDirectional.topStart, - this.textDirection, - this.sizing = StackFit.loose, - this.index, - this.reuse = true, - @required this.itemBuilder, - this.itemCount = 0}) - : super(key: key); + /// The duration of the fade animation when switching between widgets. + /// By default the [duration] is set to 0, so the switch is instant. + final Duration duration; + + const LazyIndexedStack({ + Key key, + this.alignment = AlignmentDirectional.topStart, + this.textDirection, + this.sizing = StackFit.loose, + this.index, + this.reuse = true, + @required this.itemBuilder, + this.itemCount = 0, + this.duration = const Duration(milliseconds: 0), + }) : super(key: key); @override _LazyIndexedStackState createState() => _LazyIndexedStackState(); } -class _LazyIndexedStackState extends State { +class _LazyIndexedStackState extends State + with SingleTickerProviderStateMixin { List _children; List _loaded; + AnimationController _controller; @override void initState() { @@ -42,10 +50,13 @@ class _LazyIndexedStackState extends State { _children.add(widget.itemBuilder(context, i)); _loaded.add(true); } else { - _children.add(new Container()); + _children.add(Container()); _loaded.add(false); } } + + _controller = AnimationController(vsync: this, duration: widget.duration); + _controller.forward(); super.initState(); } @@ -57,25 +68,35 @@ class _LazyIndexedStackState extends State { _children[i] = widget.itemBuilder(context, i); _loaded[i] = true; } else { - if (widget.reuse) { - return; + if (!widget.reuse) { + _children[i] = widget.itemBuilder(context, i); } - _children[i] = widget.itemBuilder(context, i); } } } - + if (widget.index != oldWidget.index) { + _controller.forward(from: 0.0); + } super.didUpdateWidget(oldWidget); } @override Widget build(BuildContext context) { - return new IndexedStack( - index: widget.index, - alignment: widget.alignment, - textDirection: widget.textDirection, - sizing: widget.sizing, - children: _children, + return FadeTransition( + opacity: _controller, + child: IndexedStack( + index: widget.index, + alignment: widget.alignment, + textDirection: widget.textDirection, + sizing: widget.sizing, + children: _children, + ), ); } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } } diff --git a/pubspec.lock b/pubspec.lock index 7102b1d..97283e8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,34 +1,62 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "1.6.0" async: dependency: transitive description: name: async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.4.1" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "2.0.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" collection: dependency: transitive description: name: collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" + source: hosted + version: "1.14.12" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -39,41 +67,48 @@ packages: description: flutter source: sdk version: "0.0.0" + image: + dependency: transitive + description: + name: image + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.12" matcher: dependency: transitive description: name: matcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.12.5" + version: "0.12.6" meta: dependency: transitive description: name: meta - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.1.7" + version: "1.1.8" path: dependency: transitive description: name: path - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.6.4" - pedantic: + petitparser: dependency: transitive description: - name: pedantic - url: "https://pub.flutter-io.cn" + name: petitparser + url: "https://pub.dartlang.org" source: hosted - version: "1.8.0+1" + version: "2.4.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.3" sky_engine: dependency: transitive description: flutter @@ -83,57 +118,64 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.7.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.9.3" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.5" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.2.5" + version: "0.2.15" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.8" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.1" sdks: - dart: ">=2.2.2 <3.0.0" + dart: ">=2.6.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index ca8cc84..7b24fcb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,35 +19,4 @@ dev_dependencies: # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages +flutter: \ No newline at end of file