Reputation: 584
I want to create a horizontal stepper, which is easy I know, but this time, the count of steps should large.
Just to give an example, this is what I am doing for the vertical,
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new HomePage(),
);
}
}
class HomePage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
child: new ListView(
children: <Widget>[
new Text("Helllo "),
new Text( " Welcome"),
new Text (" Yaaa0"),
new SimpleWidget(),
],
), ),
);
}
}
class SimpleWidget extends StatefulWidget {
@override
SimpleWidgetState createState() => new SimpleWidgetState();
}
class SimpleWidgetState extends State<SimpleWidget> {
int stepCounter = 0;
List<Step> steps = [];
@override
void initState() {
prepareState();
super.initState();
}
void prepareState(){
for (var i= 0; i<100; i++){
var stepVal = new Step(
title:new Text("Step $i"),
content: new Text("This is the child of $i step"),
isActive: true,
);
steps.add(stepVal);
}
}
@override
Widget build(BuildContext context) {
return new Container(
child: new Stepper(
type: StepperType.vertical,
physics : ClampingScrollPhysics(),
currentStep: this.stepCounter,
steps: steps,
onStepTapped: (step) {
setState(() {
stepCounter = step;
});
},
onStepCancel: () {
setState(() {
stepCounter > 0 ? stepCounter -= 1 : stepCounter = 0;
});
},
onStepContinue: () {
setState(() {
stepCounter < steps.length - 1 ? stepCounter += 1 : stepCounter = 0;
});
},
),
);
}
}
As soon as I try to recreate this in the horizontal mode, it shows nothing. I have tried to make the listView
horizontal, I have tried to make the stepper horizontal, both individually and also together. None works. You can try that in the dartpad.
My question : 1. How to make a Stepper in horizontal that is scrollable in the horizontal mode. 2. The content of the Stepper is scrollable , I can see that. Can it be switched off?
Upvotes: 7
Views: 27087
Reputation: 531
use this class
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:hexcolor/hexcolor.dart';
class StepProgressView extends StatelessWidget {
final double _width;
final List<String> _titles;
final int _curStep;
final Color _activeColor;
final Color _inactiveColor = HexColor("#E6EEF3");
final double lineWidth = 3.0;
StepProgressView(
{Key key,
@required int curStep,
List<String> titles,
@required double width,
@required Color color})
: _titles = titles,
_curStep = curStep,
_width = width,
_activeColor = color,
assert(width > 0),
super(key: key);
Widget build(BuildContext context) {
return Container(
width: this._width,
child: Column(
children: <Widget>[
Row(
children: _iconViews(),
),
SizedBox(
height: 8,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _titleViews(),
),
],
));
}
List<Widget> _iconViews() {
var list = <Widget>[];
_titles.asMap().forEach((i, icon) {
var circleColor = (i == 0 || _curStep > i + 1) ? _activeColor : _inactiveColor;
var lineColor = _curStep > i + 1 ? _activeColor : _inactiveColor;
var iconColor = (i == 0 || _curStep > i + 1) ? _activeColor : _inactiveColor;
list.add(
Container(
width: 20.0,
height: 20.0,
padding: EdgeInsets.all(0),
decoration: new BoxDecoration(
/* color: circleColor,*/
borderRadius: new BorderRadius.all(new Radius.circular(22.0)),
border: new Border.all(
color: circleColor,
width: 2.0,
),
),
child: Icon(
Icons.circle,
color: iconColor,
size: 12.0,
),
),
);
//line between icons
if (i != _titles.length - 1) {
list.add(Expanded(
child: Container(
height: lineWidth,
color: lineColor,
)));
}
});
return list;
}
List<Widget> _titleViews() {
var list = <Widget>[];
_titles.asMap().forEach((i, text) {
list.add(Text(text, style: TextStyle(color: HexColor("#000000"))));
});
return list;
}
}
declare list and int variable inside class you want to use
final List<String> titles = [TextConstant.CART, TextConstant.ADDRESS, TextConstant.PAYMENT];
int _curStep = 1;
finally use above class
StepProgressView(width: MediaQuery.of(context).size.width,
curStep: _curStep,
color: Color(0xff50AC02),
titles: titles),
Upvotes: 8
Reputation: 5984
A very easy step to create a number stepper is
Container(
margin: const EdgeInsets.only(top: 4, right: 6),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.red, width: 2),
borderRadius: BorderRadius.circular(2),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
child: Icon(Icons.remove, color: Colors.red),
onTap: _dicrement,
),
Container(
margin: EdgeInsets.only(right: 8, left: 8),
child: Text(
_currentCount.toString(),
style: TextStyle(fontWeight: FontWeight.bold),
),
),
InkWell(
child: Icon(Icons.add, color: Colors.red),
onTap: _increment,
),
],
),
),
Upvotes: 0
Reputation: 153
You can create Horizontal Stepper in Flutter without any external package also like by following This will work fine and use StatefulWidget to put this code inside it (StatefulWidget).
int _currentStep = 0;
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(
child: Stepper(
type: StepperType.horizontal,
physics: ScrollPhysics(),
currentStep: _currentStep,
onStepTapped: (step) => tapped(step),
onStepContinue: continued,
onStepCancel: cancel,
steps: <Step>[
Step(
title: new Text(''),
content: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Email Address'),
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
),
],
),
isActive: _currentStep >= 0,
state: _currentStep >= 0 ?
StepState.complete : StepState.disabled,
),
Step(
title: new Text(''),
content: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Home Address'),
),
TextFormField(
decoration: InputDecoration(labelText: 'Postcode'),
),
],
),
isActive: _currentStep >= 0,
state: _currentStep >= 1 ?
StepState.complete : StepState.disabled,
),
Step(
title: new Text(''),
content: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Mobile Number'),
),
],
),
isActive:_currentStep >= 0,
state: _currentStep >= 2 ?
StepState.complete : StepState.disabled,
),
Step(
title: new Text(''),
content: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'Mobile Number'),
),
],
),
isActive:_currentStep >= 0,
state: _currentStep >= 3 ?
StepState.complete : StepState.disabled,
),
],
),
),
],
),
);
}
tapped(int step){
setState(() => _currentStep = step);
}
continued(){
_currentStep < 3 ?
setState(() => _currentStep += 1): null;
}
cancel(){
_currentStep > 0 ?
setState(() => _currentStep -= 1) : null;
}
Upvotes: 3
Reputation: 361
I am sure you have got the answer, but maybe this is for someone who is looking for a package instead of creating a custom one. Here is something that I found good, please do check out and see if it fits in your use-case.
https://pub.dev/packages/im_stepper
Upvotes: 0
Reputation: 81
try this example, e.g: conf pubspec file: fa_stepper: ^0.0.2
, then flutter packages get
, after that: using FAStepper
constructor, define something like this:
Widget w1(BuildContext context) {
return Scaffold(
// Body
body: Container(
child: FAStepper(
// physics: ClampingScrollPhysics(),
// Using a variable here for handling the currentStep
currentStep: this.currentStep,
// List the steps you would like to have
titleHeight: 120,
steps: mySteps,
// Define the type of Stepper style
// StepperType.horizontal : Horizontal Style
// StepperType.vertical : Vertical Style
type: FAStepperType.horizontal,
titleIconArrange: FAStepperTitleIconArrange.column,
stepNumberColor: Colors.pinkAccent,
// Know the step that is tapped
onStepTapped: (step) {
// On hitting step itself, change the state and jump to that step
setState(() {
// update the variable handling the current step value
// jump to the tapped step
currentStep = step;
});
// Log function call
print("onStepTapped : " + step.toString());
},
onStepCancel: () {
// On hitting cancel button, change the state
setState(() {
// update the variable handling the current step value
// going back one step i.e subtracting 1, until its 0
if (currentStep > 0) {
currentStep = currentStep - 1;
} else {
currentStep = 0;
}
});
// Log function call
print("onStepCancel : " + currentStep.toString());
},
// On hitting continue button, change the state
onStepContinue: () {
setState(() {
// update the variable handling the current step value
// going back one step i.e adding 1, until its the length of the step
if (currentStep < mySteps.length - 1) {
currentStep = currentStep + 1;
} else {
currentStep = 0;
}
});
// Log function call
print("onStepContinue : " + currentStep.toString());
},
)),
);
}
Upvotes: 2
Reputation: 1969
Wrap the stepper with a ConstrainedBox
and set its height to a constant and make the StepperType
as horizontal
. You can check it in dartpad .
return ConstrainedBox(
constraints: BoxConstraints.tightFor(height: 500.0),
child: Stepper(
type: StepperType.horizontal,
),
);
Upvotes: 1
Reputation: 11
There is an issue about this on github https://github.com/flutter/flutter/issues/40601
BUT
This is what i m using right now
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme:ThemeData(
primarySwatch:Colors.amber
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class CustomStep {
final String title;
final Widget page;
CustomStep(
{@required this.title, @required this.page});
}
class MyWidget extends StatefulWidget {
const MyWidget({ Key key }) : super(key: key);
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
ScrollController _scrollController = new ScrollController();
static const double STEP_WIDTH = 90;
PageController pageController = PageController();
List<CustomStep> stepsList;
int currentPage=0;
@override
void initState() {
super.initState();
stepsList = [
CustomStep(
title: 'ddddd',
page: Placeholder(
color: Colors.pink,
),
),
CustomStep(
title: 'zzzzzzzz',
page: Placeholder(
color: Colors.deepPurple,
),
),
];
}
SizedBox buildStepDivider(int index) {
return SizedBox(
height: 90,
child: Container(
alignment: Alignment.topCenter,
child: Transform.translate(
offset: Offset(0, 16),
child: Container(
color: index < currentPage
? Theme.of(context).primaryColor
: Colors.grey,
width: 30,
height: 3,
padding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
);
}
buildStep(int index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: SizedBox(
height: 90,
width: STEP_WIDTH,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: index <= currentPage
? Theme.of(context).primaryColor
: Colors.grey[300],
),
padding: EdgeInsets.all(10),
child: Text((index + 1).toString()),
),
Expanded(
child: Text(
stepsList[index].title,
textAlign: TextAlign.center,
))
],
),
),
);
}
_buildStepper(int currentStep) {
Future.delayed(
Duration(milliseconds: 100),
() => _scrollController.animateTo((STEP_WIDTH * currentStep).toDouble(),
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut));
return Center(
child: SizedBox(
height: 110,
child: ListView.builder(
controller: _scrollController,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: stepsList.length,
itemBuilder: (ctx, index) => index < stepsList.length - 1
? Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
buildStep(index),
buildStepDivider(index)
],
)
:Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
buildStep(index)]) ),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('hello'), centerTitle: true),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_buildStepper(currentPage),
Expanded(
child: PageView.builder(
controller: pageController,
physics: NeverScrollableScrollPhysics(),
onPageChanged: (index) {
setState(() {
currentPage = index;
});
},
itemCount: stepsList.length,
itemBuilder: (ctx, index) =>
stepsList[index].page,
)),
],
),
);
}
}
Upvotes: 0