Flutter CupertinoPicker не помещается в экран

#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. Протестировано, работает как шарм. Спасибо за быстрое решение и подробное описание, помеченное как ответ.