Picture Image package of Flutter control

Base class Widget encapsulation of Flutter controls

Text encapsulation of Flutter control

Why cumbersome encapsulation? It’s good to use it directly. There is nothing wrong with this answer. Most views can be drawn natively, but the native controls in Flutter lack a lot of necessary and commonly used attributes, such as width and height, such as inner and outer margins, and for example Click event, if encapsulation is not adopted, the structure of the view will be nested layer by layer, which will increase a lot of redundant code. Therefore, in order to simplify the code and expand the properties that the native component does not have, it is necessary to perform a simple Encapsulation makes it easy to implement certain functions when calling.

Originally, I only planned to seal the base class of a Widget, but I thought that many basic components actually need to expand some attributes, so let’s just seal them one by one. It is both learning and accumulation. This article is simply for pictures. Image Make a package, this Image is also based on the first BaseWidget, if you are not familiar with it, you can read the first article.

Still in accordance with the usual practice, simply list the basic outline:

1. List of actual effects

2. Image related attribute analysis

3. Source code and specific use

4. Relevant summary

1. List of actual effects

The effect is very simple, just some usual functions, such as rounded corners, circles, setting placeholder images, etc.

2. Image related attribute analysis

Custom Image inherits some properties of the parent class, such as width and height, inner and outer margins, click events, etc. Of course, it also adds some unique properties of its own, such as rounded corners, circles, placeholders, etc. Specifically The parent class attributes will not be introduced too much, just read the first article, and briefly list the relevant attributes of Image.

Attributes

type

overview

placeholderImage

String

Placeholder image (only supports assets)

errorImage

String

Error graph (only supports assets)

imagePath

String

Image address (support network/assets/File)

imageBoxFit

BoxFit

Image stretching method

fill: Box is completely filled, equivalent to FIT_XY of ScaleType.

contain: Keep the aspect ratio of the Box until at least one side is filled with the parent control, which is equivalent to FIT_CENTER of ScaleType.

cover: Keep the aspect ratio of the Box and zoom until the Box completely fills the parent control, and the excess part is cropped, which is equivalent to CENTER_CROP of ScaleType.

fitWidth: Scales the Box width until it fills the parent control.

fitHeight: Scale the height of the Box until it fills the parent control.

none: Do not perform any scaling operation.

scaleDown: If the Box is larger than the parent control, the scaling mode consistent with contain will be adopted, otherwise none scaling mode will be adopted.

imageLoadType

int

Image loading type

isClipOval

bool

Is it round

imageRadius

double

Set image rounded corners

3. Source code and specific use

The source code is too simple. One is to inherit the original BaseWidget property, and the other is to expand its own related properties, such as placeholder map, error map, whether it is round, setting rounded corners, etc. The specific source code is as follows:

import 'dart:io';
import 'package:flutter/material.dart';

import '../../base/base_widget.dart';

///AUTHOR:AbnerMing
///DATE:2023/5/20
///INTRODUCE:图片控件

class VipImage extends BaseWidget {
  final String? placeholderImage; //占位图
  final String? errorImage; //错误图
  final String? imagePath; //图片地址
  final BoxFit? imageBoxFit; //图片拉伸方式
  final int? imageLoadType; //图片加载类型
  final bool? isClipOval; //是否是圆形
  final double? imageRadius; //设置图片圆角
  const VipImage(this.imagePath,
      {super.key,
      this.placeholderImage,
      this.errorImage,
      this.imageBoxFit,
      this.imageLoadType,
      this.isClipOval,
      this.imageRadius,
      super.width,
      super.height,
      super.margin,
      super.marginLeft,
      super.marginTop,
      super.marginRight,
      super.marginBottom,
      super.padding,
      super.paddingLeft,
      super.paddingTop,
      super.paddingRight,
      super.paddingBottom,
      super.backgroundColor,
      super.strokeWidth,
      super.strokeColor,
      super.solidColor,
      super.radius,
      super.isCircle,
      super.leftTopRadius,
      super.rightTopRadius,
      super.leftBottomRadius,
      super.rightBottomRadius,
      super.childWidget,
      super.alignment,
      super.gradient,
      super.gradientBegin,
      super.gradientEnd,
      super.gradientColorList,
      super.gradientColorStops,
      super.onClick,
      super.onDoubleClick,
      super.onLongPress});

  @override
  Widget getWidget(BuildContext context) {
    //不需要占位图
    if (placeholderImage == null) {
      return getEndWidget(getImage());
    } else {
      return getEndWidget(getFadeInImage());
    }
  }

  /*
  * 返回最终的Widget
  * */
  Widget getEndWidget(widget) {
    //设置图片为圆形
    if (isClipOval == true) {
      return ClipOval(child: widget);
    }
    //设置图片圆角
    if (imageRadius != null) {
      return ClipRRect(
          borderRadius: BorderRadius.circular(imageRadius!), child: widget);
    }
    return widget;
  }

