Как изменить логическое значение внутри виджета listview.builder и передать его другому виджету?

#java #flutter #listview

Вопрос:

В настоящее время я разрабатываю приложение на Android Studio для включения и выключения грузовика. Приложение будет клиентом нашего сервера TCP, который будет отправлять данные о грузовике.

У меня есть проблема при реализации истории состояния грузовика. Прямо сейчас я могу отображать полученные данные в истории. Однако мы хотим, чтобы кнопки воспроизведения и остановки грузовика были недоступны, пока сервер не выпустил их с сообщением «разблокировано». Я начинаю реализовывать это с вызова логической переменной isButtonClickable , инициализируемой значением true.

Я вставил условие в OnPressed{} каждую из кнопок. Итак, я сталкиваюсь с проблемой, когда пытаюсь проанализировать сообщение, и я хочу посмотреть, равно ли оно «Заблокировать» или «Разблокировать», чтобы изменить состояние логической переменной.

Я попытался проверить входящие сообщения, когда я читаю и отображаю их в своем Listview.Builder , но я получаю сообщение об ошибке, потому что его невозможно использовать SetState() во время создания виджета приложением.

Вот как выглядит мой экран в данный момент:

введите описание изображения здесь

введите описание изображения здесь

Вот что я пытаюсь сделать :

 import 'package:bubble/bubble.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:untitled/truck_icons.dart';
import '../models/message.dart';
import '../utils/validators.dart';
import '../tcp_bloc/tcp_bloc.dart';
import 'about_page.dart';

