180 lines
5.1 KiB
Dart
180 lines
5.1 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// Flutter code sample for [PageView].
|
|
|
|
void main() => runApp(const PageViewExampleApp());
|
|
|
|
class PageViewExampleApp extends StatelessWidget {
|
|
const PageViewExampleApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
home: Scaffold(
|
|
appBar: AppBar(title: const Text('PageView Sample')),
|
|
body: const PageViewExample(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class PageViewExample extends StatefulWidget {
|
|
const PageViewExample({super.key});
|
|
|
|
@override
|
|
State<PageViewExample> createState() => _PageViewExampleState();
|
|
}
|
|
|
|
class _PageViewExampleState extends State<PageViewExample>
|
|
with TickerProviderStateMixin {
|
|
late PageController _pageViewController;
|
|
late TabController _tabController;
|
|
int _currentPageIndex = 0;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_pageViewController = PageController();
|
|
_tabController = TabController(length: 3, vsync: this);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
_pageViewController.dispose();
|
|
_tabController.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final TextTheme textTheme = Theme.of(context).textTheme;
|
|
|
|
return Stack(
|
|
alignment: Alignment.bottomCenter,
|
|
children: <Widget>[
|
|
PageView(
|
|
/// [PageView.scrollDirection] defaults to [Axis.horizontal].
|
|
/// Use [Axis.vertical] to scroll vertically.
|
|
controller: _pageViewController,
|
|
onPageChanged: _handlePageViewChanged,
|
|
children: <Widget>[
|
|
Center(child: Text('First Page', style: textTheme.titleLarge)),
|
|
Center(child: Text('Second Page', style: textTheme.titleLarge)),
|
|
Center(child: Text('Third Page', style: textTheme.titleLarge)),
|
|
],
|
|
),
|
|
PageIndicator(
|
|
tabController: _tabController,
|
|
currentPageIndex: _currentPageIndex,
|
|
onUpdateCurrentPageIndex: _updateCurrentPageIndex,
|
|
isOnDesktopAndWeb: _isOnDesktopAndWeb,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
void _handlePageViewChanged(int currentPageIndex) {
|
|
if (!_isOnDesktopAndWeb) {
|
|
return;
|
|
}
|
|
_tabController.index = currentPageIndex;
|
|
setState(() {
|
|
_currentPageIndex = currentPageIndex;
|
|
});
|
|
}
|
|
|
|
void _updateCurrentPageIndex(int index) {
|
|
_tabController.index = index;
|
|
_pageViewController.animateToPage(
|
|
index,
|
|
duration: const Duration(milliseconds: 400),
|
|
curve: Curves.easeInOut,
|
|
);
|
|
}
|
|
|
|
bool get _isOnDesktopAndWeb =>
|
|
kIsWeb ||
|
|
switch (defaultTargetPlatform) {
|
|
TargetPlatform.macOS ||
|
|
TargetPlatform.linux ||
|
|
TargetPlatform.windows =>
|
|
true,
|
|
TargetPlatform.android ||
|
|
TargetPlatform.iOS ||
|
|
TargetPlatform.fuchsia =>
|
|
false,
|
|
};
|
|
}
|
|
|
|
/// Page indicator for desktop and web platforms.
|
|
///
|
|
/// On Desktop and Web, drag gesture for horizontal scrolling in a PageView is disabled by default.
|
|
/// You can defined a custom scroll behavior to activate drag gestures,
|
|
/// see https://docs.flutter.dev/release/breaking-changes/default-scroll-behavior-drag.
|
|
///
|
|
/// In this sample, we use a TabPageSelector to navigate between pages,
|
|
/// in order to build natural behavior similar to other desktop applications.
|
|
class PageIndicator extends StatelessWidget {
|
|
const PageIndicator({
|
|
super.key,
|
|
required this.tabController,
|
|
required this.currentPageIndex,
|
|
required this.onUpdateCurrentPageIndex,
|
|
required this.isOnDesktopAndWeb,
|
|
});
|
|
|
|
final int currentPageIndex;
|
|
final TabController tabController;
|
|
final void Function(int) onUpdateCurrentPageIndex;
|
|
final bool isOnDesktopAndWeb;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (!isOnDesktopAndWeb) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
|
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
IconButton(
|
|
splashRadius: 16.0,
|
|
padding: EdgeInsets.zero,
|
|
onPressed: () {
|
|
if (currentPageIndex == 0) {
|
|
return;
|
|
}
|
|
onUpdateCurrentPageIndex(currentPageIndex - 1);
|
|
},
|
|
icon: const Icon(Icons.arrow_left_rounded, size: 32.0),
|
|
),
|
|
TabPageSelector(
|
|
controller: tabController,
|
|
color: colorScheme.surface,
|
|
selectedColor: colorScheme.primary,
|
|
),
|
|
IconButton(
|
|
splashRadius: 16.0,
|
|
padding: EdgeInsets.zero,
|
|
onPressed: () {
|
|
if (currentPageIndex == 2) {
|
|
return;
|
|
}
|
|
onUpdateCurrentPageIndex(currentPageIndex + 1);
|
|
},
|
|
icon: const Icon(Icons.arrow_right_rounded, size: 32.0),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|