欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flutter控件之實(shí)現(xiàn)Widget基類的封裝

 更新時(shí)間:2023年05月19日 14:35:16   作者:二流小碼農(nóng)  
在實(shí)際的開(kāi)發(fā)中,Widget的基類還是很有必要存在的,不然就會(huì)存在很多的冗余嵌套代碼,本文為大家介紹了Flutter中基類是如何封裝的,需要的可以收藏一下

在短時(shí)間的接觸Flutter之后,有一個(gè)問(wèn)題一直擺在了明面上,那就是,F(xiàn)lutter中的Widget確實(shí)沒(méi)有Android中的控件好用,在Android中,比如TextView,ImageView等等或者其他View,都有著自己非常廣泛的屬性和方法,比如寬,高,margin和padding,以及相關(guān)的點(diǎn)擊事件,這在Flutter,對(duì)應(yīng)的控件中,卻少了這些基礎(chǔ)又常用的屬性,以至于每寫一個(gè)Widget,如果想要實(shí)現(xiàn)點(diǎn)擊事件,或者margin,padding,不得不用其他的Widget包裹一層,使用起來(lái)很是不方便,基于以上的背景,便萌生了一個(gè)封裝基類的想法。

雖然之前接觸過(guò)Flutter,但也是許久不用了,今再拾起,難免有些許不足,如果在封裝上有哪些問(wèn)題,還望不吝賜教。

一、需要封裝哪些屬性

具體需要哪些屬性,不是越多越好,也不是越少越好,而是基于實(shí)際的開(kāi)發(fā)需求,拓展出常用的即可。

一個(gè)文本或者圖片控件又或者是其他控件,在實(shí)際的開(kāi)發(fā)中,哪些是我們需要考慮的?是不是最常見(jiàn)的就是自身的寬高,這是最常見(jiàn)且必須需要的,除了寬高,其自身的點(diǎn)擊事件,也是頻次居高不下的一個(gè)屬性,所以,在基類Widget中,其寬、高、點(diǎn)擊事件是必須要存在的,說(shuō)到事件,除了點(diǎn)擊事件之外,一些需求中的雙擊或者長(zhǎng)按事件也是存在的,所以,盡量也封到基類中,便于子類控件的使用。

除此之外,像外邊距、內(nèi)邊距、也是必不可少的屬性,不敢說(shuō)十個(gè)控件有九個(gè)用到,起碼說(shuō)也得一半以上的概率,所以,這也是要封裝到基類中的;至于背景屬性,比如圓角的,圓形的,空心的,實(shí)心的,這些看實(shí)際的項(xiàng)目使用,如果需要,也可以放到基類中。

初步羅列了一下,大致封裝的屬性如下,當(dāng)然了,每個(gè)人的封裝都有不同,主要還是要看實(shí)際的需求。

屬性類型概述
widthdouble
heightdouble
margindouble外邊距統(tǒng)一設(shè)置(左上右下)
marginLeftdouble外邊距(左)
marginTopdouble外邊距(上)
marginRightdouble外邊距(右)
marginBottomdouble外邊距(下)
paddingdouble內(nèi)邊距統(tǒng)一設(shè)置
paddingLeftdouble內(nèi)邊距(左)
paddingTopdouble內(nèi)邊距(上)
paddingRightdouble內(nèi)邊距(右)
paddingBottomdouble內(nèi)邊距(下)
onClick方法點(diǎn)擊事件
onDoubleClick方法雙擊事件
onLongPress方法長(zhǎng)按事件
backgroundColorColor背景顏色 和 decoration 二者取其一
strokeWidthdouble背景邊框統(tǒng)一的寬度
strokeColorColor背景邊框的顏色
solidColorColor背景填充顏色
radiusdouble背景的角度,統(tǒng)一設(shè)置
leftTopRadiusdouble背景左上角度
rightTopRadiusdouble背景右上角度
leftBottomRadiusdouble背景左下角度
rightBottomRadiusdouble背景右下角度
isCirclebool背景是否是圓形
childWidgetWidget傳遞的子控件
alignmentAlignment位置
gradientColorListList漸變顏色集合
gradientColorStopsList漸變顏色值梯度,取值范圍[0,1]
gradientBeginAlignment漸變起始位置
gradientEndAlignment漸變結(jié)束位置

二、確定基類Widget

基類的Widget主要確定以下幾個(gè)方面,第一就是,自定義一個(gè)抽象類還是非抽象類,第二、繼承方式,采取有狀態(tài)還是無(wú)狀態(tài),第三、關(guān)于組件的點(diǎn)擊方式,如何進(jìn)行實(shí)現(xiàn)。

一開(kāi)始自己寫的是一個(gè)抽象基類,畢竟在接下來(lái)的操作中,對(duì)于各個(gè)控件,我都會(huì)重新在原生的基礎(chǔ)之上進(jìn)行再次的封裝,而不是獨(dú)立的使用,這種情況下,抽象類是最合適的,向子類拓展出必須要實(shí)現(xiàn)的方法即可,但是這種情況下就有一個(gè)弊端,那就是,原生的控件無(wú)法享有這個(gè)基類的各個(gè)屬性,沒(méi)辦法,最后又改為了非抽象類,這樣,兩種方式均可滿足。

關(guān)于繼承方式,對(duì)于一個(gè)頁(yè)面而言,或多或少都是需要渲染數(shù)據(jù),更新UI的,這種情況下繼承StatefulWidget是肯定的,但是一般一個(gè)控件,都是別人來(lái)觸發(fā)它,而它自己很少主動(dòng)觸發(fā),所以,一般而言,我們繼承StatelessWidget即可。

關(guān)于組件的點(diǎn)擊方式,如果是非Button級(jí)別的,很少有控件自帶點(diǎn)擊事件,所以我們不得不自行實(shí)現(xiàn),而在Flutter中提供了很多可以協(xié)助實(shí)現(xiàn)點(diǎn)擊的組件,比如InkWell,GestureDetector,InkResponse,原始指針事件Listener,都為我們提供了豐富的觸摸事件,下面簡(jiǎn)單的列舉一下:

InkWell

InkWell(
      onLongPress: (){
        print("長(zhǎng)按事件");
      },
      onDoubleTap: (){
        print("雙擊事件");
      },
      onTap: (){
        print("點(diǎn)擊事件");
      }
      child: Container()
)

GestureDetector

return GestureDetector(
      child: const Text("首頁(yè)"),
  		onLongPress: (){
        print("長(zhǎng)按事件");
      },
      onDoubleTap: (){
        print("雙擊事件");
      },
      onTap: (){
        print("點(diǎn)擊事件");
      },
      onPanDown: (DragDownDetails detail) {
        // 手指按下的相對(duì)于屏幕的位置
        print("手指按下回調(diào)");
      },
      onPanUpdate: (DragUpdateDetails detail) {
        print("手指滑動(dòng)回調(diào)");
      },
      onPanEnd: (DragEndDetails detail) {
        print("手指停止滑動(dòng)回調(diào)");
      },
  		// 垂直方向拖動(dòng)事件
      onVerticalDragUpdate: (DragUpdateDetails details) {
      },
      // 水平方向拖動(dòng)事件
      onHorizontalDragUpdate: (DragUpdateDetails details) {
      },
    );

InkResponse

return InkResponse(
      child: const Text("點(diǎn)擊"),
      onTap: () {
        //點(diǎn)擊事件
        print("點(diǎn)擊事件");
      },
      onLongPress: () {
        //長(zhǎng)按事件
        print("長(zhǎng)按事件");
      },
      onDoubleTap: () {
        //雙擊事件
        print("雙擊事件");
      },
    );

原始指針事件

return Listener(
      child: Container(
        child: const Text("測(cè)試"),
      ),
  		//手指按下回調(diào)
      onPointerDown: (PointerDownEvent event) {},
  		//手指移動(dòng)回調(diào)
      onPointerMove: (PointerMoveEvent event) {},
  		//手指抬起回調(diào)
      onPointerUp: (PointerUpEvent event) {},
  		//觸摸事件取消回調(diào)
      onPointerCancel: (PointerCancelEvent event) {},
    );

相關(guān)的屬性有很多,大家可以看下相關(guān)源碼,具體用哪個(gè),我是認(rèn)為,前三個(gè)都可以,畢竟都有相關(guān)的點(diǎn)擊,雙擊,長(zhǎng)按事件,如果你想要獲取更多的觸摸事件,那么就可以使用GestureDetector,如果只是點(diǎn)擊,長(zhǎng)按和雙擊,比較推薦InkWell,相對(duì)點(diǎn)擊比較靈敏,當(dāng)然了,具體使用哪個(gè),還是要看自己。

