Flutter: особенности отображения listview внутри виджета showdialog

А именно, проблема заключается в том, что ничего не отображается, пока listview не будет обёрнут в контейнер с указанной высотой. И это на самом деле проблема, т.к. в этом случае нельзя указать «резиновую» высоту. Обёртывание в виджет Expanded тоже не поможет. Остаётся один выход — рассчитывать высоту в случае динамического списка. Например:

            Container(
              height: EzsInfo["connectors"].length.toDouble()*72,
              width: double.maxFinite,
              child:  ListView.builder(
                  shrinkWrap: true,
                  physics: NeverScrollableScrollPhysics(),
                  padding: const EdgeInsets.all(8),
                  itemCount: EzsInfo["connectors"].length,
                  itemBuilder: (BuildContext context, int index) {
                    return Container(
                      //padding: EdgeInsets.symmetric(vertical: 10),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Row(
                              mainAxisSize: MainAxisSize.max,
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                Padding(
                                  padding: const EdgeInsets.only(bottom: 0,left: 0,right: 10),
                                  child: Text(EzsInfo["connectors"][index]["station_name"],style: TextStyle(fontWeight: FontWeight.w100, fontSize: 8.0, color: Colors.black)),
                                ),
                                Container(
                                  width: 6.0,
                                  height: 6.0,
                                  decoration: BoxDecoration(
                                    color: EzsInfo["connectors"][index]["status"]==3?Colors.grey:Colors.green,
                                    shape: BoxShape.circle,
                                  ),),
                                Padding(
                                  padding: const EdgeInsets.only(bottom: 0,left: 2,right: 0),
                                  child: Text(EzsInfo["connectors"][index]["status_name"],style: TextStyle(fontWeight: FontWeight.w100, fontSize: 8.0, color: Colors.black)),
                                ),

                              ],
                            ),
                            Row(
                              children: [
                                IconButton (
                                  padding: const EdgeInsets.only(bottom: 0,left: 0,right: 0),
                                  icon: Image.asset('lib/images/'+EzsInfo["connectors"][index]["url_connector"],height: 32,),
                                  onPressed: () {print('IconButton pressed ...');},
                                ),
                                Container(
                                  alignment: Alignment.topLeft,
                                  width: 150,
                                  child: Column(
                                    children: [
                                      Align(
                                        alignment: Alignment.topLeft,
                                        child: Text(EzsInfo["connectors"][index]["connector_name"],style: TextStyle(fontSize: 12.0, color: Colors.black),textAlign: TextAlign.left,),
                                      ),
                                      Align(
                                        alignment: Alignment.topLeft,
                                        child: Text(EzsInfo["connectors"][index]["maxpower"].toString()+" кВт",style: TextStyle(fontSize: 12.0, color: Colors.black),textAlign: TextAlign.left),
                                      ),
                                    ],
                                  ),
                                ),
                                Text(EzsInfo["connectors"][index]["price"].toString()+"Р кВт*ч",style: TextStyle(fontSize: 12.0, color: Colors.black)),
                              ],
                            ),
                            new Divider(),
                          ],
                        )
                    );
                  }
              ),
            )

Результат:

Flutter: показ прелоадера при загрузке данных в виджете showDialog

Задача: при отображении данных при помощи виджета showDialog, необходимо показывать «прелоадер» во время загрузки данных со стороннего ресурса.

Решение: для отображения прелоадера, используем пакет card_loader. Однако! дело осложняется тем, что виджет showDialog не имеет метода setState, соответственно у нас нет возможности изменить уже отображенные данные, после окончания загрузки.

Для обхода этого ограничения, оформим showDialog как полноценный StatefulWidget с получением в связи с этим стандартных плюшек в виде setState, а так-же возможность вызова своих процедур после окончания отображения виджета:

import 'package:flutter/material.dart';
import 'package:card_loading/card_loading.dart';
import 'dart:convert';

class MyMeDialogInfo extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyMeDialogInfoState();
  }
}
class _MyMeDialogInfoState extends State<MyMeDialogInfo> {
  bool info_is_load=false;

