flutter 如何只触发一个指定的块生成器?

kmynzznz  于 2023-08-07  发布在  Flutter
关注(0)|答案(1)|浏览(136)

我正在创建一个聊天应用程序,在发送消息功能中,我使用bloc处理消息可能处于的不同状态(不同状态是:sent,delivered and seen),但问题是因为我使用BlocBuilder来处理ui,所以它正在为所有发送的消息重建UI。让我给你看一个例子来了解更多,首先这里是我的小部件:

class MessageItemWidget extends StatelessWidget {
  final Message message;
  final Alignment alignment;
  final BorderRadius borderRadius;
  final TextStyle chatStyle;
  final Color color;
  const MessageItemWidget({
    Key? key,
    required this.message,
    required this.alignment,
    required this.borderRadius,
    required this.chatStyle,
    required this.color,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<MessagesCubit, MessagesState>(
      builder: (context, state) {
        if (state is MessageSending) {
          return Align(
            alignment: alignment,
            child: UnconstrainedBox(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.end,
                children: [
                  Container(
                    margin: const EdgeInsets.all(8),
                    padding: const EdgeInsets.symmetric(
                      horizontal: 20,
                      vertical: 10,
                    ),
                    constraints: BoxConstraints(
                      maxWidth: MediaQuery.of(context).size.width * 0.55,
                    ),
                    decoration: BoxDecoration(
                      borderRadius: borderRadius,
                      color: color,
                    ),
                    child: Text(
                      message.content,
                      style: chatStyle,
                    ),
                  ),
                  const Icon(
                    Icons.check,
                    color: Colors.grey,
                    size: 15,
                  ),
                ],
              ),
            ),
          );
        } else if (state is MessageSent) {
          return Align(
            alignment: alignment,
            child: UnconstrainedBox(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.end,
                children: [
                  Container(
                    margin: const EdgeInsets.all(8),
                    padding: const EdgeInsets.symmetric(
                      horizontal: 20,
                      vertical: 10,
                    ),
                    constraints: BoxConstraints(
                      maxWidth: MediaQuery.of(context).size.width * 0.55,
                    ),
                    decoration: BoxDecoration(
                      borderRadius: borderRadius,
                      color: color,
                    ),
                    child: Text(
                      message.content,
                      style: chatStyle,
                    ),
                  ),
                  const Row(
                    children: [
                      Icon(
                        Icons.check,
                        color: Colors.blue,
                        size: 15,
                      ),
                      Icon(
                        Icons.check,
                        color: Colors.blue,
                        size: 15,
                      ),
                    ],
                  )
                ],
              ),
            ),
          );
        } else {
          return const SizedBox();
        }
      },
    );
  }
}

字符串
简而言之,它的作用是:如果消息被发送,则它在消息下显示一个检查图标,并且当消息已经被传送时,它在消息下显示两个检查图标。但是,每当发送消息时,它都会重新构建所有先前已发送消息的UI,这里是一个示例:


的数据
在上图中,所有消息都已成功传递。但每当我发送新消息时,就会发生这种情况:



已经发送的消息显示它们正在发送,但实际上它们之前已经发送过了,我怎么能只为特定的消息触发一个指定的块呢?
这是我的腕尺:

class MessagesCubit extends Cubit<MessagesState> {
  ChatRepository chatRepository;
  MessagesCubit(this.chatRepository) : super(MessagesInitial());

  Future<void> getMessages(
    BuildContext context, {
    required UserChat client,
    required UserChat supplier,
  }) async {
    emit(MessagesLoading());

    final failureOrStreamOfMessages =
        await chatRepository.getMessages(client: client, supplier: supplier);

    failureOrStreamOfMessages.fold(
      (failure) => emit(MessageError(mapFailureToMessage(failure, context))),
      (streamOfMessages) => streamOfMessages.listen(
        (messages) => emit(MessagesLoaded(messages)),
      ),
    );
  }

  Future<void> sendMessage(BuildContext context, Message message) async {
    emit(MessageSending());

    final failureOrUnit = await chatRepository.sendMessage(message);

    failureOrUnit.fold(
      (failure) => emit(MessageError(mapFailureToMessage(failure, context))),
      (_) => emit(MessageSent()),
    );
  }
}


以下是我的状态:

abstract class MessagesState extends Equatable {
  const MessagesState();

  @override
  List<Object> get props => [];
}

class MessagesInitial extends MessagesState {}

// reading messages

abstract class ReadingMessagesState extends MessagesState {
  const ReadingMessagesState();
}

class MessagesLoading extends ReadingMessagesState {}

class MessagesLoaded extends ReadingMessagesState {
  final List<Message> messages;

  const MessagesLoaded(this.messages);

  @override
  List<Object> get props => [messages];
}

class MessagesError extends ReadingMessagesState {
  final String message;

  const MessagesError(this.message);

  @override
  List<Object> get props => [message];
}

// writing messages

abstract class WritingMessagesState extends MessagesState {
  const WritingMessagesState();
}

class MessageSending extends WritingMessagesState {}

class MessageSent extends WritingMessagesState {}

class MessageError extends WritingMessagesState {
  final String message;

  const MessageError(this.message);

  @override
  List<Object> get props => [message];
}

j8ag8udp

j8ag8udp1#

我不确定您的Message模型是什么样子的,但让我们假设它有一个唯一的Id字段。如果没有,您可以添加一个。您可以将其传递到您发出的任何WritingMessagesState状态中。然后使用BlocBuilderbuildWhen功能,仅当来自小部件的消息ID与state的消息ID匹配时才过滤重建。
例如。

abstract class WritingMessagesState extends MessagesState {
  WritingMessagesState({required this.id});

  final String id; // add this
}

class MessageSending extends WritingMessagesState {
  MessageSending({required super.id});
}

class MessageSent extends WritingMessagesState {
  MessageSent({required super.id});
}

class MessageError extends WritingMessagesState {
  MessageError({required super.id, required this.message});
  final String message;

  @override
  List<Object> get props => [message];
}

字符串
那么emit的示例如下所示

emit(MessageSending(id: message.id));


然后将buildWhen添加到BlocBuilder

return BlocBuilder<MessagesCubit, MessagesState>(
     buildWhen: (previous, current) => current.id == message.id, // this will prevent all the other widgets from building
      builder: (context, state) {
    ...

相关问题