mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Add ValueTabController – generic feature!
This commit is contained in:
@@ -12,6 +12,7 @@ import 'flutter.dart';
|
|||||||
import 'puzzle_flow_delegate.dart';
|
import 'puzzle_flow_delegate.dart';
|
||||||
import 'shared_theme.dart';
|
import 'shared_theme.dart';
|
||||||
import 'themes.dart';
|
import 'themes.dart';
|
||||||
|
import 'value_tab_controller.dart';
|
||||||
|
|
||||||
class PuzzleHomeState extends State with TickerProviderStateMixin, AppState {
|
class PuzzleHomeState extends State with TickerProviderStateMixin, AppState {
|
||||||
@override
|
@override
|
||||||
@@ -163,7 +164,8 @@ Widget _updateConstraints(
|
|||||||
Widget _doBuild(BuildContext _, BoxConstraints constraints) =>
|
Widget _doBuild(BuildContext _, BoxConstraints constraints) =>
|
||||||
_updateConstraints(constraints, _doBuildCore);
|
_updateConstraints(constraints, _doBuildCore);
|
||||||
|
|
||||||
Widget _doBuildCore(bool small) => PuzzleThemeTabController(
|
Widget _doBuildCore(bool small) => ValueTabController<SharedTheme>(
|
||||||
|
values: themes,
|
||||||
child: Consumer<SharedTheme>(
|
child: Consumer<SharedTheme>(
|
||||||
builder: (_, theme, __) => AnimatedContainer(
|
builder: (_, theme, __) => AnimatedContainer(
|
||||||
duration: puzzleAnimationDuration,
|
duration: puzzleAnimationDuration,
|
||||||
@@ -190,8 +192,7 @@ Widget _doBuildCore(bool small) => PuzzleThemeTabController(
|
|||||||
margin:
|
margin:
|
||||||
const EdgeInsets.symmetric(horizontal: 20),
|
const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: TabBar(
|
child: TabBar(
|
||||||
controller:
|
controller: ValueTabController.of(context),
|
||||||
PuzzleThemeTabController.of(context),
|
|
||||||
labelPadding:
|
labelPadding:
|
||||||
const EdgeInsets.fromLTRB(0, 20, 0, 12),
|
const EdgeInsets.fromLTRB(0, 20, 0, 12),
|
||||||
labelColor: theme.puzzleAccentColor,
|
labelColor: theme.puzzleAccentColor,
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import 'package:flutter_web/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import 'shared_theme.dart';
|
|
||||||
import 'theme_plaster.dart';
|
import 'theme_plaster.dart';
|
||||||
import 'theme_seattle.dart';
|
import 'theme_seattle.dart';
|
||||||
import 'theme_simple.dart';
|
import 'theme_simple.dart';
|
||||||
@@ -11,86 +7,3 @@ const themes = [
|
|||||||
ThemeSeattle(),
|
ThemeSeattle(),
|
||||||
ThemePlaster(),
|
ThemePlaster(),
|
||||||
];
|
];
|
||||||
|
|
||||||
class PuzzleThemeTabController extends StatefulWidget {
|
|
||||||
/// Creates a default tab controller for the given [child] widget.
|
|
||||||
const PuzzleThemeTabController({
|
|
||||||
Key key,
|
|
||||||
@required this.child,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
|
||||||
///
|
|
||||||
/// Typically a [Scaffold] whose [AppBar] includes a [TabBar].
|
|
||||||
///
|
|
||||||
/// {@macro flutter.widgets.child}
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
|
||||||
///
|
|
||||||
/// Typical usage:
|
|
||||||
///
|
|
||||||
/// ```dart
|
|
||||||
/// TabController controller = DefaultTabBarController.of(context);
|
|
||||||
/// ```
|
|
||||||
static TabController of(BuildContext context) {
|
|
||||||
final scope =
|
|
||||||
context.inheritFromWidgetOfExactType(_PuzzleThemeTabControllerScope)
|
|
||||||
as _PuzzleThemeTabControllerScope;
|
|
||||||
return scope?.controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
_PuzzleThemeTabControllerState createState() =>
|
|
||||||
_PuzzleThemeTabControllerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PuzzleThemeTabControllerState extends State<PuzzleThemeTabController>
|
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
final _notifier = ValueNotifier<SharedTheme>(themes.first);
|
|
||||||
|
|
||||||
TabController _controller;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = TabController(
|
|
||||||
vsync: this,
|
|
||||||
length: themes.length,
|
|
||||||
initialIndex: 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
_controller.addListener(() {
|
|
||||||
_notifier.value = themes[_controller.index];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _PuzzleThemeTabControllerScope(
|
|
||||||
controller: _controller,
|
|
||||||
enabled: TickerMode.of(context),
|
|
||||||
child: ValueListenableProvider.value(
|
|
||||||
valueListenable: _notifier,
|
|
||||||
child: widget.child,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PuzzleThemeTabControllerScope extends InheritedWidget {
|
|
||||||
const _PuzzleThemeTabControllerScope(
|
|
||||||
{Key key, this.controller, this.enabled, Widget child})
|
|
||||||
: super(key: key, child: child);
|
|
||||||
|
|
||||||
final TabController controller;
|
|
||||||
final bool enabled;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool updateShouldNotify(_PuzzleThemeTabControllerScope old) =>
|
|
||||||
enabled != old.enabled || controller != old.controller;
|
|
||||||
}
|
|
||||||
|
|||||||
88
web/slide_puzzle/lib/src/value_tab_controller.dart
Normal file
88
web/slide_puzzle/lib/src/value_tab_controller.dart
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import 'package:flutter_web/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ValueTabController<T> extends StatefulWidget {
|
||||||
|
/// Creates a default tab controller for the given [child] widget.
|
||||||
|
const ValueTabController({
|
||||||
|
Key key,
|
||||||
|
@required this.child,
|
||||||
|
@required this.values,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
/// The widget below this widget in the tree.
|
||||||
|
///
|
||||||
|
/// Typically a [Scaffold] whose [AppBar] includes a [TabBar].
|
||||||
|
///
|
||||||
|
/// {@macro flutter.widgets.child}
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
final List<T> values;
|
||||||
|
|
||||||
|
/// The closest instance of this class that encloses the given context.
|
||||||
|
///
|
||||||
|
/// Typical usage:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// TabController controller = DefaultTabBarController.of(context);
|
||||||
|
/// ```
|
||||||
|
static TabController of(BuildContext context) {
|
||||||
|
final scope = context.inheritFromWidgetOfExactType(_ValueTabControllerScope)
|
||||||
|
as _ValueTabControllerScope;
|
||||||
|
return scope?.controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ValueTabControllerState<T> createState() => _ValueTabControllerState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ValueTabControllerState<T> extends State<ValueTabController<T>>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
final _notifier = ValueNotifier<T>(null);
|
||||||
|
|
||||||
|
TabController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = TabController(
|
||||||
|
vsync: this,
|
||||||
|
length: widget.values.length,
|
||||||
|
initialIndex: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
_notifier.value = widget.values.first;
|
||||||
|
|
||||||
|
_controller.addListener(() {
|
||||||
|
_notifier.value = widget.values[_controller.index];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _ValueTabControllerScope(
|
||||||
|
controller: _controller,
|
||||||
|
enabled: TickerMode.of(context),
|
||||||
|
child: ValueListenableProvider.value(
|
||||||
|
valueListenable: _notifier,
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ValueTabControllerScope extends InheritedWidget {
|
||||||
|
const _ValueTabControllerScope(
|
||||||
|
{Key key, this.controller, this.enabled, Widget child})
|
||||||
|
: super(key: key, child: child);
|
||||||
|
|
||||||
|
final TabController controller;
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(_ValueTabControllerScope old) =>
|
||||||
|
enabled != old.enabled || controller != old.controller;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user