IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter Key详解(LocalKeyGlobalKey)获取子组件 -> 正文阅读

[移动开发]Flutter Key详解(LocalKeyGlobalKey)获取子组件

1.Flutter Key

我们平时一定接触过很多的?Widget,比如?Container、Row、Column?等,它们在我们绘制界面的过程中发挥着重要的作用。但是不知道你有没有注意到,在几乎每个?Widget?的构造函数中,都有一个共同的参数,它们通常在参数列表的第一个,那就是?Key.

在Flutter中,Key是不能重复使用的,所以Key一般用来做唯一标识。组件在更新的时候,其状态的保存主要是通过判断组件的类型或者key值是否一致。因此,当各组件的类型不同的时候,类型已经足够用来区分不同的组件了,此时我们可以不必使用key。但是如果同时存在多个同一类型的控件的时候,此时类型已经无法作为区分的条件了,我们就需要使用到key。

Flutter key子类包含?LocalKey?和?GlobalKey?。

局部键(LocalKey):ValueKey、ObjectKey、UniqueKey

? ? ? ? ValueKey?(值key)把一个值作为key?,

? ? ? ? UniqueKey(唯一key)程序生成唯一的Key,当我们不知道如何指定ValueKey的时候就可以使用UniqueKey,

? ? ? ? ObjectKey(对象key)把一个对象实例作为key。

全局键(GlobalKey):?GlobalKey、GlobalObjectKey?

? ? ? GlobalKey(全局key),GlobalObjectKey(全局Objec key,和ObjectKey有点类似).

没有?Key?会发生什么奇怪现象

如下面例: 定义了一个StatefulWidget的Box,点击Box的时候可以改变Box里面的数字,当我们重新对Box排序的时候Flutter就无法识别到Box的变化了, 这是什么原因呢?

运行后我们发现改变list Widget顺序后,Widget颜色会变化,但是每个Widget里面的文本内容并没有变化,为什么会这样呢?当我们List重新排序后Flutter检测到了Widget的顺序变化,所以重新绘制ListWidget,但是Flutter?发现List Widget?里面的元素没有变化,所以就没有改变Widget里面的内容。

把List?里面的Box的颜色改成一样,这个时候您重新对list进行排序,就很容易理解了。重新排序后虽然执行了setState,但是代码和以前是一样的,所以Flutter不会重构List Widget里面的内容,?也就是Flutter没法通过Box里面传入的参数来识别Box是否改变。如果要让FLutter能识别到List Widget子元素的改变,就需要给每个Box指定一个key。


class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<Widget> list =  [  //注意:常量没法改变
  //1、可以保存状态 2、可以排序
   const Box(
      key: ValueKey('1'),
      color: Colors.red,
    ),
    Box(
      key: UniqueKey(),   //唯一值 每次运行的时候会随机生成
      color: Colors.yellow,
    ),
    const Box(
      key: ObjectKey(Box(color: Colors.blue)),
      color: Colors.blue
    )
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.refresh),
        onPressed: (){
          setState(() {
            list.shuffle();  //shuffle:打乱list元素的顺序
          });
        },
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: list,
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  final Color color;
  const Box({Key? key, required this.color}):super(key:key);

  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  int _count = 0;
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 100,
      width: 100,
      child: ElevatedButton(
        style: ButtonStyle(
            backgroundColor: MaterialStateProperty.all(widget.color)),
        onPressed: () {
          setState(() {
            _count++;
          });
        },
        child: Text(
          "$_count",
          style: Theme.of(context).textTheme.headline2,
        ),
      ),
    );
  }
}

?2.GlobalKey?获取子组件(3种)

? ? ?globalKey.currentState: 可以获取子组件的状态,执行子组件的方法, ? ?

? ? ?globalKey.currentWidget:可以获取子组件的属性,


? ? _globalKey.currentContext!.fifindRenderObject():可以获取渲染的属性。 ?

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

//父Widget
class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey _globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          //1、获取currentState Widget的属性(记住)
          var boxState = _globalKey.currentState as _BoxState;
          print(boxState._count);
          setState(() {
            boxState._count++;
          });
          //调用currentState Widget的方法
          boxState.run();

          //2、获取子Widget (了解)
          var boxWidget = _globalKey.currentWidget as Box;
          print(boxWidget.color);   //值:MaterialColor(primary value: Color(0xfff44336))

          // 3、获取子组件渲染的属性(了解)

           var renderBox= _globalKey.currentContext!.findRenderObject() as RenderBox;
           print(renderBox.size);  //值:Size(100.0, 100.0)


        },
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: Box(key: _globalKey, color: Colors.red),
      ),
    );
  }
}

//子Widget
class Box extends StatefulWidget {
  final Color color;
  const Box({Key? key, required this.color}) : super(key: key);
  @override
  State<Box> createState() => _BoxState();
}

class _BoxState extends State<Box> {
  int _count = 0;
  void run() {
    print("我是box的run方法");
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 100,
      width: 100,
      child: ElevatedButton(
        style: ButtonStyle(
            backgroundColor: MaterialStateProperty.all(widget.color)),
        onPressed: () {
          setState(() {
            _count++;
          });
        },
        child: Text(
          "$_count",
          style: Theme.of(context).textTheme.headline2,
        ),
      ),
    );
  }
}

3.Widget Tree、Element Tree?和?RenderObject Tree

Flutter应用是由是Widget Tree、Element Tree?和?RenderObject Tree组成

Widget可以理解成一个类,

Element可以理解成Widget的实例,

Widget与Element的关系可以是一对多,一份配置可以创造多个Element实例.

属性描述

Widget

Widget就是一个类, 是Element?的配置信息。与Element的关系可以是一对多,一份配置可以创造多个Element实例

Element

Widget?的实例化,内部持有Widget和RenderObject。

RenderObject

负责渲染绘制

默认情况下面,当Flutter同一个?Widget的大小,顺序变化的时候,FLutter不会改变Widget的state。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:26:57  更:2022-10-22 21:27:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 1:52:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码