MST

星途 面试题库

面试题:Flutter中Stack在响应式布局下的复杂UI实现

使用Stack实现一个复杂UI,该UI在不同屏幕尺寸下有不同的布局方式。例如,在大屏幕上,三个不同的Widget横向排列展示;在小屏幕上,这三个Widget纵向排列展示,且每个Widget都有自己独特的动画效果(如淡入淡出)。请阐述整体的实现方案,并给出核心代码逻辑。
13.1万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

整体实现方案

  1. 检测屏幕尺寸:通过设备相关的API获取屏幕的宽度或尺寸信息,以此来判断当前设备是大屏幕还是小屏幕。
  2. 布局管理
    • 大屏幕:使用水平布局(如Row在Flutter中)将三个Widget横向排列。
    • 小屏幕:使用垂直布局(如Column在Flutter中)将三个Widget纵向排列。
  3. 动画效果实现:利用动画库(如在Flutter中使用AnimatedOpacity实现淡入淡出效果),对每个Widget分别设置动画。
  4. Stack使用:Stack用于将不同的Widget叠加在一起,以便在不同布局下合理放置Widget,并确保动画的正确展示。可以在Stack中根据屏幕尺寸决定子Widget的排列方式和动画状态。

核心代码逻辑(以Flutter为例)

import 'package:flutter/material.dart';

class ComplexUI extends StatefulWidget {
  @override
  _ComplexUIState createState() => _ComplexUIState();
}

class _ComplexUIState extends State<ComplexUI> with SingleTickerProviderStateMixin {
  late AnimationController _controller1;
  late AnimationController _controller2;
  late AnimationController _controller3;
  late Animation<double> _opacityAnimation1;
  late Animation<double> _opacityAnimation2;
  late Animation<double> _opacityAnimation3;

  @override
  void initState() {
    super.initState();
    _controller1 = AnimationController(
      duration: const Duration(milliseconds: 1000),
      vsync: this,
    );
    _controller2 = AnimationController(
      duration: const Duration(milliseconds: 1500),
      vsync: this,
    );
    _controller3 = AnimationController(
      duration: const Duration(milliseconds: 2000),
      vsync: this,
    );
    _opacityAnimation1 = Tween<double>(begin: 0.0, end: 1.0).animate(_controller1);
    _opacityAnimation2 = Tween<double>(begin: 0.0, end: 1.0).animate(_controller2);
    _opacityAnimation3 = Tween<double>(begin: 0.0, end: 1.0).animate(_controller3);

    _controller1.forward();
    _controller2.forward();
    _controller3.forward();
  }

  @override
  void dispose() {
    _controller1.dispose();
    _controller2.dispose();
    _controller3.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bool isLargeScreen = MediaQuery.of(context).size.width > 600;

    return Stack(
      children: [
        if (isLargeScreen)
          Row(
            children: [
              AnimatedOpacity(
                opacity: _opacityAnimation1.value,
                duration: const Duration(milliseconds: 1000),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.red,
                ),
              ),
              AnimatedOpacity(
                opacity: _opacityAnimation2.value,
                duration: const Duration(milliseconds: 1500),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.green,
                ),
              ),
              AnimatedOpacity(
                opacity: _opacityAnimation3.value,
                duration: const Duration(milliseconds: 2000),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
              ),
            ],
          )
        else
          Column(
            children: [
              AnimatedOpacity(
                opacity: _opacityAnimation1.value,
                duration: const Duration(milliseconds: 1000),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.red,
                ),
              ),
              AnimatedOpacity(
                opacity: _opacityAnimation2.value,
                duration: const Duration(milliseconds: 1500),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.green,
                ),
              ),
              AnimatedOpacity(
                opacity: _opacityAnimation3.value,
                duration: const Duration(milliseconds: 2000),
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.blue,
                ),
              ),
            ],
          )
      ],
    );
  }
}

在上述代码中:

  1. 首先定义了三个AnimationController和对应的Animation对象来控制每个Widget的淡入淡出动画。
  2. initState中初始化并启动动画。
  3. build方法中,通过MediaQuery.of(context).size.width检测屏幕宽度来决定是使用横向布局还是纵向布局。
  4. 使用AnimatedOpacity包裹每个Widget来实现淡入淡出效果。Stack用于容纳不同布局方式下的Widget。