  void RefreshMeDialogData(context){
    TRequests req=new TRequests();
    req.request("adfserfserf", {}), (List result){
      setState(() {
        //info_is_load=true;
      });
    }, (String error){
    });

  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) => RefreshMeDialogData(context));  // эвент после того как страница отобразилась - обновим данные по пользователю
  }

  @override
  Widget build(BuildContext context) {
    return Align (
        alignment: Alignment.bottomCenter,
        child:
        Container(
            width: double.infinity,
            decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(32.0),
                    topRight: Radius.circular(32.0))),
            child:Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  // заголовок окна
                  Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Material(
                        child: Text("Заголовок окна", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14.0, color: Colors.black))),
                  ),
                  Container(
                    width: MediaQuery.of(context).size.width,
                    height: MediaQuery.of(context).size.height - 220,
                    decoration: BoxDecoration(),
                    child:
                    SingleChildScrollView(
                      child: Stack(
                        children: <Widget>[
                          Visibility(
                              visible: info_is_load,
                              child:
                              Padding(
                                padding: const EdgeInsets.all(16.0),
                                child: Material(
                                    child: Text("Тут перечисляем какую инфу загружаемую асинхронно", style: TextStyle(fontSize: 14.0, color: Colors.black))),
                              )
                          ),
                          Visibility(
                              visible: !info_is_load,
                              child:
                              Padding(
                                padding: const EdgeInsets.only(bottom: 20,left: 20,right: 20),
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: const [
                                    CardLoading(
                                      height: 30,
                                      borderRadius: BorderRadius.all(Radius.circular(15)),
                                      width: 100,
                                      margin: EdgeInsets.only(bottom: 10),
                                    ),
                                    CardLoading(
                                      height: 100,
                                      borderRadius: BorderRadius.all(Radius.circular(15)),
                                      margin: EdgeInsets.only(bottom: 10),
                                    ),
                                    CardLoading(
                                      height: 30,
                                      width: 200,
                                      borderRadius: BorderRadius.all(Radius.circular(15)),
                                      margin: EdgeInsets.only(bottom: 10),
                                    ),
                                  ],
                                ),
                              )
                          )
                        ],
                      ),
                    ),
                  )
                ]
            )
        )
    );
  }
}

class TMeDialog {
  void MeDialogInfoDialog(BuildContext context,Map ezs){
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return MyMeDialogInfo(ezs);
      },
    );
  }
}

nmp — ошибка проверки самоподписанного сертификата

При установке модуля через nmp, иногда возникает ошибка вида:

reason: self-signed certificate in certificate chain

Причин возникновения её может быть множество. У меня например — из-за антивируса Касперского, который имеет свойство подпехивать свои сертификаты в промежуток трафика SSL. Что делать? Одним из решений может быть отключение у npm проверки подлинности SSL. Это конечно плохое решение, но в моём случае оказалось единственным вариантом

npm set strict-ssl false

Flutter: ошибка присвоения переменных Safe nulled

С 3 версии Flatter, если вам нужна переменная которая может быть null, то это нужно объявить явно при помощи оператора ?:

double?latitude;

Возникает смесь, переменными, которые объявлены традиционно вида:

double aaa=10.0;

И если далее в программе мы захотим присвоить значение одной переменной другой:

aaa=latitude;

Мы получим ошибку вида:

dart A value of type 'double?' can't be assigned to a variable of type 'double' because 'double?' is nullable and 'double' isn't

Как избежать? Достаточно при присвоении использовать оператор ??, при помощи которого можно назначить значение «по умолчанию» для null:

aa=latitude??0;

Flutter: обновление виджета одного класса из другого класса

Задача: в одном из фоново работающих классов (WebSocket клиент) изменилось значение отображаемое в другом классе. Необходимо вызвать setState для изменившегося виджета

Решение: воспользуемся классом StreamController. По сути это «конвеер», в который можно что-то ложить и объявлять «слушателя», который будет что-то делать если в «конвеер» попадет какое-либо значение.

Объявим в глобальных переменных контроллер, «конвеера»:

library me_flutter.globals;
var sup_controller = new StreamController<String>.broadcast();

Далее в классе ИЗ которого нужно сообщить что что-то изменилось, ложим в «конвеер» данные:

globals.sup_controller.add("new_message");

А в классе, который должен отображать изменения, объявим «слушателя» в initState:

class Support extends StatefulWidget {
  @override
  _SupportState createState() => _SupportState();
}
class _SupportState extends State<Support> {
  StreamSubscription?subscription;
  @override
  void initState() {
    super.initState();
    print("-оформляем подписку..");
      subscription = globals.sup_controller.stream.listen((index) {
        print("чтото пришло!");
        setState(() {
          _scrollDown();
        });
      });
....

Не забудем при выходе из класса, убить подписку:

  @override
  void dispose() {
    print("--отменил подписку..");
    subscription?.cancel();
    super.dispose();
  }
1 52 53 54 55 56 308