#flutter #dart
#флаттер #dart
Вопрос:
Я создаю свой первый проект flutter, и на данный момент я сталкиваюсь с огромной проблемой с CupertinoPicker. Похоже, он полностью функционален, но я не могу правильно встроить его в Stepper. Одновременно я вижу только один элемент, а не все колесо выбора. Есть идеи, как это решить?
Почти весь код :
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'objects/Course.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int selectedCourse = 0;
List<Course> courses;
int _currentstep = 0;
double _yearFrom = 1, _yearTo = 5;
double _currentSliderValue = 1;
go(int step) {
setState(() => _currentstep = step);
print(selectedCourse);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Stepper(
currentStep: _currentstep,
onStepContinue: () {
if (_currentstep != 1 amp;amp; selectedCourse >= 0) {
go(1);
} else {
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('Error !')));
}
},
onStepCancel: () {
if (_currentstep != 0) {
go(-1);
}
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Center(
child: Row(
children: <Widget>[
RaisedButton(
padding: const EdgeInsets.all(10.0),
color: Colors.blue,
child: Text(
"Next",
style: TextStyle(color: Colors.white),
),
onPressed: onStepContinue,
),
FlatButton(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text("Back"),
),
onPressed: onStepCancel,
),
],
),
);
},
steps: [
Step(
title: Text("Pick your study program"),
isActive: _currentstep == 0,
content: Center(
child: FutureBuilder<List<Course>>(
future: downloadData(), // function where you call your api
builder: (BuildContext context,
AsyncSnapshot<List<Course>> snapshot) {
// AsyncSnapshot<Your object type>
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: Text('Please wait its loading...'));
} else {
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return showCoursePicker();
// snapshot.data :- get your object which is pass from your downloadData() function
}
},
),
),
),
Step(
isActive: _currentstep == 1,
state: StepState.indexed,
title: const Text('Pick your study year'),
content: Column(
children: <Widget>[
Card(
child: Row(
children: [
Column(
children: [Text(_yearFrom.toInt().toString())],
),
Column(
children: [
Slider(
min: _yearFrom,
max: _yearTo == _yearFrom ? _yearTo 1 : _yearTo,
divisions: _yearTo == _yearFrom
? _yearTo.toInt() - _yearFrom.toInt() 1
: _yearTo.toInt() - _yearFrom.toInt(),
value: _currentSliderValue,
label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
],
),
Column(
children: [
Text(_yearTo.toInt().toString()),
],
)
],
),
),
],
),
)
],
),
);
}
Future<List<Course>> downloadData() async {
var response = await http
.get('https://lekcijas.va.lv/lekcijas_android/getAllCourseData.php');
var data = json.decode(response.body)["result"];
courses = List<Course>.from(data.map((x) => Course.fromJson(x)));
return Future.value(courses);
}
Widget showCoursePicker() {
return CupertinoPicker.builder(
childCount: courses.length,
itemExtent: 40,
useMagnifier: true,
magnification: 1.3,
onSelectedItemChanged: (value) {
selectedCourse = value;
print(selectedCourse);
setState(() {
_yearFrom = double.parse(courses[selectedCourse].course_from);
print(_yearFrom);
_yearTo = double.parse(courses[selectedCourse].course_to);
print(_yearTo);
});
},
itemBuilder: (ctx, index) {
return Center(
child: Text(
courses.isEmpty ? '' : courses[index].abbreviation,
),
);
});
}
}
Объектный код курса :
class Course {
final String id;
final String abbreviation;
final String course_from;
final String course_to;
Course({this.id, this.abbreviation, this.course_from, this.course_to});
factory Course.fromJson(Map<String, dynamic> json) {
return Course(
id: json['id'] as String,
abbreviation: json['abbreviation'] as String,
course_from: json['course_from'] as String,
course_to: json['course_to'] as String,
);
}
}
Рис :
Макет с помощью CupertinoPicker (видна только лупа)
Примечание: вам необходимо добавить зависимости в pubspec.yml :
dependencies:
http: ^0.12.2
Ответ №1:
Вы можете скопировать вставить выполнить полный код ниже
шага 1: установите Future
так, чтобы избежать перестроения, вызывающего перезагрузку данных
Future<List<Course>> _future;
...
@override
void initState() {
_future = downloadData();
...
child: FutureBuilder<List<Course>>(
future: _future,
Шаг 2: Используйте Container
для установки height
Widget showCoursePicker() {
return Container(
height: 250,
child: CupertinoPicker.builder(
рабочая демонстрация
полный код
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class Course {
final String id;
final String abbreviation;
final String course_from;
final String course_to;
Course({this.id, this.abbreviation, this.course_from, this.course_to});
factory Course.fromJson(Map<String, dynamic> json) {
return Course(
id: json['id'] as String,
abbreviation: json['abbreviation'] as String,
course_from: json['course_from'] as String,
course_to: json['course_to'] as String,
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int selectedCourse = 0;
List<Course> courses;
int _currentstep = 0;
double _yearFrom = 1, _yearTo = 5;
double _currentSliderValue = 1;
Future<List<Course>> _future;
go(int step) {
setState(() => _currentstep = step);
print(selectedCourse);
}
@override
void initState() {
_future = downloadData();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Stepper(
currentStep: _currentstep,
onStepContinue: () {
if (_currentstep != 1 amp;amp; selectedCourse >= 0) {
go(1);
} else {
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('Error !')));
}
},
onStepCancel: () {
if (_currentstep != 0) {
go(-1);
}
},
controlsBuilder: (BuildContext context,
{VoidCallback onStepContinue, VoidCallback onStepCancel}) {
return Center(
child: Row(
children: <Widget>[
RaisedButton(
padding: const EdgeInsets.all(10.0),
color: Colors.blue,
child: Text(
"Next",
style: TextStyle(color: Colors.white),
),
onPressed: onStepContinue,
),
FlatButton(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text("Back"),
),
onPressed: onStepCancel,
),
],
),
);
},
steps: [
Step(
title: Text("Pick your study program"),
isActive: _currentstep == 0,
content: Center(
child: FutureBuilder<List<Course>>(
future: _future, // function where you call your api
builder: (BuildContext context,
AsyncSnapshot<List<Course>> snapshot) {
// AsyncSnapshot<Your object type>
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: Text('Please wait its loading...'));
} else {
if (snapshot.hasError)
return Center(child: Text('Error: ${snapshot.error}'));
else
return showCoursePicker();
// snapshot.data :- get your object which is pass from your downloadData() function
}
},
),
),
),
Step(
isActive: _currentstep == 1,
state: StepState.indexed,
title: const Text('Pick your study year'),
content: Column(
children: <Widget>[
Card(
child: Row(
children: [
Column(
children: [Text(_yearFrom.toInt().toString())],
),
Column(
children: [
Slider(
min: _yearFrom,
max: _yearTo == _yearFrom ? _yearTo 1 : _yearTo,
divisions: _yearTo == _yearFrom
? _yearTo.toInt() - _yearFrom.toInt() 1
: _yearTo.toInt() - _yearFrom.toInt(),
value: _currentSliderValue,
label: _currentSliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
});
},
),
],
),
Column(
children: [
Text(_yearTo.toInt().toString()),
],
)
],
),
),
],
),
)
],
),
);
}
Future<List<Course>> downloadData() async {
var response = await http
.get('https://lekcijas.va.lv/lekcijas_android/getAllCourseData.php');
var data = json.decode(response.body)["result"];
courses = List<Course>.from(data.map((x) => Course.fromJson(x)));
return Future.value(courses);
}
Widget showCoursePicker() {
return Container(
height: 250,
child: CupertinoPicker.builder(
childCount: courses.length,
itemExtent: 40,
useMagnifier: true,
magnification: 1.3,
onSelectedItemChanged: (value) {
selectedCourse = value;
print(selectedCourse);
setState(() {
_yearFrom = double.parse(courses[selectedCourse].course_from);
print(_yearFrom);
_yearTo = double.parse(courses[selectedCourse].course_to);
print(_yearTo);
});
},
itemBuilder: (ctx, index) {
return Center(
child: Text(
courses.isEmpty ? '' : courses[index].abbreviation,
),
);
}),
);
}
}
Комментарии:
1. Протестировано, работает как шарм. Спасибо за быстрое решение и подробное описание, помеченное как ответ.