Я реализую степпер, в котором содержимое отображает список вариантов.В зависимости от того, где находится шаг на экране, скроллер выталкивает заголовок из поля зрения и отображает только часть списка при нажатии.Это не подходит с точки зрения UX.
Я пытался изменить физику на ClampingScrollPhysics (), как советовали в комментариях к виджету, но это не решает проблему.Ниже урезанная версия программы, чтобы помочь другим воссоздать - просто вставьте в демонстрационный проект флаттера.
Я также обновил флаттер: -)
class _MyHomePageState extends State<MyHomePage> {
static YourAge yourAge = YourAge();
static Widget _ageSelector = CustomSelectorFromList(
selections: yourAge.valueList,
initialSelection: yourAge.currentSelectionIndex,
onSelectionChanged: (int choice) {
yourAge.value = yourAge.valueList[choice];
});
List<Step> _listSteps = [
Step(
title: Text("Step 1"),
content: _ageSelector,
),
Step(
title: Text("Step 2"),
content: _ageSelector,
),
Step(
title: Text("Step 3"),
content: _ageSelector,
),
Step(
title: Text("Step 4"),
content: _ageSelector,
),
Step(
title: Text("Step 5"),
content: _ageSelector,
),
Step(
title: Text("Step 6"),
content: _ageSelector,
),
Step(
title: Text("Step 7"),
content: _ageSelector,
),
];
static int _currentStep = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: <Widget>[
Expanded(
child: Container(
child: Stepper(
steps: _listSteps,
physics: ClampingScrollPhysics(),
currentStep: _currentStep,
onStepTapped: (step) {
setState(() {
_currentStep = step;
});
},
),
),
),
],
));
}
}
abstract class DiscreteParameter {
final String _yourValueKey;
final List<String> _valueList;
final String _defaultValue;
DiscreteParameter(this._yourValueKey, this._valueList, this._defaultValue);
String _value;
String get value => _value;
set value(String value) {
_value = value;
}
int get currentSelectionIndex => _valueList.indexOf(_value);
set currentSelectionIndex(int index) => () {
_value = _valueList[index];
};
List<String> get valueList => _valueList;
}
class YourAge extends DiscreteParameter {
static String _yourAgeKey = 'yourAge';
YourAge() : super(_yourAgeKey, _ageList, aged26to35);
//String _yourAge = aged26to35;
static const String agedUpto15 = "<15";
static const String aged16to25 = "16-25";
static const String aged26to35 = "26-35";
static const String aged36to45 = "36-45";
static const String aged46to55 = "46-55";
static const String aged56to65 = "56-65";
static const String aged66plus = "66+";
static const List<String> _ageList = [
agedUpto15,
aged16to25,
aged26to35,
aged36to45,
aged46to55,
aged56to65,
aged66plus
];
}
class CustomSelectorFromList extends StatefulWidget {
final Function(int) onSelectionChanged;
final int initialSelection;
final List<String> selections;
@override
_CustomSelectorFromListState createState() => _CustomSelectorFromListState(
onSelectionChanged: onSelectionChanged,
initialSelection: initialSelection,
selections: selections);
//include a callback function to parent to react to state change
CustomSelectorFromList(
{Key key,
@required this.selections,
@required this.onSelectionChanged,
@required this.initialSelection});
}
class _CustomSelectorFromListState extends State<CustomSelectorFromList> {
Function(int) onSelectionChanged;
final int initialSelection;
final List<String> selections;
int _listLength;
int _value = 0;
_CustomSelectorFromListState(
{Key key,
@required this.selections,
@required this.onSelectionChanged,
@required this.initialSelection}) {
//state is preserved so can be set from user "shared preferences"
_value = initialSelection;
_listLength = selections.length;
}
@override
Widget build(BuildContext context) {
//debugPrint("list length: ${selections.length.toString()}");
return Wrap(
direction: Axis.vertical,
children: List<Widget>.generate(
_listLength,
(int index) {
return ChoiceChip(
label: Text(
"${selections[index]}",
style: TextStyle(
color: _value == index ? Colors.white70 : Colors.blueGrey),
),
selectedColor: Colors.blueGrey,
disabledColor: Colors.white70,
//labelPadding: EdgeInsets.symmetric(),
padding: const EdgeInsets.all(10),
selected: _value == index,
onSelected: (bool selected) {
setState(() {
_value = selected ? index : null;
});
//callback to parent widget - index of selected item
onSelectionChanged(index);
},
);
},
).toList(),
);
}
}
Я ожидаю onTap изшаг, чтобы прокрутить, чтобы показать заголовок шага и содержание ниже.Но если я открою шаг 1, не прокручивайте и не нажимайте шаг 2, тогда заголовок вылетает вверх из поля зрения, и отображаются только несколько нижних фишек выбора, вынуждая пользователя перетащить список вниз, чтобы просмотреть все варианты.