MST

星途 面试题库

面试题:Flutter中Mixin增强StatefulWidget的复杂场景应用

假设你有一个StatefulWidget用于展示图片列表,要求通过Mixin为其添加图片缓存和预加载功能,详细描述实现思路,并给出主要的代码结构。
49.4万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 定义Mixin:创建一个Mixin类,该类负责处理图片缓存和预加载逻辑。
  2. 缓存机制:使用一个Map来存储已经加载过的图片,键为图片的URL,值为对应的Image对象。
  3. 预加载:在图片即将进入屏幕可视区域时,提前加载图片。可以通过监听滚动事件来判断图片是否接近可视区域。

主要代码结构

import 'package:flutter/material.dart';

// Mixin定义
mixin ImageCacheAndPreloadMixin<T extends StatefulWidget> on State<T> {
  final Map<String, Image> imageCache = {};

  Future<Image> getImage(String url) async {
    if (imageCache.containsKey(url)) {
      return imageCache[url]!;
    } else {
      final image = await precacheImage(NetworkImage(url), context);
      imageCache[url] = image;
      return image;
    }
  }

  void preloadImages(List<String> urls, int visibleIndex) {
    for (int i = visibleIndex - 2; i <= visibleIndex + 2; i++) {
      if (i >= 0 && i < urls.length) {
        getImage(urls[i]);
      }
    }
  }
}

class ImageListWidget extends StatefulWidget {
  final List<String> imageUrls;
  const ImageListWidget({Key? key, required this.imageUrls}) : super(key: key);

  @override
  _ImageListWidgetState createState() => _ImageListWidgetState();
}

class _ImageListWidgetState extends State<ImageListWidget> with ImageCacheAndPreloadMixin<ImageListWidget> {
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      final position = _scrollController.position;
      final viewportHeight = position.viewportDimension;
      final offset = position.pixels;
      final totalHeight = position.maxScrollExtent;
      final visibleIndex = (offset / viewportHeight).floor();
      preloadImages(widget.imageUrls, visibleIndex);
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      controller: _scrollController,
      itemCount: widget.imageUrls.length,
      itemBuilder: (context, index) {
        return FutureBuilder<Image>(
          future: getImage(widget.imageUrls[index]),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const CircularProgressIndicator();
            } else if (snapshot.hasError) {
              return Text('Error: ${snapshot.error}');
            } else {
              return Image(image: snapshot.data!);
            }
          },
        );
      },
    );
  }
}