欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flutter入门疑难杂症:获取网络图片,并自适应屏幕宽度(适合文章/帖子详情)

程序员文章站 2022-03-11 18:09:04
...

经常会遇到帖子详情/文章详情,需要动态显示网络图片,并且要求图片宽度自适应屏幕,高度进行等比例缩放,如下图:
Flutter入门疑难杂症:获取网络图片,并自适应屏幕宽度(适合文章/帖子详情)
实现思路:
1、下载图片;
2、计算宽高比;
3、显示;

话不多说,直接贴代码,跑不通的可以留言。

  //放在Column内,构建多张图片
  List<Widget> _buildImgList(List<String>imgUrlList) {
    List<Widget> returnList = List();
    for (int i = 0; i < imgUrlList.length; i++) {
      returnList.add(InkWell(
        child: Column(children: [
          ItemFitWidthNetImage(imgUrlList[i])
        ]),
        onTap: () {
          //这里是点击查看大图的,可以替换成各自自己的
          MediaUtils.showBigImg(context,imgUrlList, i);
        },
      ));
    }
    return returnList;
  }
///宽度自适应的图片
// ignore: non_constant_identifier_names
Widget ItemFitWidthNetImage(String url, double fitWidth) {
  return AsperctRaioImage.network(url, builder: (context, snapshot, url) {
    //计算缩放
    double scale = snapshot.data.width.toDouble() / fitWidth;
    double fitHeight = snapshot.data.height.toDouble() / scale;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Container(
          width: fitWidth,
          height: fitHeight,
          decoration: BoxDecoration(
            image: DecorationImage(image: NetworkImage(url), fit: BoxFit.cover),
          ),
        )
      ],
    );
  });
}

AsperctRaioImage :

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;

typedef AsyncImageWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> snapshot, String url);

typedef AsyncImageFileWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> snapshot, File file);

typedef AsyncImageMemoryWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> snapshot, Uint8List bytes);

enum AsperctRaioImageType { NETWORK, FILE, ASSET, MEMORY }

///有宽高的Image
class AsperctRaioImage extends StatelessWidget {
  String url;
  File file;
  Uint8List bytes;
  final ImageProvider provider;
  AsperctRaioImageType type;
  AsyncImageWidgetBuilder<ui.Image> builder;
  AsyncImageFileWidgetBuilder<ui.Image> filebBuilder;
  AsyncImageMemoryWidgetBuilder<ui.Image> memoryBuilder;

  AsperctRaioImage.network(url, {Key key, @required this.builder})
      : provider = NetworkImage(url),
        type = AsperctRaioImageType.NETWORK,
        this.url = url;

  AsperctRaioImage.file(
      file, {
        Key key,
        @required this.filebBuilder,
      })  : provider = FileImage(file),
        type = AsperctRaioImageType.FILE,
        this.file = file;

  AsperctRaioImage.asset(name, {Key key, @required this.builder})
      : provider = AssetImage(name),
        type = AsperctRaioImageType.ASSET,
        this.url = name;

  AsperctRaioImage.memory(bytes, {Key key, @required this.memoryBuilder})
      : provider = MemoryImage(bytes),
        type = AsperctRaioImageType.MEMORY,
        this.bytes = bytes;

  @override
  Widget build(BuildContext context) {
    final ImageConfiguration config = createLocalImageConfiguration(context);
    final Completer<ui.Image> completer = Completer<ui.Image>();
    final ImageStream stream = provider.resolve(config);
    ImageStreamListener listener;
    listener = ImageStreamListener(
          (ImageInfo image, bool sync) {
        completer.complete(image.image);
        stream.removeListener(listener);
      },
      onError: (dynamic exception, StackTrace stackTrace) {
        completer.complete();
        stream.removeListener(listener);
        FlutterError.reportError(FlutterErrorDetails(
          context: ErrorDescription('image failed to precache'),
          library: 'image resource service',
          exception: exception,
          stack: stackTrace,
          silent: true,
        ));
      },
    );
    stream.addListener(listener);

    return FutureBuilder(
        future: completer.future,
        builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
          if (snapshot.hasData) {
            if (type == AsperctRaioImageType.FILE) {
              return filebBuilder(context, snapshot, file);
            } else if (type == AsperctRaioImageType.MEMORY) {
              return memoryBuilder(context, snapshot, bytes);
            } else {
              return builder(context, snapshot, url);
            }
          } else {
            return Container();
          }
        });
  }
}

参考:https://www.jianshu.com/p/ee62849752e8

相关标签: Flutter入门