当前位置: 首页 > news >正文

面试复习题-Flutter场景题

🌟 场景题 1:实现一个“下拉刷新 + 上拉加载更多”的商品列表

需求

  • 商品列表支持下拉刷新。
  • 滑动到底部自动加载更多。
  • 加载中显示“加载中...”Footer。
  • 加载失败显示“点击重试”按钮。
  • 网络请求失败有重试机制。
✅ 高级回答要点:

dart

深色版本

class ProductList extends StatefulWidget {@override_ProductListState createState() => _ProductListState();
}class _ProductListState extends State<ProductList> {final ProductBloc _bloc = ProductBloc();final ScrollController _scrollController = ScrollController();@overridevoid initState() {_bloc.fetchProducts();_scrollController.addListener(_onScroll);super.initState();}void _onScroll() {if (_scrollController.position.pixels >=_scrollController.position.maxScrollExtent - 200) {_bloc.loadMore();}}@overrideWidget build(BuildContext context) {return RefreshIndicator(onRefresh: () => _bloc.refresh(),child: BlocBuilder<ProductBloc, ProductState>(bloc: _bloc,builder: (context, state) {if (state is ProductLoading && state.products.isEmpty) {return const Center(child: CircularProgressIndicator());}return ListView.builder(controller: _scrollController,itemCount: state.products.length + (state.hasMore ? 1 : 0),itemBuilder: (context, index) {if (index == state.products.length) {if (state.loadFailed) {return ElevatedButton(onPressed: _bloc.retryLoadMore,child: const Text('点击重试'),);}return const Padding(padding: EdgeInsets.all(16),child: Center(child: CircularProgressIndicator()),);}return ProductItem(product: state.products[index]);},);},),);}@overridevoid dispose() {_bloc.dispose();_scrollController.dispose();super.dispose();}
}
💡 考察点:
  1. 状态管理:使用 Bloc 或 Riverpod 管理复杂状态(加载中、失败、是否有更多)。
  2. 性能ListView.builder 懒加载。
  3. 用户体验:Footer 显示加载/失败状态。
  4. 内存管理ScrollController 和 Bloc 正确释放。
  5. 可维护性:逻辑与 UI 分离。

🌟 场景题 2:实现一个“登录页”,支持手机号、密码、验证码登录,且表单验证

需求

  • 手机号输入框(带格式化:138 **** ****)。
  • 密码或验证码输入。
  • “获取验证码”按钮(60秒倒计时)。
  • 表单验证(手机号格式、密码长度、验证码6位)。
  • 提交按钮禁用状态控制。
✅ 高级回答要点:

dart

深色版本

