In Flutter, I have built a carousel PageView for a list of widgets (media files). I want a seamless way to add comments to the currentPage widget. I don’t want a TextField permanently attached at the bottom, but switch from IconButton to TextField upon user engagement. What I have right now works, but it’s really ugly :/
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class MyWidget extends StatefulWidget {
final int? initialIndex;
final List<String> items;
const MyWidget({super.key, this.initialIndex, required this.items});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late int _currentPage;
late final PageController _controller =
PageController(initialPage: widget.initialIndex ?? _currentPage);
final commentFN = FocusNode();
bool _hasFocus = false;
@override
void initState() {
_currentPage = widget.initialIndex ?? 0;
_controller.addListener(() {
setState(() {
_currentPage = _controller.page!.toInt();
});
});
commentFN.addListener(() {
setState(() {
_hasFocus = commentFN.hasFocus;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${_currentPage + 1} of 10'),
),
body: Stack(
children: [
GestureDetector(
onTapDown: (details) {
if (details.localPosition.dx <
MediaQuery.of(context).size.width / 2) {
_currentPage == 0
? null
: _controller.previousPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
} else {
_currentPage == widget.items.length - 1
? context.pop(context)
: _controller.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
},
child: PageView.builder(
controller: _controller,
itemCount: widget.items.length,
itemBuilder: (context, index) {
return Center(child: Text(widget.items[index]));
},
),
),
_hasFocus
? Positioned(
bottom: 0,
left: 15,
right: 15,
child: TextField(
focusNode: commentFN,
autofocus: _hasFocus,
),
)
: Positioned(
bottom: 20,
right: 15,
child: Column(
children: [
IconButton(
onPressed: () {
setState(() {
_hasFocus = true;
});
},
icon: const Icon(Icons.comment),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.face),
),
],
),
),
],
),
);
}
@override
void dispose() {
_controller.dispose();
commentFN.dispose();
super.dispose();
}
}
1