关于flutter:flutter-踩坑

48次阅读

共计 3958 个字符,预计需要花费 10 分钟才能阅读完成。

1. 应用 flutter_svg 引入 svg 报错

该 svg 是从 figma 导出的。

翻阅 Out of order defs/references #102 将 defs 放到 svg 标签的顶部,能够解决这个报错,且修改了该 svg 外部小图标的色彩问题,从而让页面上的 svg 跟 figma 上看起来统一。

2. 应用 GridView 滚动的时候报错

*The following assertion was thrown while notifying status listeners for AnimationController:
The provided ScrollController is currently attached to more than one ScrollPosition.*

class GridList extends StatelessWidget {
  const GridList({Key? key,}) : super(key: key);

  @override
  Widget build(BuildContext context) {\
    return GridView.count(
      crossAxisCount: 3,
      crossAxisSpacing: 32,
      mainAxisSpacing: 32,
      scrollDirection: Axis.vertical,
      childAspectRatio: (1 / .75),
      shrinkWrap: true,
      children: const [GridCard(),
        GridCard(),
        GridCard(),
        GridCard(),
        GridCard(),
        GridCard(),],
    );
  }
}

参考 Flutter 谬误 The provided ScrollController is attached to more than one ScrollPosition 须要给 GridView 增加个 controller。

3. OutlinedButton 默认是 disabled 状态

OutlinedButton 默认是 disabled 状态,须要传递 onPressed 或者 onLongPress 才是可用状态,ButtonStyleButton 做了解释

  /// Whether the button is enabled or disabled.
  ///
  /// Buttons are disabled by default. To enable a button, set its [onPressed]
  /// or [onLongPress] properties to a non-null value.
  bool get enabled => onPressed != null || onLongPress != null;

4. hydrated_bloc 长久化数据如何从新同步到客户端

需要:
不同的用户登录同一个客户端须要保留之前的操作记录(比方之前通过 trtc 设置的麦克风音量)。
间接上代码

class SettingBloc extends HydratedBloc<SettingEvent, SettingState> {
  final String uid;

  SettingBloc({required this.uid}) : super(SettingInitial()) {on<SettingVolumeUpdate>(_onVolumeUpdate);
    on<SettingInitialize>(_onSettingInitialize);
    add(const SettingInitialize()); // 初始化数据
  }

  final TRTC trtc = TRTC();

  void _onSettingInitialize(
    SettingInitialize event,
    Emitter<SettingState> emit,
  ) async {
    // 在这里能够拿到原始的 state 或从 fromJson 中返回的 state
    add(SettingVolumeUpdate(state.headsetVolume, false));

    add(SettingVolumeUpdate(state.microphoneVolume, true));
  }

  void _onVolumeUpdate(
    SettingVolumeUpdate event,
    Emitter<SettingState> emit,
  ) async {if (event.isMicrophone) {await trtc.setCurrentMicDeviceVolume(event.volume.toInt()); // 设置麦克风音量
    } else {await trtc.setCurrentSpeakerDeviceVolume(event.volume.toInt());
    }
    emit(event.isMicrophone
        ? state.copyWith(microphoneVolume: event.volume)
        : state.copyWith(headsetVolume: event.volume));
  }

  @override
  String get id => uid; // 缓存不同用户的数据

  @override
  SettingState? fromJson(Map<String, dynamic> json) { // 从缓存中读取数据
    final headsetVolume = json['headsetVolume'];
    final microphoneVolume = json['microphoneVolume'];
    // 在这里不能间接通过 add(SettingVolumeUpdate(state.microphoneVolume, true))触发事件,// 因为 fromJson 在 SettingBloc 构造函数之前执行,事件还没注册,// 然而上面返回的后果会在_onSettingInitialize 中拿到
    // 从而在_onSettingInitialize 中触发 SettingVolumeUpdate 
    return SettingState(
      headsetVolume: headsetVolume ?? 100,
      microphoneVolume: microphoneVolume ?? 100,
    );
  }

  @override
  Map<String, dynamic>? toJson(SettingState state) { // 将 bloc 的数据缓存起来
    return {
      "microphoneVolume": state.microphoneVolume,
      "headsetVolume": state.headsetVolume,
    };
  }
}

5. 空容器怎么触发 onSecondaryTapDown 事件

class Separator extends StatelessWidget {Separator({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.translucent,  // 须要加这行能力触发 onSecondaryTapDown 事件
      onSecondaryTapDown: (TapDownDetails details) { },
      child: const SizedBox( // child 为空无奈触发 onSecondaryTapDown 事件
        height: 28,
      ),
    );
  }
}

6. [email protected] customButton 点击 menu 没法弹出

customButton 是我自定义的一个 svg icon 用了 GestureDetector 注册了 onTap 事件

GestureDetector(onTapDown: (details) {setState(() {isPressed = true;});
                widget.onTapDown?.call(details);
              },
              onTapUp: (details) {setState(() {isPressed = false;});
              },
              onTapCancel: () {setState(() {isPressed = false;});
              },
              onTap: () {widget.onTap?.call();
              },
              behavior: widget.behavior,
              child: SizedBox.square(
                dimension: widget.size,
                child: SvgPicture.asset(svgStatusSrc,),
              ),
            ),

customButton 的正文:

  /// Uses custom widget like icon,image,etc.. instead of the default button
  final Widget? customButton;

我间接用 SvgPicture.asset 作为 customButton 是没问题的, 所以狐疑是我的图标控件注册了 onTap 事件的问题,果然去掉了 GestureDetector 就没问题了。然而这个是通用控件,不能把 GestureDetector 去掉,有什么好方法去触发 dropdownbutton 的 onTap 事件呢?
Does this widget allow you to open the button programmatically? 给出了答案

 final dropdownKey = GlobalKey<DropdownButton2State>();

 GestureDetector(onTap: () {dropdownKey.currentState!.callTap();
              },
              child: Container(
                height: 100,
                width: 100,
                color: Colors.red,
              )

DropdownButton2(key: dropdownKey,)

正文完
 0