My main issue is with the content in the first child of PageView where if you scroll the content vertically you will see that the Text('Hello') is behind the PageIndicator. How do I create the PageView so that is uses a scrollable region that excludes the PageIndicator area?
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
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(
controller: _pageViewController,
onPageChanged: _handlePageViewChanged,
children: <Widget>[
SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 800.0,
child: Text('First Page', style: textTheme.titleLarge),
),
Text('Hello',
style: Theme.of(context)
.primaryTextTheme
.headlineLarge
?.copyWith(color: Colors.black)),
],
),
),
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 {
if (kIsWeb) {
return true;
}
switch (defaultTargetPlatform) {
case TargetPlatform.macOS:
case TargetPlatform.linux:
case TargetPlatform.windows:
return true;
case TargetPlatform.android:
case TargetPlatform.iOS:
case TargetPlatform.fuchsia:
return false;
}
}
}
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.background,
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,
),
),
],
),
);
}
}

Just like @chunhunghan said.
You can change the stack with column and wrap your pageview with expanded to make it expand.
The final code below:
This is the result:
Hopefully it can solve your problem, Thanks