class LoginForm extends StatefulWidget {@override_LoginFormState createState() => _LoginFormState();
}class _LoginFormState extends State<LoginForm> {final _formKey = GlobalKey<FormState>();final _phoneController = TextEditingController();final _codeController = TextEditingController();bool _isCodeLogin = true;bool _isSubmitting = false;int _countdown = 0;@overridevoid initState() {super.initState();_phoneController.addListener(_formatPhone);}void _formatPhone() {// 实现手机号格式化:138****1234}void _startCountdown() {setState(() => _countdown = 60);Timer.periodic(const Duration(seconds: 1), (timer) {if (_countdown <= 1) {timer.cancel();setState(() => _countdown = 0);} else {setState(() => _countdown--);}});}void _submit() async {if (_formKey.currentState?.validate() ?? false) {setState(() => _isSubmitting = true);try {await login(_phoneController.text, _codeController.text);Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => Home()));} catch (e) {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('登录失败: $e')));} finally {setState(() => _isSubmitting = false);}}}@overrideWidget build(BuildContext context) {return Form(key: _formKey,child: Column(children: [TextFormField(controller: _phoneController,decoration: const InputDecoration(labelText: '手机号'),validator: (value) => isValidPhone(value) ? null : '请输入正确的手机号',),if (_isCodeLogin) ...[TextFormField(controller: _codeController,decoration: InputDecoration(labelText: '验证码',suffixIcon: _countdown > 0? Text('$_countdowns'): TextButton(onPressed: _countdown == 0 ? _startCountdown : null,child: const Text('获取验证码'),),),validator: (value) => value?.length == 6 ? null : '验证码为6位',),] else ...[// 密码输入框],ElevatedButton(onPressed: (_formKey.currentState?.isValid ?? false) && !_isSubmitting ? _submit : null,child: _isSubmitting ? const CircularProgressIndicator() : const Text('登录'),),],),);}
}
💡 考察点:
  1. 表单管理GlobalKey<FormState> + TextFormField
  2. 输入控制TextEditingController 监听和格式化。
  3. 状态反馈:倒计时、提交中 loading 状态。
  4. 用户体验:按钮禁用、错误提示。
  5. 可扩展性:支持密码/验证码切换。

🌟 场景题 3:实现一个“聊天界面”,支持文本、图片、语音消息

需求

  • 消息列表(左:别人,右:自己)。
  • 支持文本、图片、语音消息。
  • 图片可点击放大。
  • 语音消息可播放/暂停。
  • 输入框支持文字输入和发送。
✅ 高级回答要点:

dart

深色版本

// 1. 定义消息类型
sealed class ChatMessage {final String sender;final DateTime timestamp;
}class TextMessage extends ChatMessage {final String text;TextMessage({required this.text, required super.sender, required super.timestamp});
}class ImageMessage extends ChatMessage {final String imageUrl;ImageMessage({required this.imageUrl, required super.sender, required super.timestamp});
}class VoiceMessage extends ChatMessage {final String audioUrl;final int duration;VoiceMessage({required this.audioUrl, required this.duration, required super.sender, required super.timestamp});
}// 2. 消息项 Widget
Widget buildMessage(ChatMessage message) {final isMe = message.sender == 'me';return Row(mainAxisAlignment: isMe ? MainAxisAlignment.end : MainAxisAlignment.start,children: [Container(padding: const EdgeInsets.all(8),margin: const EdgeInsets.symmetric(vertical: 4),decoration: BoxDecoration(color: isMe ? Colors.blue : Colors.grey[300],borderRadius: BorderRadius.circular(8),),child: _buildMessageContent(message),),],);
}Widget _buildMessageContent(ChatMessage message) {if (message is TextMessage) {return Text(message.text, style: TextStyle(color: message.sender == 'me' ? Colors.white : Colors.black));} else if (message is ImageMessage) {return GestureDetector(onTap: () => showImageDialog(message.imageUrl),child: Image.network(message.imageUrl, width: 150),);} else if (message is VoiceMessage) {return VoicePlayer(audioUrl: message.audioUrl, duration: message.duration);}return const SizedBox();
}
💡 考察点:
  1. 数据建模:使用 sealed class(Dart 3.0)或 enum + factory 区分消息类型。
  2. UI 复用_buildMessageContent 分类型渲染。
  3. 交互:图片点击放大(showDialog + PhotoView)。
  4. 第三方库audioplayers 播放语音。
  5. 性能:图片懒加载、缓存。

🌟 场景题 4:实现一个“商品详情页”,包含轮播图、标题、价格、规格选择、购买按钮

需求

  • 顶部轮播图(支持自动播放、指示器)。
  • 商品标题、价格、销量。
  • 规格选择(颜色、尺寸),选择后更新价格。
  • “加入购物车”和“立即购买”按钮。
  • 页面滑动时,标题栏颜色渐变。
✅ 高级回答要点:

dart

深色版本

class ProductDetailPage extends StatefulWidget {@override_ProductDetailPageState createState() => _ProductDetailPageState();
}class _ProductDetailPageState extends State<ProductDetailPage> {final ScrollController _scrollController = ScrollController();double _appBarOpacity = 0;@overridevoid initState() {_scrollController.addListener(() {final offset = _scrollController.offset;setState(() {_appBarOpacity = offset.clamp(0.0, 1.0);});});super.initState();}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [CustomScrollView(controller: _scrollController,slivers: [SliverAppBar(pinned: true,backgroundColor: Colors.white.withOpacity(_appBarOpacity),title: Text('商品详情', style: TextStyle(color: _appBarOpacity > 0.5 ? Colors.black : Colors.white)),),SliverToBoxAdapter(child: Column(children: [CarouselSlider(...), // 轮播图ProductInfo(),     // 标题、价格SpecSelector(),    // 规格选择BuyButtons(),      // 购买按钮],),),],),],),);}
}
💡 考察点:
  1. 复杂布局CustomScrollView + SliverAppBar 实现渐变标题。
  2. 状态联动:规格选择 → 价格更新(Provider 或 Bloc)。
  3. 第三方库carousel_slider 实现轮播。
  4. 用户体验:平滑滚动、视觉反馈。

🌟 场景题 5:实现一个“后台定位服务”(Android/iOS)

需求

  • 应用在后台时持续获取用户位置。
  • 位置变化超过 100 米上报一次。
  • 低功耗模式(不影响电池)。
  • 前台服务显示通知(Android)。
✅ 高级回答要点:
  1. 插件选择geolocator + workmanager(定时任务)或 flutter_background_service
  2. 权限
    • Android: ACCESS_FINE_LOCATIONACCESS_BACKGROUND_LOCATION
    • iOS: NSLocationAlwaysAndWhenInUseUsageDescription
  3. 实现
    dart

    深色版本

    final service = FlutterBackgroundService();
    service.startForeground(onStart: (service) {service.on('location').listen((data) {Geolocator.getPositionStream(distanceFilter: 100, // 100米变化desiredAccuracy: LocationAccuracy.low,).listen((position) {// 上报位置sendToServer(position);});});},
    );
  4. 保活:Android 前台服务 + 通知,iOS BGTaskScheduler
💡 考察点:
  1. 平台特性:了解 Android/iOS 后台限制。
  2. 插件能力:选择合适的插件。
  3. 功耗优化:低精度、距离过滤。
  4. 合规性:隐私权限、用户提示。

总结:如何应对 Flutter 场景题?

步骤说明
1. 理解需求问清楚边界条件、异常情况
2. 设计数据模型定义 classenumstate
3. 选择状态管理ProviderBlocRiverpod
4. 构建 UI 结构Widget 拆分、复用
5. 处理交互手势、动画、表单
6. 考虑性能constListView.builderIsolate
7. 异常与加载loadingerrorretry
8. 内存与生命周期dispose()controller 释放

记住:面试官想看到的是你的思考过程,边说边写,展示架构思维和工程素养。

http://www.dtcms.com/a/365254.html

相关文章:

  • C# 开发 ACS 运动控制系统:从入门到高阶应用实践
  • LSE录取率上升,中国申请者却减少!除了成绩,这点成关键胜负手
  • 跟做springboot尚品甄选项目
  • 逻辑回归:从原理到实战的完整指南
  • Spring AOP注解案例
  • AI 重塑就业市场:哪些职业会被替代?又有哪些新岗位正在崛起?
  • 基于https+域名的Frp内网穿透教程(Linux+Nginx反向代理)
  • python数据分析 与spark、hive数据分析对比
  • Gemini CLI源码解析:Agent与上下文管理实现细节
  • 2025年COR IOTJ SCI2区,灾后通信无人机基站位置优化和移动充电无人机路径规划,深度解析+性能实测
  • Aerobits-用于 sUAS 和 UTM/U-Space 的微型 ADS-B 技术(收发器/接收器)和无人机跟踪应答器
  • Grok-4 :AI 基准测试霸主,速度与智能并存——但代价几何?
  • 简述 Java 的异常体系结构。Error 和 Exception 有什么区别?
  • 精通人机协同:使用 LangGraph 构建交互式智能体的综合指南
  • 服务器固件全景地图:从BIOS到BMC,升级背后的安全与性能革命
  • [光学原理与应用-376]:ZEMAX - 优化 - 概述
  • 中通笔试ShowMeBug编程题复盘
  • Ansible 核心功能:循环、过滤器、判断与错误处理全解析
  • 《苍穹外卖》开发环境搭建_后端环境搭建【简单易懂注释版】
  • PL-YOLOv8:基于YOLOv8的无人机实时电力线检测与植被风险预警框架,实现精准巡检与预警
  • 【Spring Cloud微服务】11.微服务通信演义:从飞鸽传书到5G全息,一部消息中间件的进化史诗
  • Git 别名:用简短命令大幅提升开发效率
  • 无人机报警器8G信号技术解析
  • leetcode110. 平衡二叉树
  • 深入解析Java Spliterator(Stream延迟、并行计算核心)
  • 哪些AI生成PPT的软件或网站支持多平台使用?都支持哪些平台?
  • AI生成PPT工具排名:2025年高效办公新选择
  • 关于MySQL数据库连接超时问题及解决办法
  • AR智慧运维系统介绍
  • vue项目打包后dist部署到Nginx