Flutter组件 StatefulWidget、StatelessWidget 可继承写法

前言

学过Java的同学,应该都知道面向对象语言的三大特征,封装、继承、多态;

Dart也是面向对象的语言,但是在Flutter中的很多组件都被下划线 '_' 标记为私有,导致无法继承,本文将介绍一种非私有的创建组件写法。

当前案例 Flutter SDK版本:3.13.2

效果图

StatefulWidget

基类:base_stateful_widget.dart

import 'package:flutter/material.dart';


class BaseStatefulWidget extends StatefulWidget {

  final Map<String,dynamic>? arguments;
  const BaseStatefulWidget({super.key,this.arguments});

  @override
  State<BaseStatefulWidget> createState() => BaseStatefulWidgetState();
}

class BaseStatefulWidgetState<T extends StatefulWidget> extends State<BaseStatefulWidget> {

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }

}

创建第一个非私有的StatefulWidget组件:parent_box.dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/base/base_stateful_widget.dart';

class ParentBox extends BaseStatefulWidget {
  const ParentBox({super.key,super.arguments});

  @override
  ParentBoxState<ParentBox> createState() => ParentBoxState();
}

class ParentBoxState<T extends ParentBox> extends BaseStatefulWidgetState<ParentBox> {

  @override
  Widget build(BuildContext context) {
    final size = double.parse((widget.arguments?['size'] ?? 50).toString());
    return Container(
      width: size,
      height: size,
      margin: const EdgeInsets.only(bottom: 12),
      color: Colors.green,
      alignment: Alignment.center,
      child: content(),
    );
  }

  content() {
    final content = widget.arguments?['content'];
    return Text(content,
        style: const TextStyle(
          fontSize: 20,
          color: Colors.yellow,
        ));
  }

}

子类:child_box.dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/widget/parent_box.dart';

class ChildBox extends ParentBox {
  const ChildBox({super.key,super.arguments});

  @override
  ChildBoxState<ChildBox> createState() => ChildBoxState();
}

class ChildBoxState<T extends ChildBox> extends ParentBoxState<ChildBox> {

  @override
  content() {
    final content = widget.arguments?['content'];
    return Text(content,
        style: const TextStyle(
          fontSize: 20,
          color: Colors.white,
        ));
  }

}

子孙类:posterity_box.dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/widget/child_box.dart';

class PosterityBox extends ChildBox {
  const PosterityBox({super.key,super.arguments});

  @override
  ChildBoxState<ChildBox> createState() => PosterityBoxState();
}

class PosterityBoxState<T extends PosterityBox> extends ChildBoxState<PosterityBox> {

  @override
  content() {
    final content = widget.arguments?['content'];
    return Text(content,
        style: const TextStyle(
          fontSize: 20,
          color: Colors.black,
        ));
  }

}

StatelessWidget

基类:base_stateless_widget.dart

import 'package:flutter/material.dart';

class BaseStatelessWidget extends StatelessWidget {
  final Map<String,dynamic>? arguments;
  const BaseStatelessWidget({super.key, this.arguments});

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

创建第一个非私有的StatelessWidget组件:school_box.dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/base/base_stateless_widget.dart';

class SchoolBox extends BaseStatelessWidget {
  const SchoolBox({super.key,super.arguments});

  @override
  Widget build(BuildContext context) {
    final size = double.parse((arguments?['size'] ?? 50).toString());
    return Container(
      width: size,
      height: size,
      margin: const EdgeInsets.only(bottom: 12),
      color: Colors.cyan,
      alignment: Alignment.center,
      child: content(),
    );
  }

  content() {
    final content = arguments?['content'];
    return Text(content,
        style: const TextStyle(
          fontSize: 20,
          color: Colors.white,
        ));
  }

}

子类:teacher_box.dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/widget/school_box.dart';

class TeacherBox extends SchoolBox {
  const TeacherBox({super.key,super.arguments});

  @override
  content() {
    final content = arguments?['content'];
    return Text(content,
        style: const TextStyle(
          fontSize: 20,
          color: Colors.yellow,
        ));
  }

}

子孙类:student_box.dart

import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/widget/teacher_box.dart';

class StudentBox extends TeacherBox {
  const StudentBox({super.key,super.arguments});

  @override
  content() {
    final content = arguments?['content'];
    return Text(content,
        style: const TextStyle(
          fontSize: 20,
          color: Colors.greenAccent,
        ));
  }

}

入口相关文件:test_stateful_widget.dart、test_stateless_widget.dart、main.dart

import 'package:flutter/material.dart';

import '../widget/child_box.dart';
import '../widget/parent_box.dart';
import '../widget/posterity_box.dart';

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

  @override
  State<TestStatefulWidget> createState() => _TestStatefulWidgetState();
}