class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  TcpBloc? _tcpBloc;
  TextEditingController? _hostEditingController;
  TextEditingController? _portEditingController;
  TextEditingController? _chatTextEditingController;

  bool isButtonClickable=true;
  void ButtonUnclickable(){
    setState(() {
      isButtonClickable=false;
    });
  }
  void ButtonClickable(){
    setState(() {
      isButtonClickable=true;
    });
  }

  void TestMessage(TcpState tcpState,int idx){
    Message m = tcpState.messages[idx];
    if(m.message=="Unlock"){
      ButtonClickable();
    }else{
      ButtonUnclickable();
    }
  }

  @override
  void initState() {
    super.initState();
    _tcpBloc =  BlocProvider.of<TcpBloc>(context);

//Default parameter of my TCP server
    _hostEditingController = new TextEditingController(text: '192.168.1.28');
    _portEditingController = new TextEditingController(text: '9632');
    _chatTextEditingController = new TextEditingController(text: '');

    _chatTextEditingController!.addListener(() {
      setState(() {

      });
    });
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('Truck Application')
      ),
      body: BlocConsumer<TcpBloc, TcpState>(
        bloc: _tcpBloc,
        listener: (BuildContext context, TcpState tcpState) {
          if (tcpState.connectionState == SocketConnectionState.Connected) {
            ScaffoldMessenger.of(context)
              ..hideCurrentSnackBar();
          } else if (tcpState.connectionState == SocketConnectionState.Failed) {
            ScaffoldMessenger.of(context)
              ..hideCurrentSnackBar()
              ..showSnackBar(
                SnackBar(
                  content: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [Text("Connection failed"), Icon(Icons.error)],
                  ),
                  backgroundColor: Colors.red,
                ),
              );
          }
        },
        builder: (context, tcpState) {
          if (tcpState.connectionState == SocketConnectionState.None || tcpState.connectionState == SocketConnectionState.Failed) {
            return Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8.0),
//Checking IP/port TCP serveur
              child: ListView(
                children: [
                  TextFormField(
                    controller: _hostEditingController,
                    autovalidateMode : AutovalidateMode.always,
                    validator: (str) => isValidHost(str) ? null : 'Invalid hostname',
                    decoration: InputDecoration(
                      helperText: 'The ip address or hostname of the TCP server',
                      hintText: 'Enter the address here, e. g. 10.0.2.2',
                    ),
                  ),
                  TextFormField(
                    controller: _portEditingController,
                    autovalidateMode : AutovalidateMode.always,
                    validator: (str) => isValidPort(str) ? null : 'Invalid port',
                    decoration: InputDecoration(
                      helperText: 'The port the TCP server is listening on',
                      hintText: 'Enter the port here, e. g. 8000',
                    ),
                  ),
                  ElevatedButton(
//Checking host and port before connection attempt
                    child: Text('Connect'),
                    onPressed: isValidHost(_hostEditingController!.text) amp;amp; isValidPort(_portEditingController!.text)
                      ? () {
                        _tcpBloc!.add(
                          Connect(
                            host: _hostEditingController!.text,
                            port: int.parse(_portEditingController!.text)
                          )
                        );
                      }
                      : null,
                  )
                ],
              ),
            );
          } else if (tcpState.connectionState == SocketConnectionState.Connecting) {
//Connection attempt with abort button
            return Center(
              child: Column(
                children: <Widget>[
                  CircularProgressIndicator(),
                  Text('Connecting...'),
                  ElevatedButton(
                    child: Text('Abort'),
                    onPressed: () {
                      _tcpBloc!.add(Disconnect());
                    },
                  )
                ],
              ),
            );
          } else if (tcpState.connectionState == SocketConnectionState.Connected) {
// Connection OK --> Screen Play and Stop truck
            return Column(
              children: [
                Expanded(
                  child: Container(
                    padding: EdgeInsets.all(10),
                    margin: EdgeInsets.fromLTRB(20, 10, 20, 10),
                    //1 ligne
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
//Play button
                        Container(
                          child: Column(
                            children: [
                              Opacity(
                                opacity: isButtonClickable? 1.0:0.2,
                                //padding: EdgeInsets.all(5),
                                child: RaisedButton(
                                  padding: EdgeInsetsDirectional.all(10),
                                  onPressed: () {
                                    if (isButtonClickable){
                                      _tcpBloc!.add(SendMessage(message: '1'));
                                    }
                                  },
                                  color: Colors.green,
                                  child: Icon(
                                    Icons.play_arrow_sharp,
                                    color: Colors.white,
                                    size: 30,
                                  ),
                                ),
                              ),
                              SizedBox(height: 5),
                              Text('Play')
                            ],
                          ),
                        ),
//Stop Buttton
                        Container(
                          child: Column(
                            children: [
                              Opacity(
                                //padding: EdgeInsets.all(5),
                                opacity: isButtonClickable? 1.0:0.2,
                                child: RaisedButton(
                                  padding: EdgeInsetsDirectional.all(10),
                                  onPressed: () {
                                    if(isButtonClickable){
                                      _tcpBloc!.add(SendMessage(message: '0'));
                                    }
                                  },
                                  color: Colors.red,
                                  child: Icon(
                                    Icons.stop,
                                    color: Colors.white,
                                    size: 30,
                                  ),
                                ),
                              ),
                              SizedBox(height: 5),
                              Text('Stop')
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
//Read and display received and requested data
              Container (

                  child: Text("Historique de l'état du camion :",style: TextStyle(color: Colors.white, fontSize: 23)
                  ),
                  decoration: ShapeDecoration(
                    color: Colors.lightBlue,
                    shape: RoundedRectangleBorder (
                    borderRadius: BorderRadius.circular(15.0),
                    side: BorderSide(
                    width: 5,
                    color: Colors.lightBlue),
                  ),
                  ),
                  padding: EdgeInsets.all(3),
                margin: EdgeInsets.fromLTRB(10, 3, 10, 3),
              ),

                Container(
                  height: 460,
                  width : 600,
                  decoration: BoxDecoration(color: Colors.white38,border: Border.all(width: 5,
                    color: Colors.lightBlue,
                  ),),
                  child: ListView.builder(
                      itemCount: tcpState.messages.length,
                      itemBuilder: (context, idx) {
                        Message m = tcpState.messages[idx];
                        return Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Bubble(
                            child:
                            Text(m.message),
                            alignment: m.sender == Sender.Client ? Alignment.centerRight : Alignment.centerLeft,
                          ),
                        );
                      }
                  ),

                ),

//Disconnect Button
                ElevatedButton(
                  child: Text('Disconnect'),
                  onPressed: () {
                    _tcpBloc!.add(Disconnect());
                  },
                ),

              ],
            );
          } else {
            return Container();
          }
        },
      ),
    );
  }
}

 

Ответ №1:

Flutter позволяет проще справиться с вашей ситуацией: вместо того, чтобы проверять, работает ли ваша служба TCP «или» еще не запущена», вам нужно дождаться Future ответа от вашего TCP-сервера и выполнить соответствующую сборку. Или, если ваша серверная служба «переключается» более одного раза (вкл.<->выкл.), вам следует подписаться на< -> Stream , чтобы проверить изменение ее значения и выполнить соответствующую сборку.

Чтобы сделать это легко, я бы сказал, что вы должны окончательно проверить FutureBuilder виджеты и StreamBuilder виджеты, которые делают именно то, что вы просите.

Вот документация FutureBuilder.

Вот документация StreamBuilder.

В них также есть быстрое и приятное видео, чтобы вы могли быстрее понять, как его использовать (-: