难以在Flutter中实现上下文相关的图标按钮

时间:2019-08-04 07:13:42

标签: flutter

我像这样在一行中有一个TextField和一个IconButton。

enter image description here

我希望仅在TextField中有文本时才启用IconButton。我正在使用provider package进行状态管理。

这是ChangeNotifier实现。

class ChatMessagesProvider with ChangeNotifier{

List<ChatMessage> chatMessages = <ChatMessage>[];
bool messageTyped = false;

ChatMessagesProvider(this.chatMessages);

void newMessage(String textMessage){

ChatMessage message = ChatMessage(textMessage);

this.chatMessages.add(message);
notifyListeners();
}

int messageCount() => chatMessages.length;

void updateMessageTyped(bool typed){
this.messageTyped = typed;
//    notifyListeners(); Un-comennting this makes the Text disappear everytime I type something on the text field
}

}

这是实际的小部件:

class TextCompose extends StatelessWidget {

final TextEditingController _composeTextEditingController = new            TextEditingController();

TextCompose(this.chatMessagesProvider);

final ChatMessagesProvider chatMessagesProvider;

@override
Widget build(BuildContext context) {

return Container(
margin: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
  Flexible(
    child: new TextField(
      controller: _composeTextEditingController,
      onSubmitted: (String text) {
        _onMessageSubmitted(text, context);
      },
      onChanged: (String text){
        if(text.length > 0){
          chatMessagesProvider.updateMessageTyped(true);
          print(text);
        }
        else{
          chatMessagesProvider.updateMessageTyped(false);
          print("No text typed");
        }
      },
      decoration: new InputDecoration.collapsed(
          hintText: "Enter message"
      ),
    ),
  ),
  new Container(
    margin: new EdgeInsets.all(8.0),
    child: new IconButton(
      color: Theme.of(context).accentColor,
        icon: new Icon(Icons.send),
      disabledColor: Colors.grey,
      onPressed:chatMessagesProvider.messageTyped // This dosen't work
       ? () => _onMessageSubmitted(_composeTextEditingController.text, context)
       : null,
    ),
  )
],
),
);
}

void _onMessageSubmitted(String text, BuildContext context){
if(chatMessagesProvider.messageTyped) { // This works fine. 
// clear the message compose text box
_composeTextEditingController.clear();

// add the message to provider.
chatMessagesProvider.newMessage(text);

// set the message typed to false
chatMessagesProvider.messageTyped = false;
}

我正在使用来自ChatMessageProvider的messageTyped来检查TextField中是否有任何文本。当我在_onMessageSubmitted方法中检查它时,它似乎工作正常,但是当我在IconButton的onPressed属性中检查它的值时,它似乎工作正常。

我知道这是因为我在键入文本时可以看到IconButton保持禁用状态(颜色不会从灰色更改),而我可以按下虚拟键盘上的Submit按钮,并且可以从TextField中清除文本(按调用_composeTextEditingController.clear())

问题:

  • 当从_onMessageSubmitted调用时,为什么chatMessagesProvider.messageTyped返回正确的值,但是从IconButton的onPrssed属性调用时,为什么不能返回正确的值?

  • 我该如何在Flutter中调试类似的东西,我真的很想在onPressedAttribute中放置一个断点并查看chatMessagesProvider.messageTyped的值

让我知道您是否需要查看更多我的代码。

3 个答案:

答案 0 :(得分:1)

onPressed:chatMessagesProvider.messageTyped这行是在窗口小部件构建期间执行的,因此它始终是默认值,除非您使用notify listener或有状态窗口小部件重建窗口小部件,否则它永远不会刷新。

currently being typed message存储在provider中,并根据currently being typed message是否为空来使发送按钮启用/禁用。

答案 1 :(得分:1)

您说您正在使用'provider_package',但实际上您的布局中没有Provider。相反,您有一个没有侦听器的自定义构建ChangeNotifier-您确实在调用notifyListeners(),但实际上没有侦听器,因此不会触发任何重建。为了使按钮更改其onPressed函数引用并隐式更改其颜色,需要进行重建。

对于调试,您可以onPressed行上设置一个断点,但是只有在重建过程中它才会被击中。

要理解的最重要的事情是,您对onPressed的函数引用将被正确调用,但是需要重新构建才能使小部件在视觉上发生变化。

尽管您当前的ChangeNotifier实现没有多大意义,但只需将对updateMessageTyped的调用包装在setState内就可以解决视觉问题-每次键入后,您的断点也会被击中/已删除的字符。

答案 2 :(得分:0)

最简单的解决方案是,首先可以使窗口小部件StatefulWidget

您需要在State类中使用布尔值:

bool hasText = false;

然后创建initState

  @override
  void initState() {
    _composeTextEditingController.addListener(() {
      if (_composeTextEditingController.text.isNotEmpty) {
        setState(() {
          hasText = true;
        });
      } else {
        setState(() {
          hasText = false;
        });
      }
    });
    super.initState();
  }

也不要忘记dispose

  @override
  void dispose() {
    _composeTextEditingController.dispose();
    super.dispose();
  }

最后是您的build方法:

Row(
  children: <Widget>[
    Expanded(
        child: TextField(
      controller: _composeTextEditingController,
    )),
    if (hasText) IconButton(icon: Icon(Icons.send), onPressed: () {})
  ],
),