class _TestStatefulWidgetState extends State<TestStatefulWidget> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: const Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ParentBox(arguments: {
              'size': 260,
              'content': '父级',
            }),
            ChildBox(arguments: {
              'size': 200,
              'content': '子级',
            }),
            PosterityBox(arguments: {
              'size': 150,
              'content': '子孙级',
            }),
          ],
        ),
      ),
    );
  }

}
import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/widget/school_box.dart';
import 'package:flutter_widget_extends/widget/student_box.dart';
import 'package:flutter_widget_extends/widget/teacher_box.dart';

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

  @override
  State<TestStatelessWidget> createState() => _TestStatelessWidgetState();
}

class _TestStatelessWidgetState extends State<TestStatelessWidget> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: const Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            SchoolBox(arguments: {
              'size': 150,
              'content': '父级',
            }),
            TeacherBox(arguments: {
              'size': 200,
              'content': '子级',
            }),
            StudentBox(arguments: {
              'size': 260,
              'content': '子孙级',
            }),
          ],
        ),
      ),
    );
  }

}
import 'package:flutter/material.dart';
import 'package:flutter_widget_extends/page/test_stateful_widget.dart';
import 'package:flutter_widget_extends/page/test_stateless_widget.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SizedBox(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Padding(
              padding: const EdgeInsets.only(bottom: 16),
              child: ElevatedButton(
                onPressed: () {
                  Navigator.push<void>(
                    context,
                    MaterialPageRoute<void>(
                      builder: (BuildContext context) =>
                          const TestStatefulWidget(),
                    ),
                  );
                },
                child: const Text(
                  'TestStatefulWidget',
                  style: TextStyle(fontSize: 16),
                ),
              ),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.push<void>(
                  context,
                  MaterialPageRoute<void>(
                    builder: (BuildContext context) =>
                        const TestStatelessWidget(),
                  ),
                );
              },
              child: const Text(
                'TestStatelessWidget',
                style: TextStyle(fontSize: 16),
              ),
            )
          ],
        ),
      ),
    );
  }
}

源码地址

GitHub - LanSeLianMa/flutter_widget_extends: Flutter组件 StatefulWidget、StatelessWidget 可继承写法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/366343.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot 自定义参数配置化,密钥,密码,文件保存路径

application.properties 和 application.yml 都是一样的配置方法&#xff0c;只是格式不一样 定义配置文件 server.port8080 image.save.pathE:\ #自定义文件保存路径读取配置文件 Value("${image.save.path}")private String filePath;//E:\优化配置文件 如果我参…

处理安装uni-ui依赖一直安装不上

根据官方的文档去安装&#xff0c;我这边把npm换成了pnpm。 搞了一个小时没搞明白为什么下载不下来依赖&#xff0c;原因是镜像的问题。 处理方式&#xff1a;安装了cnpm&#xff0c;去访问国内镜像 安装cnpm&#xff0c;使用国内镜像 npm install -g cnpm --registryhttps…

Docker容器化安装SonarQube9.9

文章目录 1.环境准备1.1 版本信息1.2 系统设置 2.Docker环境安装2.1 卸载旧版本2.2 设置源2.3 安装Docker2.4 设置阿里仓库2.5 启动Docker 3.Docker Compose4.登录4.1 首页4.2 安装插件 5.制作镜像离线安装 1.环境准备 1.1 版本信息 名称版本备注Docker25.0.1当前2024-01-01最…

广州标点医药信息-米内网数据及咨询服务企业全方位解析!

米内网&#xff08;MENET&#xff09;原名中国医药经济信息网&#xff0c;由广州标点医药信息股份有限公司主办&#xff0c;2010年10月28日更名为“米内网”&#xff0c;上线初始主打医药销售数据库&#xff0c;经过十余年的迭代发展&#xff0c;现已成为国内主要的医药健康信息…

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放,Kotlin

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放&#xff0c;Kotlin class MyImageView : AppCompatImageView {private var mSrcBmp: Bitmap? nullprivate var testIV: ImageView? nullconstructor(ctx: Context, attrs: AttributeSet) :…

吸引企业选择的SD-WAN四大亮点

SD-WAN解决了传统组网所面临的各种挑战&#xff0c;尤其是分支数量众多且分散的问题&#xff0c;其实施交付成本远远低于传统方法&#xff0c;尤其在海外应用更为显著。因此&#xff0c;越来越多的企业正在转向SD-WAN网络。 为什么企业更倾向于选择SD-WAN呢&#xff1f;SD-WAN方…

【LVGL环境搭建】

LVGL环境搭建 win模拟器环境搭建一.二.三.四.五. Ubuntu模拟器环境搭建一. 前置准备二. 下载LVGL Source code&#xff1a;三. 安装sdl2&#xff1a;四. 开启VScode执行五. 安装扩展套件六. 按F5执行七. 执行结果 win模拟器环境搭建 一. 二. 三. 四. 五. Ubuntu模拟器环境…

flask基于django大数据的证券股票分析系统python可视化大屏