  /*
  * 有无占位图组件
  * */
  Widget getFadeInImage() {
    return FadeInImage(
        fit: imageBoxFit ?? BoxFit.contain,
        placeholderFit: imageBoxFit ?? BoxFit.contain,
        placeholder: getPlaceholder(),
        image: getImageProvider(),
        placeholderErrorBuilder: (ctx, err, stackTrace) => _imagePlaceholder(),
        imageErrorBuilder: (ctx, err, stackTrace) => _imageError());
  }

  /*
  * 无占位图组件
  * */
  Widget getImage() {
    return Image(
        image: getImageProvider(),
        fit: imageBoxFit ?? BoxFit.contain,
        errorBuilder: (ctx, err, stackTrace) => _imageError());
  }

  /*
  * 占位图错误组件
  * */
  Widget _imagePlaceholder() {
    return Image.asset("", fit: imageBoxFit ?? BoxFit.contain);
  }

  /*
  * 错误组件
  * */
  Widget _imageError() {
    var imagePath = "";
    if (errorImage != null) {
      imagePath = errorImage!;
    }
    return Image.asset(imagePath, fit: imageBoxFit ?? BoxFit.contain);
  }

  /*
  * 判断图片是网络还是本地还是应用内
  * */
  ImageProvider getImageProvider() {
    if (imageLoadType == null) {
      return NetworkImage(imagePath!);
    } else if (imageLoadType == 0) {
      return FileImage(File(imagePath!));
    } else {
      return AssetImage(imagePath!);
    }
  }

  /*
  * 占位图
  * */
  ImageProvider getPlaceholder() {
    return AssetImage(placeholderImage!);
  }
}

easy to use

 VipImage("https://www.vipandroid.cn/ming/image/gan.png")

Specific cases (corresponding to the rendering of the first article)

In this case, the previously packaged VipText control is combined. You can just read the article directly. Of course, you can delete it. It is a Text control itself, which is used to describe information.

import 'package:flutter/material.dart';

import '../../constants/dimen_constant.dart';
import '../../constants/image_constant.dart';
import '../widget/vip_image.dart';
import '../widget/vip_text.dart';

///AUTHOR:AbnerMing
///DATE:2023/5/20
///INTRODUCE:Image组件效果页面

class ImagePage extends StatefulWidget {
  const ImagePage({super.key});

  @override
  State<ImagePage> createState() => _ImagePageState();
}

class _ImagePageState extends State<ImagePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      padding: const EdgeInsets.only(
          left: DimenConstant.dimen_10, right: DimenConstant.dimen_10),
      child: SingleChildScrollView(
          child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: const [
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
            ),
            VipText("(普通加载)", marginTop: DimenConstant.dimen_5),
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
              width: 80,
              height: 80,
            ),
            VipText("(设置宽高)", marginTop: DimenConstant.dimen_5),
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
              imageBoxFit: BoxFit.fill,
              width: 80,
              height: 80,
            ),
            VipText("(设置宽高拉伸充满)", marginTop: DimenConstant.dimen_5),
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
              imageBoxFit: BoxFit.cover,
              width: 80,
              height: 80,
            ),
            VipText("(设置宽高居中裁切)", marginTop: DimenConstant.dimen_5),
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
              imageBoxFit: BoxFit.cover,
              placeholderImage: ImageConstant.imageDefault,
              width: 80,
              height: 80,
            ),
            VipText("(设置占位图)", marginTop: DimenConstant.dimen_5),
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
              imageBoxFit: BoxFit.cover,
              isClipOval: true,
              width: 80,
              height: 80,
            ),
            VipText("(设置圆形)", marginTop: DimenConstant.dimen_5),
            VipImage(
              "https://www.vipandroid.cn/ming/image/gan.png",
              marginTop: DimenConstant.dimen_10,
              imageBoxFit: BoxFit.cover,
              imageRadius: DimenConstant.dimen_10,
              placeholderImage: ImageConstant.imageDefault,
              width: 80,
              height: 80,
            ),
            VipText("(设置圆角)", marginTop: DimenConstant.dimen_5),
          ])),
    );
  }
}

DimenConstant

The relevant size is extracted into a constant class, the purpose is easy to manage, and you don't want to use direct code to write the value.

///AUTHOR:AbnerMing
///DATE:2023/5/15
///INTRODUCE:尺寸常量

class DimenConstant {
  static const double dimen_5 = 5;
  static const double dimen_10 = 10;
  static const double dimen_15 = 15;
  static const double dimen_22 = 22;
  static const double dimen_44 = 44;
}

ImageConstant

The image constant class is used to store the image address under some assets, which is easy to manage.

///AUTHOR:AbnerMing
///DATE:2023/5/15
///INTRODUCE:图片地址常量

class ImageConstant {
  static const String imageDefault = "images/vip_ic_image_default.png";
}

4. Relevant summary

During project development, about some constant information, such as the size, local picture address, requested interface address, etc., we generally don’t write it directly in the page. First, it is inconvenient to manage. Second, once it is changed later, You need to find each file, which is a waste of time, so try to extract it to a place, similar to Android, such files as strings. Here I hope to help you all.

 

Guess you like

Origin blog.csdn.net/ming_147/article/details/130780841