Reputation: 135
I'm using flutter horizontal stepper and there are 4 steps, in the 3rd step there is a form, which the content exceeds the screen height. Since stepper is handling scrolling, I didn't need to use a scroll there. The issue is when goes to 3rd screen, the UI content scrolls down. It should appear from the bottom. Any idea what I can do about it?
Upvotes: 1
Views: 2864
Reputation: 1150
You need to make a copy of the stepper then add the scroll controller to its method.
class TmpStepper extends StatefulWidget {
const TmpStepper({
super.key,
required this.steps,
this.physics,
this.type = TmpStepperType.vertical,
this.scrollController,
this.currentStep = 0,
this.onStepTapped,
this.onStepContinue,
this.onStepCancel,
this.controlsBuilder,
this.elevation,
this.margin,
}) : assert(steps != null),
assert(type != null),
assert(currentStep != null),
assert(0 <= currentStep && currentStep < steps.length);
// Add your scrollcontroller
final ScrollController? scrollController;
Then under the method _buildHorizontal()
add that scrollController
defined above widget.scrollController
as shown bellow.
return Column(
children: <Widget>[
Material(
elevation: widget.elevation ?? 2,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 24.0),
child: Row(
children: children,
),
),
),
),
Expanded(
child: ListView(
physics: widget.physics,
padding: const EdgeInsets.all(24.0),
controller: widget.scrollController,
children: <Widget>[
AnimatedSize(
curve: Curves.fastOutSlowIn,
duration: kThemeAnimationDuration,
child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: stepPanels),
),
_buildVerticalControls(widget.currentStep),
],
),
),
],
);
initialize the stepperScrollController on your stateful widget
class MyStepperScreen extends StatefulWidget {
const MyStepperScreen({Key? key}) : super(key: key);
@override
State<MyStepperScreen> createState() => _MyStepperScreenState();
}
class _MyStepperScreenState extends State<MyStepperScreen> {
late ScrollController _stepperScrollController;
@override
void initState() {
super.initState();
_stepperScrollController = ScrollController(keepScrollOffset:false)..addListener(() => _controlScroll());
}
// You can do whatever you want with the scrollController listener
void controlScroll() {
print(stepperScrollController.offset);
}
@override
Widget build(BuildContext context) {
return TmpStepper(
elevation: 0,
margin: EdgeInsets.zero,
type: TmpStepperType.horizontal,
physics: ClampingScrollPhysics(),
currentStep: 0,
scrollController: _stepperScrollController,
onStepTapped: (step) {
_stepperScrollController.jumpTo(0.0); // You should write it in a proper way as this is just for example
},
steps: []
);
}
}
Upvotes: 0
Reputation: 31356
Using LayoutBuilder
and some investigation about the default Stepper
elements sizes you can achieve the wanted result.
Stepper
with a LayoutBuilder
NeverScrollableScrollPhysics()
(You can do that when the user is in the page where you have the form only)if you are using the default Stepper widget controls the total of height is:
height: constraints.maxHeight - (72 + 48 + 24 + 24)
Code:
/// Flutter code sample for Stepper
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatefulWidget(),
),
),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _index = 0;
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
print(constraints);
return Stepper(
currentStep: _index,
type: StepperType.horizontal,
onStepCancel: () {
if (_index > 0) {
setState(() {
_index -= 1;
});
}
},
onStepContinue: () {
if (_index <= 0) {
setState(() {
_index += 1;
});
}
},
onStepTapped: (int index) {
setState(() {
_index = index;
});
},
physics: NeverScrollableScrollPhysics(),
steps: <Step>[
Step(
title: const Text('Step 1 title'),
content: Container(alignment: Alignment.centerLeft, child: const Text('Content for Step 1')),
),
Step(
title: Text('Step 2 title'),
content: Container(
height: constraints.maxHeight - (72 + 48 + 24 + 24),
child: SingleChildScrollView(
reverse: true,
child: Column(
children: [
for (int i = 0; i < 20; i++)
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
decoration: InputDecoration(hintText: 'Hint $i'),
),
),
],
),
),
),
),
],
);
},
);
}
}
Upvotes: 0
Reputation: 302
You should use singlechildecrollview and scroll controller and set srollposition accordingly through scroll controller
Upvotes: 0