证券分析系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的Python进行编写&#xff0c;使用了Django框架。该系统从两个对象&#xff1a;由管理员和用户来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对股票信息、股票买入、…

正点原子--STM32定时器学习笔记(1)(更新中....)

F1系列基本定时器&#xff08;TIM6 / TIM7&#xff09; 我们的目标是通过TIM6基本定时器定时500ms&#xff0c;让LED0每隔500ms闪一下&#xff01; 思路&#xff1a;使用定时器6&#xff0c;实现500ms产生一次定时器更新中断&#xff0c;在中断里执行“翻转LED0”。 定时器什…

留学生怎么合理使用ChatGPT ?还有哪些同类工具可以使用?

一篇篇相关于ChatGPT的文章陆陆续续铺天盖地的出现在我们面前。今天我们来看看怎么使用这个宝藏工具&#xff01; 文章主要内容为&#xff1a; 1.它是什么&#xff1f; 2.它能做什么&#xff1f; 3.作为留学生我们怎么使用它&#xff1f; 4.其他同类工具推荐 5.个人观点 一…

【代码随想录】LC 1. 两数之和

文章目录 前言一、题目1、原题链接2、题目描述 二、解题报告1、思路分析2、时间复杂度3、代码详解 前言 本专栏文章为《代码随想录》书籍的刷题题解以及读书笔记&#xff0c;如有侵权&#xff0c;立即删除。 一、题目 1、原题链接 1. 两数之和 2、题目描述 二、解题报告 1、思…

故障诊断 | 一文解决,RF随机森林的故障诊断(Matlab)

效果一览 文章概述 故障诊断 | 一文解决,RF随机森林的故障诊断(Matlab) 模型描述 随机森林(Random Forest)是一种集成学习(Ensemble Learning)方法,常用于解决分类和回归问题。它由多个决策树组成,每个决策树都独立地对数据进行训练,并且最终的预测结果是由所有决策…

PostGIS教程学习二十二:使用触发器追踪历史编辑操作

PostGIS教程学习二十二&#xff1a;使用触发器追踪历史编辑操作 生产环境下数据库的一个常见要求是能够跟踪用户编辑数据的历史&#xff1a;数据在两个日期之间是如何变化的&#xff0c;是谁操作的&#xff0c;以及它们哪些内容变化了&#xff1f;一些GIS系统通过在客户端接口…

代码随想录算法训练营第38天(动态规划01 ● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

动态规划part01 理论基础509. 斐波那契数70. 爬楼梯解题思路 746. 使用最小花费爬楼梯解题思路 今天正式开始动态规划&#xff01; 理论基础 理论基础讲解 视频讲解 动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#xff0c;贪心没有状态…

1451A/D/F捷变信号发生器

01 1451A/D/F捷变信号发生器 产品综述&#xff1a; 1451系列捷变信号发生器采用直接数字合成&#xff08;DDS&#xff09;技术和直接模拟合成技术&#xff08;ADS&#xff09;相结合的设计方案&#xff0c;实现覆盖10MHz~3/20/40GHz全频段的频率捷变&#xff0c;捷变时间小于…

02链表:19、删除链表的倒数第N个节点

19、删除链表的倒数第N个节点 文章目录 19、删除链表的倒数第N个节点方法一&#xff1a;快慢指针 思路&#xff1a;使用虚拟头节点快慢指针&#xff0c;fast指针先走n1&#xff0c;直到为null&#xff0c;slow节点刚好在删除元素前一个位置&#xff0c;方便操作 重点&#xff1…

代码随想录算法训练营29期|day38 任务以及具体安排

第九章 动态规划part01 509. 斐波那契数 //非压缩状态的版本 class Solution {public int fib(int n) {if (n < 1) return n; int[] dp new int[n 1];dp[0] 0;dp[1] 1;for (int index 2; index < n; index){dp[index] dp[index - 1] dp[index - 2];}r…

《金融时报》:直面“雪球”风波 究竟影响几何?

“他们给我推荐的时候说是只要市场不大跌&#xff0c;我就能按照年化20%获得收益&#xff0c;当时我看大盘走势&#xff0c;也认为跌那么多的概率不大。”李先生告诉《金融时报》记者&#xff0c;他当初被银行客户经理推荐“雪球”产品并头脑一热买了的时候&#xff0c;以为按照…

leetcode刷题(剑指offer) 103.二叉树的锯齿形层序遍历

103.二叉树的锯齿形层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。 示例 1&#xff1a; 输入&#xff1a…

幻兽帕鲁能在Mac上运行吗?幻兽帕鲁Palworld新手攻略

幻兽帕鲁能在Mac上运行吗&#xff1f; 《幻兽帕鲁》目前还未正式登陆Mac平台&#xff0c;不过通过一些方法是可以让游戏在该平台运行的。 虽然游戏不能在最高配置下运行&#xff0c;但如果你安装了CrossOver这个软件&#xff0c;就可以玩了。这是为Mac、Linux和ChromeOS等设计…