三、基類實(shí)現(xiàn)

基類實(shí)現(xiàn)就比較的簡(jiǎn)單了,build方法中最外層用點(diǎn)擊事件包裹,再往下用Container組件來(lái)包裹,目的用于寬高,margin,padding和背景等實(shí)現(xiàn),圓角和圓形以及漸變用的是Container的屬性decoration。

全部的源碼如下,都是系統(tǒng)的api調(diào)用,沒(méi)有特別難的。

import 'package:flutter/material.dart';
///AUTHOR:AbnerMing
///DATE:2023/5/11
///INTRODUCE:控件無(wú)狀態(tài)基類
class BaseWidget extends StatelessWidget {
  final VoidCallback? onClick; //點(diǎn)擊事件
  final VoidCallback? onDoubleClick; //雙擊事件
  final VoidCallback? onLongPress; //長(zhǎng)按事件
  final double? width; //寬度
  final double? height; //高度
  final double? margin; //外邊距,左上右下
  final double? marginLeft; //外邊距,距離左邊
  final double? marginTop; //外邊距,距離上邊
  final double? marginRight; //外邊距,距離右邊
  final double? marginBottom; //外邊距,距離下邊
  final double? padding; //內(nèi)邊距,左上右下
  final double? paddingLeft; //內(nèi)邊距,距離左邊
  final double? paddingTop; //內(nèi)邊距,距離上邊
  final double? paddingRight; //內(nèi)邊距,距離右邊
  final double? paddingBottom; //內(nèi)邊距,距離下邊
  final Color? backgroundColor; //背景顏色 和 decoration 二者取其一
  final double? strokeWidth; //背景邊框統(tǒng)一的寬度
  final Color? strokeColor; //背景邊框的顏色
  final Color? solidColor; //背景填充顏色
  final double? radius; //背景的角度
  final bool? isCircle; //背景是否是圓形
  final double? leftTopRadius; //背景左上角度
  final double? rightTopRadius; //背景 右上角度
  final double? leftBottomRadius; //背景 左下角度
  final double? rightBottomRadius; //背景 右下角度
  final Widget? childWidget; //子控件
  final Alignment? alignment; //位置
  final int? gradient; //漸變方式,為支持后續(xù)拓展,用int類型
  final List<Color>? gradientColorList; //漸變顏色
  final List<double>? gradientColorStops; //顏色值梯度,取值范圍[0,1]
  final Alignment? gradientBegin; //漸變起始位置
  final Alignment? gradientEnd; //漸變結(jié)束位置
  //邊框的顏色
  const BaseWidget(
      {super.key,
      this.width,
      this.height,
      this.margin,
      this.marginLeft,
      this.marginTop,
      this.marginRight,
      this.marginBottom,
      this.padding,
      this.paddingLeft,
      this.paddingTop,
      this.paddingRight,
      this.paddingBottom,
      this.backgroundColor,
      this.strokeWidth,
      this.strokeColor,
      this.solidColor,
      this.radius,
      this.isCircle,
      this.leftTopRadius,
      this.rightTopRadius,
      this.leftBottomRadius,
      this.rightBottomRadius,
      this.childWidget,
      this.alignment,
      this.gradient,
      this.gradientColorList,
      this.gradientColorStops,
      this.gradientBegin,
      this.gradientEnd,
      this.onClick,
      this.onDoubleClick,
      this.onLongPress});
  @override
  Widget build(BuildContext context) {
    return InkWell(
        highlightColor: Colors.transparent,
        // 透明色
        splashColor: Colors.transparent,
        // 透明色
        onTap: onClick,
        onDoubleTap: onDoubleClick,
        onLongPress: onLongPress,
        child: Container(
          width: width,
          height: height,
          alignment: alignment,
          margin: margin != null
              ? EdgeInsets.all(margin!)
              : EdgeInsets.only(
                  left: marginLeft != null ? marginLeft! : 0,
                  top: marginTop != null ? marginTop! : 0,
                  right: marginRight != null ? marginRight! : 0,
                  bottom: marginBottom != null ? marginBottom! : 0),
          padding: padding != null
              ? EdgeInsets.all(padding!)
              : EdgeInsets.only(
                  left: paddingLeft != null ? paddingLeft! : 0,
                  top: paddingTop != null ? paddingTop! : 0,
                  right: paddingRight != null ? paddingRight! : 0,
                  bottom: paddingBottom != null ? paddingBottom! : 0,
                ),
          color: backgroundColor,
          decoration: backgroundColor != null ? null : getDecoration(),
          child: childWidget ?? getWidget(context),
        ));
  }
  /*
  * 獲取Decoration
  * */
  Decoration? getDecoration() {
    BorderRadiusGeometry? borderRadiusGeometry;
    if (radius != null) {
      //所有的角度
      borderRadiusGeometry = BorderRadius.all(Radius.circular(radius!));
    } else {
      //否則就是,各個(gè)角度
      borderRadiusGeometry = BorderRadius.only(
          topLeft: Radius.circular(leftTopRadius != null ? leftTopRadius! : 0),
          topRight:
              Radius.circular(rightTopRadius != null ? rightTopRadius! : 0),
          bottomLeft:
              Radius.circular(leftBottomRadius != null ? leftBottomRadius! : 0),
          bottomRight: Radius.circular(
              rightBottomRadius != null ? rightBottomRadius! : 0));
    }
    Gradient? tGradient;
    if (gradient != null) {
      tGradient = LinearGradient(
        colors: gradientColorList != null ? gradientColorList! : [],
        // 設(shè)置有哪些漸變色
        begin: gradientBegin != null ? gradientBegin! : Alignment.centerLeft,
        // 漸變色開(kāi)始的位置,默認(rèn) centerLeft
        end: gradientEnd != null ? gradientEnd! : Alignment.centerRight,
        // 漸變色結(jié)束的位置,默認(rèn) centerRight
        stops: gradientColorStops, // 顏色值梯度,取值范圍[0,1],長(zhǎng)度要和 colors 的長(zhǎng)度一樣
      );
    }
    Decoration? widgetDecoration = BoxDecoration(
      gradient: tGradient,
      //背景顏色
      color: solidColor != null ? solidColor! : Colors.transparent,
      //圓角半徑
      borderRadius: isCircle == true ? null : borderRadiusGeometry,
      //是否是圓形
      shape: isCircle == true ? BoxShape.circle : BoxShape.rectangle,
      //邊框線寬、顏色
      border: Border.all(
          width: strokeWidth != null ? strokeWidth! : 0,
          color: strokeColor != null ? strokeColor! : Colors.transparent),
    );
    return widgetDecoration;
  }
  /*
  * 獲取控件
  * */
  Widget? getWidget(BuildContext context) {
    return null;
  }
}

