在AndroidStudio中对Flutter的认识

在AndroidStudio中对Flutter的认识,第1张

文章目录 前言一、Flutter是什么?二、为什么选择Flutter1.使用Dart语言2.快速开发 三、Key的介绍Key1.ValueKey2.LocalKey3.GlobalKey 使用Key做一个小程序参考文献


前言

​在Android Studio的学习中,我认识到不同iosandroid和PC端之间存在不同。苹果在2008年发布iOS,Google 在2009年发布Android,它们的SDK使用的是不同的编程语言,Objective-C,Swift和Java,Kotlin。开发人员在直接调用平台SDK进行UI开发时,由于语言以及SDK的不同,所以开发人员必须为两个平台分别开发App。那么开发人员的工作量将会大大提升,所以由逐渐推出了很多跨平台的开发。Flutter就是其中的一种。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Flutter是什么?

Flutter is Google’s UI toolkit for building beautiful,natively compiled applicatioins for mobile,web,and desktop from a single condebase.(引用自官网)
由上面的介绍可以知道Flutter是Google一个新的用于构建跨平台的手机App的SDK。即写一份代码,在Android 和iOS平台上都可以运行。

二、为什么选择Flutter

越来越多的App包含Flutter,如QQ,QQ邮箱,Soul等的制作中都含有Flutter。这也可以体现出Flutter的实用性。但为什么会选择Flutter呢?

1.使用Dart语言

根据大神介绍,Dart语言是构建客户端应用程序的绝佳工具,而且针对UI开发工作做了调整和优化。它与其他语言(C#,Java)相似,所以大部分开发人员可以快速上手并使用它。
代码如下(部分):

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(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
2.快速开发

使用过Android Studio的朋友都应该被它的速度折服过,而且,虽然Android Studio的xml文件具有布局预览功能,但在自定义View的时候不是每次都像所预期的运行。
但Flutter有“热重载”功能,可以实时看到应用的变化,且不会丢失当前应用程序的状态。“热重载”的实现与Dart语言有关。Dart语言支持JIT(Just In Time)。即能够即时编译或运行时编译。这样就可以实时看到应用的变化了。


## 3.良好的交互体验 用户体验的关键时App的性能,而Flutter不依赖任何中间代码做映射,直接调用底层代码,极大的提高了性能。 而对于开发人员,Flutter可以随时修改屏幕上的任何空间,可以直接使用原生控件来做UI动画,在使用Flutter生成动画的时候,不仅更加灵活和通用,而且不会额外增加工作量。
三、Key的介绍

Flutter积攒了纪念的Widget,像是专门为我们准备的礼物
在介绍Key之前,我们要理解它是谁的参数。
–>Widget
我们要理解Widget到底是什么。
Widget是Flutter应用程序用户界面的基本构建块。
每个Widget都是用户界面一部分的不可变声明。 与其他将视图、控制器、布局和其他属性分离的框架不同,Flutter具有一致的统一对象模型:widget。可以理解为Widget是描述UI元素Element的配置数据。一个Widget可以对应多个Element,即:同一份配置,可生成多个Element;每个Element都会对应一个Widget。

abstract class Widget extends DiagnosticableTree {

  const Widget({ this.key });

  final Key key;

  @protected
  Element createElement();

  ...
  

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}

而如何灵活的运用Widget,Key很重要。


Key

此处将Key设置为一级标题,只是为了强调Key,并非格式错误
Widget的构造方法中有一个可选参数Key

abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });

首先我们可以想想:
如果没有Key会发生什么
如果StatelessWidget没有Key不会出现问题,
但StatefulWidget如果没有Key就会导致无法进行添加删除等 *** 作。因为代码无法判断相同的三个代码,就像你无法判断三个长相一直的三胞胎。

        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Box(Colors.blue),
            Box(Colors.blue),
            Box(Colors.blue),
            ),
          ],
        ),

Key就像一个id一样控制Widget。就如同给三胞胎发身份z,我们就可以通过身份z去分辨他们

        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Box(Colors.blue,ValueKey(1)),
            Box(Colors.blue,ValueKey(2)),
            Box(Colors.blue,ValueKey(3)),
            ),
          ],
        ),

所以就可以实现Key控制一个Widget替换另一个Widget。如果两个Widget的runtimeType与Key相同,则表示新的Widget将替换旧的Widget。
但Widget不是最终出现在屏幕上的东西。Element才是;Widget就相当于一个蓝图,而他的实例化就是Element。
所以如果没有key,即两个Widget的runtimeType和Key相同,会update更新Element;否则旧的Element将从树中移出,新的element插入树中。


1.ValueKey

是新建Flutter时候默认的Key,存在与LocalKey中。
是以一个值作为 Key。比如数字,字母等。

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  ......
  class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

例如:

            Text("name"),
            TextField(key: ValueKey("name"),),
            Text("Address"),
            TextField(key: ValueKey("Address"),),

2.LocalKey

局部键
除了刚刚在1.中讲解的ValueKey
还存在:
ObjectKey
以一个对象作为 Key。当多个值才能唯一标识的时候,将这多个值组合成一个对象。比如【学校 + 学号】才能唯一标识一个学生。

