什么要進行繁瑣的封裝?直接用也挺好啊,這個回答一點毛病沒有,大部分視圖都可以原生繪制,可在Flutter中偏偏原生的控件,少了很多需要又常用的屬性,比如寬高,比如內外邊距,又比如點擊事件,如果不采取封裝,視圖的結構會一層嵌套一層,徒增很多的冗余代碼,所以,為了簡潔代碼,還有為了拓展原生組件沒有的屬性,就不得不進行一次簡單的封裝,使其在調用的時候,可以很方便的實現某些功能。
本來只打算封一個Widget的基類就算了,但是想到很多的基礎組件其實也需要進行拓展一些屬性,那么索性就一一封一下吧,既是學習,也是積累,本篇文章就簡單的針對圖片Image做一個封裝,此Image也是基于第一篇的BaseWidget,不熟悉的可以看下第一篇的文章。
還是按照慣例,簡單的羅列下基本的大綱:
1、實際的效果一覽
2、Image相關屬性分析
3、源碼和具體使用
4、相關總結
效果呢,很是簡單,就是一些平時的功能,比如圓角,圓形,設置占位圖等等。
自定義Image繼承了父類的一些屬性,比如寬高,內外邊距,點擊事件等,當然了,也增加了自己獨有的一些屬性,比如圓角,圓形,占位圖等,具體的父類屬性就不過多介紹了,看第一篇文章即可,簡單的列舉下Image的相關屬性。
屬性 | 類型 | 概述 |
placeholderImage | String | 占位圖(僅支持assets) |
errorImage | String | 錯誤圖(僅支持assets) |
imagePath | String | 圖片地址(支持網絡/assets/File) |
imageBoxFit | BoxFit | 圖片拉伸方式 fill:Box被完全填充,相當于ScaleType的FIT_XY。 contain:保持Box的縱橫比至至少有一邊填充滿父控件,相當于ScaleType的FIT_CENTER。 cover:保持Box的縱橫比進行縮放至Box完全填充滿父控件,超出部分進行裁剪,相當于ScaleType的CENTER_CROP。 fitWidth:縮放Box寬直至填充滿父控件。 fitHeight:縮放Box高直至填充滿父控件。 none:不進行任何縮放操作。 scaleDown:Box大于父控件,則采用與contain一致的縮放模式,否則采用none縮放模式。 |
imageLoadType | int | 圖片加載類型 |
isClipOval | bool | 是否是圓形 |
imageRadius | double | 設置圖片圓角 |
源碼就比較過分的簡單了,一是繼承原有的BaseWidget屬性,二是拓展自己的相關屬性,占位圖,錯誤圖,是否圓形,設置圓角等,具體的源碼如下:
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!);
}
}
VipImage("https://www.vipandroid.cn/ming/image/gan.png")
這個案例中結合了之前封裝的VipText控件,大家可以直接看那篇文章即可,當然你可以刪除,本身它就是一個文本Text控件,用來做個描述信息。
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),
])),
);
}
}
把相關尺寸抽成了一個常量類了,目的便于管理,大家不想用直接代碼寫值也行。
///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;
}
圖片常量類,用來存儲一些assets下的圖片地址,便于管理。
///AUTHOR:AbnerMing
///DATE:2023/5/15
///INTRODUCE:圖片地址常量
class ImageConstant {
static const String imageDefault="images/vip_ic_image_default.png";
}
在項目開發的時候,關于一些常量信息,比如尺寸的大小,本地的圖片地址,請求的接口地址等等,我們一般不要直接在頁面中寫死,一是不方便管理,二是后期一旦改動,就需要查找每個文件,非常的浪費時間,所以,盡量抽取到一個地方,類似Android中的,strings.xml,dimens.xml,colors.xml這些文件,好了鐵子們,本篇文章就先到這里,希望可以幫助大家。
天小海前端(頭條號)為大家講解一個CSS3新增的邊框圖像屬性。這個屬性是為容器的邊框來增加圖像的。該屬性的兼容性暫時還不是特別好,建議大家使用火狐瀏覽器來嘗試該屬性的各個效果。
承接文章:在Web頁面實現圓角效果,CSS3幫你輕松實現,一個人人皆知的屬性
技術等級:中級 | 適合有一定的CSS基礎的人士閱讀。
本節涉及到的CSS3屬性為:
border-image
border-image-source
border-image-slice
border-image-width
border-image-repeat
border-image-outset
一、圖像邊框的屬性:
要想實現圖像的邊框,需要用到上面提到的六個屬性。這六個屬性只有border-image屬性和border-image-outset可以直接在代碼中使用,剩下的四個屬性是border-image屬性的派生屬性,用在border-image屬性的格式中。
border-image屬性的格式如下所示:
border-image:border-image-source
border-image-slice/
border-image-width
border-image-repeat
接下來我們對其中的每一個派生屬性來進行介紹。
二、加載圖像源屬性:
border-image-source屬性用于指定邊框圖像加載的圖像路徑和文件名,取值格式為:
border-image-source:url(image_URL);
三、圖像切片屬性:
border-image-slice屬性用于指定一張圖片是如何分割為多個部分,并放置在塊級元素邊框的各個組成部分的。該屬性的取值為四個方向的像素值,并且規定不允許帶有單位。
首先,我們選擇下面這張圖片作為邊框圖片的內容。這張圖片存放在一個名為images的文件夾中,文件名為ball.jpg,圖片的寬度和高度均為90像素。圖片中的每一個圓形的直徑均為30像素。
素材圖片
border-image-slice屬性就是用來設置上下左右四個方向向內切分圖像的寬度。我們大家一塊看下張圖片。
切分圖片示意圖
可以看出,如果四個方向均向內切分30像素的大小,由于這些圓的直徑為30像素,那么這些切分線就將這張圖片劃分為了9個組成部分。這9個組成部分正好是圖片中編號的9個組成部分。
這樣,這張圖片的九個部分就會分布在邊框的以下幾個位置:
1號圓形分布在邊框的左上角。
2號圓形分布在邊框的上方。
3號圓形分布在邊框的右上角。
4號圓形分布在邊框的左側。
5號圓形CSS將其分布在容器的內部。
6號圓形分布在邊框的右側。
7號圓形分布在邊框的左下角。
8號圓形分布在邊框的下方。
9號圓形分布在邊框的右下角。
最后將圖像邊框的寬度也設置為30像素,這個圖像邊框就能夠顯示出來了。
CSS代碼如下所示:
border-image:url(../images/ball.jpg) 30/30px;
最終的顯示效果為:
代碼效果示意圖
四、圖片邊框的平鋪效果:
我們可以從效果圖中看出,在四個邊上的圖片都是拉伸的,這是由于border-image-repeat屬性的取值默認是stretch,意思是“拉伸”,該屬性還可以取值為repeat(平鋪)、round(精確平鋪)。我們將這個效果取值為round,再看一看邊框效果。
CSS代碼如下所示:
border-image:url(../images/ball.jpg) 30/30px round;
最終的顯示效果為:
代碼效果示意圖
在頭條上發表的這些文章都是從前端開發的基礎開始一步一步講起的。我非常希望能有更多的前端開發初學者通過我寫的文章,逐步學到一定的知識,甚至慢慢有了入門的感覺。這些文章都是我這幾年教學過程中的經驗,每寫一篇時我都盡量把握好措辭,用簡單易懂的語言描述,同時精心設計版面,讓版面更加豐富,激發閱讀興趣。所以,每一篇文章可能篇幅不長,但是都要耗費小海老師很久的時間。
希望收藏了這篇文章的你同時也可以關注一下“小海前端”的頭條號,因為這些文章都是連載的,并且是經過系統的歸納和總結的。塌下心來認真閱讀,你一定會學到對你有用的知識。
關注“小海前端”,我會繼續為大家奉上更加深入的前端開發文章,也希望更多的初學者跟著學下去,我們共同將前端開發的路努力堅持的走下去。
下一篇文章中,小海前端(頭條號)會為小伙伴們繼續介紹border-image屬性的詳細用法。希望正在學習CSS3技術的小伙伴們繼續關注。
片處理其實一鍵滲透到我們的基礎工作中,學會對圖片的基本處理也是工作基本功。在遇到好看的圖片卻被拉伸要如何處理?今天給大家介紹一個神奇的網站,在線一鍵修復拉伸變形圖片,處理圖像快人一步!
在線工具:圖像AI處理:zaixianai-cn/imageHandle
素材準備:變形哪吒圖片/拉伸女生圖片
打開這個神奇的網站,在線AI轉換,然后再打開“圖像AI處理”欄目,里面有其他選項,找到“拉伸圖片修復”即可。如下圖所示:
將準備好的素材,點擊“本地上傳”,然后網站就會自動開始修復啦。
圖片修復過程很快,十幾秒的時間,然后就可以自己進行比對。值得注意的是,他的優化前和優化后的圖片尺寸在網站上都會被固定尺寸給框柱,所以如果原圖片跟網站尺寸不匹配,那么效果可能看不出來,得要下載下來才看清。
點擊“立即下載”,掃描,網站就會自動下載啦!下面看看修復效果和案例吧!
網站還有語音處理功能,可以參考案例:文字如何在線轉成語音?
*請認真填寫需求信息,我們會在24小時內與您取得聯系。