具體使用

使用方式有兩種,一種是直接使用,用BaseWidget包裹你的組件即可,相關(guān)屬性和方法就可以直接調(diào)用了。

return BaseWidget(
      childWidget: const Text("測(cè)試文本"),
      margin: 10,
      onClick: () {
        //點(diǎn)擊事件
      },
    );

第二種就是,自己定義組件,繼承BaseWidget,可擴(kuò)展自己想要實(shí)現(xiàn)的屬性,之后直接用自己定義的組件即可,比如我想自定義一個(gè)Text,如下所示:

class SelfText extends BaseWidget {
  final String? text;
  const SelfText(this.text,
      {super.key,
      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.onClick,
      super.onDoubleClick,
      super.onLongPress});
  @override
  Widget? getWidget(BuildContext context) {
    return Text(text!);
  }
}

具體使用的時(shí)候,直接使用,就不用在外層包裹BaseWidget,而且你還可以在自定義類中隨意擴(kuò)展自己的屬性。

return SelfText(
      "測(cè)試文本",
      margin: 10,
      onClick: () {
        //點(diǎn)擊事件
      },
    );

四、相關(guān)總結(jié)

在實(shí)際的開(kāi)發(fā)中,Widget的基類還是很有必要存在的,不然就會(huì)存在很多的冗余嵌套代碼,具體如何去封裝,還要根據(jù)相關(guān)的需求和業(yè)務(wù)來(lái)實(shí)際的操作。好了鐵子們,本篇文章就到這里,不管封裝的好與壞,都希望可以幫助到大家。

以上就是Flutter控件之實(shí)現(xiàn)Widget基類的封裝的詳細(xì)內(nèi)容,更多關(guān)于Flutter Widget的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論