so I want to make a multipage form that has a linear progress indicator at the top instead of the normal stepper widget one, I've tried SO many different websites and nothing is both working and has everything I need,
what I want is:
any advice on how I'd do this would be so so so appreciated and thank you in advance
at first, it's a shorthand solution (fast solution) for your problem.
the below code should be refactored and and can be enhanced, but i'm presenting an idea. here's the code, the coming is the driver class that manages the Linear Progress Indicator(LPI) and page view.
class HomeScreen extends StatefulWidget {
HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
var pages = [ FirstPage(),SecondPage(), ThirdPage(),FourthPage(),];
int currentIndex = 0;
@override
Widget build(BuildContext context) {
print('called');
return SafeArea(
child: Scaffold(
body: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 10,vertical: 30),
child: LinearProgressIndicator(
color: Colors.blue.shade700,
value: (currentIndex+1) /4,
borderRadius: BorderRadius.circular(10),
minHeight: 20,
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(15),
child: PageView(
children: pages,
onPageChanged: (i){
setState(() {
currentIndex = i;
});
},
padEnds: true,
),
),
),
],
),
),
);
}
}
ok, pages variable is a list of widgets, in which every widget holds the presented content in every page. it's a page view
look at FirstPage
Widget implementation
class FirstPage extends StatelessWidget {
static var controller = TextEditingController();
const FirstPage({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('First Page'),
),
TextFormField(
controller: controller,
decoration: InputDecoration(
label: Text('Name'),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(width: 1,color: Colors.blue)
)
),
),
],
);
}
}
here's second page, regardless the number of pages you have. the third page will have the same implementation like the others.
class SecondPage extends StatelessWidget {
static var controller = TextEditingController();
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Second Page'),
),
TextFormField(
controller: controller,
decoration: InputDecoration(
label: Text('phone'),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(width: 1,color: Colors.blue)
)
),
),
],
);
}
}
if you notice every page (class) has a controller for its text field which enables us to get the written text at last.
the last page of page view
class FourthPage extends StatelessWidget {
static var controller = TextEditingController();
const FourthPage({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Fourth Page'),
),
TextFormField(
controller: controller,
onFieldSubmitted: (s){
Navigator.of(context).push(
MaterialPageRoute(
builder: (context)=> FinalScreen(),
settings: RouteSettings(
arguments: {
'first' : FirstPage.controller.text,
'second' : SecondPage.controller.text,
'third' : ThirdPage.controller.text,
'fourth' : FourthPage.controller.text
},
)
)
);
},
decoration: InputDecoration(
label: Text('Password'),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(width: 1,color: Colors.blue)
)
),
),
],
);
}
}
the fourth and last page has a critical lines of code that are executed when user submits the value to text field( it navigate to the home or final page and send data to that page using route settings ).
here's the final page which presents user gathered data
class FinalScreen extends StatelessWidget {
const FinalScreen({super.key});
@override
Widget build(BuildContext context) {
var data = ModalRoute.of(context)?.settings.arguments as Map<String,String>;
return Scaffold(
appBar: AppBar(
title: Text('Final Screen'),
centerTitle: true,
),
body: Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('first page data: ${data['first']}'),
Text('second page data: ${data['second']}'),
Text('third page data: ${data['third']}'),
Text('fourth page data: ${data['fourth']}'),
],
),
),
);
}
}
notice:
hope it helps you.