class ObjectKey extends LocalKey {
  /// Creates a key that uses [identical] on [value] for its [operator==].
  const ObjectKey(this.value);

  /// The object whose identity is used by this key's [operator==].
  final Object? value;

  @override
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType)
      return false;
    return other is ObjectKey
        && identical(other.value, value);
  }

UniqueKey
生成唯一随机数(对象的 Hash 值)作为 Key。注意:如果直接在控件构建的时候生成,那么每次构建都会生成不同的 Key。

class UniqueKey extends LocalKey {
  /// Creates a key that is equal only to itself.
  ///
  /// The key cannot be created with a const constructor because that implies
  /// that all instantiated keys would be the same instance and therefore not
  /// be unique.
  // ignore: prefer_const_constructors_in_immutables , never use const for this class
  UniqueKey();

  @override
  String toString() => '[#${shortHash(this)}]';
}

如果不加上UniqueKey,则动画效果会直接改变,但加上UniqueKey,会逐渐改变文字,由hi逐渐变为hello。

AnimatedSwitcher(
     duration:Duration(seconds:1),
child:Text("hello",key:Uniquekey(),),//child:Text("hi",key:Uniquekey(),),
)

3.GlobalKey

全局键
通过 GlobalKey 能够跨 Widget 访问状态。

final _globalKey = GlobalKey();
......
body:Center(
child:Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
          counter(),
          Center(child:Counter(_globalKey)),
]
)
)
......
class Counter extends StatefulWidget{
   Count([Key key]):super(key:key);
   @override
   _CounterState createState()=>_CounterState();
}

使用Key做一个小程序

提示:这里运用刚刚讲解的Key做一个小游戏:分辨颜色深浅
(此部分为Key的代码)

class Box extends StatelessWidget {
  static const width = 60.0;
  static const height = 150.0;
  static const margin = 2.0;

  final Function(Color) onDrag;
  final Color color;
  final double x,y;
  final Function() onEnd;

  Box(
     this.color,
     this.x,
     this.y,
     this.onDrag,
     this.onEnd,
     ) : super(key: ValueKey(color),);//ValueKey!!!

  @override
  Widget build(BuildContext context) {

    final container = Container(
          width: width - margin * 2,
          height: height - margin * 2,
          decoration: BoxDecoration(
            color: color,
            borderRadius: BorderRadius.circular(8.0),//圆边框
          ),
    );

    return AnimatedPositioned(//隐式动画,决定拖动时出现躲避的效果
      duration: Duration(milliseconds: 100),
      top: y,
      left: x,
      child: Draggable(//Draggable可以实现拖拽
        onDragStarted: () => onDrag(color),
        onDragEnd: (_) => onEnd(),
        child: container,
        feedback: container,//拖动时的反馈
        childWhenDragging: Container(//留下的渲染
          width: width - margin * 2,
          height: height - margin * 2,
        ),
      ),
    );
  }
}

而为了可以实现左右拖动时发生位置的变化:

      body: Listener(//监听者,监听事件,得到位置
        onPointerMove: (event){
          final x = event.position.dx;
          if (x > (_slot +1)* Box.width) { //实现互换
            if (_slot == _colors.length - 1) return;
            setState(() {
              final c = _colors[_slot];
              _colors[_slot] = _colors[_slot + 1];
              _colors[_slot + 1] = c;
              _slot++;//相应的往后移一位
            });
          }else if(x < _slot * Box.width){
            if (_slot == 0) return;
            setState(() {
              final c = _colors[_slot];
              _colors[_slot] = _colors[_slot - 1];
              _colors[_slot - 1] = c;
              _slot--;//相应的往前移一位
    });

    }
        },

        child: SizedBox(
          child: Stack(//自己写类似于ReorderableListView,但更加灵活,不用长按,也可以上下左右的移动
            children: List.generate(_colors.length, (i) {
              return Box(
                _colors[i],
                i*Box.width,
                200,
                (Color color){
                  final index = _colors.indexOf(color);//得到拖拽的颜色框号码
                    _slot = index;
                    },
                ValueKey(_colors[i]),
              );
            }),
          ),
        ),
      ), // This trailing comma makes auto-formatting nicer for build methods.

图片展示:

为了检测所拖动的代码是否成功,加入_checkWinCondition()检测方块

   _checkWinCondition(){//检测方块
     List<double> lum = _colors.map((c) => c.computerLuminance()).toList();
     
     bool success = true;
     for (int i = 0; i < lum.length - 1;i++){
       if(lum[i] > lum[i + 1]){
         success = false;
         break;
       }
     }
     print(success ? "win" : "");
   }

图片展示:
成功提示:

为了更加有趣味性,添加颜色多变,点击返回按钮时,颜色能发生随机改变

   _shuffle(){
     _color = Colors.primaries[Random().nextInt(Colors.primaries.length)];
     _colors = List.generate(6, (index) => _color[(index + 1) * 100]);
     setState(() => _colors.shuffle());
   }

图片展示:

参考文献

1.8个Flutter的优势以及为什么要在下一个项目中尝试Flutter
2.Flutter 中的 Key

作者:彭馨逸
原文链接

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/994286.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存