国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(一)Widget

這篇具有很好參考價(jià)值的文章主要介紹了Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(一)Widget。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

目錄

0 引言

1 Widget 簡(jiǎn)介

1.1 Widget 概念

1.2?Widget 接口

1.3?Flutter中的四棵樹(shù)

1.4?StatelessWidget

1.4.1 簡(jiǎn)介

1.4.2?Context上下文

1.5?StatefulWidget

1.6??State

1.6.1 簡(jiǎn)介

1.6.2?State生命周期

1.7??在 widget 樹(shù)中獲取State對(duì)象

1.7.1 通過(guò)Context獲取

1.7.2 通過(guò)GlobalKey獲取

1.8?通過(guò) RenderObject 自定義 Widget

1.9?Flutter SDK內(nèi)置組件庫(kù)介紹

1.9.1?基礎(chǔ)組件

1.9.2 Material組件

1.9.3 ?Cupertino組件

1.10 總結(jié)


0 引言

本文是對(duì)第二版序 | 《Flutter實(shí)戰(zhàn)·第二版》 (flutterchina.club)的學(xué)習(xí)和總結(jié)。

1 Widget 簡(jiǎn)介

1.1 Widget 概念

  • Widget 字面意思:控件、組件、部件、微件、插件、小工具
  • widget 的功能是“描述一個(gè)UI元素的配置信息”,所謂的配置信息就是 Widget 接收的參數(shù)
  • Widget 只是描述一個(gè)UI元素的配置信息,并不是表示最終繪制在設(shè)備屏幕上的顯示元素

1.2?Widget 接口

  • @immutable?代表 Widget 是不可變的,即Widget 中定義的屬性必須是 final。
  • widget類(lèi)繼承自DiagnosticableTree,即“診斷樹(shù)”,主要作用是提供調(diào)試信息。
  • Key屬性類(lèi)似于 React/Vue 中的key,主要的作用是決定是否在下一次build時(shí)復(fù)用舊的 widget ,決定的條件在canUpdate()方法中。
  • createElement():一個(gè) widget 可以對(duì)應(yīng)多個(gè)Element,Flutter 框架在構(gòu)建UI樹(shù)時(shí),會(huì)先調(diào)用此方法生成對(duì)應(yīng)節(jié)點(diǎn)的Element對(duì)象。此方法是 Flutter 框架隱式調(diào)用的,在開(kāi)發(fā)過(guò)程中基本不會(huì)調(diào)用到。
  • debugFillProperties(...)?復(fù)寫(xiě)父類(lèi)的方法,主要是設(shè)置診斷樹(shù)的一些特性。
  • canUpdate(...)是一個(gè)靜態(tài)方法,只要newWidgetoldWidgetruntimeTypekey同時(shí)相等,就會(huì)用new widget去更新舊UI樹(shù)上所對(duì)應(yīng)的Element對(duì)象的配置,否則會(huì)創(chuàng)建新的Element對(duì)象。
  • 在 Flutter 開(kāi)發(fā)中,一般不用直接繼承Widget類(lèi)來(lái)實(shí)現(xiàn)一個(gè)新組件。通常會(huì)通過(guò)繼承StatelessWidgetStatefulWidget來(lái)間接繼承widget類(lèi)來(lái)實(shí)現(xiàn)。
/*
Widget 類(lèi)的聲明:
*/
@immutable // 不可變的
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });

  final Key? key;

  @protected
  @factory
  Element createElement();

  @override
  String toStringShort() {
    final String type = objectRuntimeType(this, 'Widget');
    return key == null ? type : '$type-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  @override
  @nonVirtual
  bool operator ==(Object other) => super == other;

  @override
  @nonVirtual
  int get hashCode => super.hashCode;

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

1.3?Flutter中的四棵樹(shù)

Flutter 框架的處理流程:(真正的布局、繪制是由誰(shuí)來(lái)完成的)

  1. 根據(jù) Widget 樹(shù)生成一個(gè) Element 樹(shù),Element 樹(shù)中的節(jié)點(diǎn)都繼承自?Element?類(lèi)。
  2. 根據(jù) Element 樹(shù)生成 Render 樹(shù)(渲染樹(shù)),渲染樹(shù)中的節(jié)點(diǎn)都繼承自RenderObject?類(lèi)。
  3. 根據(jù)渲染樹(shù)生成 Layer 樹(shù),然后上屏顯示,Layer 樹(shù)中的節(jié)點(diǎn)都繼承自?Layer?類(lèi)。
  • ?Flutter 真正的布局和渲染邏輯在 Render 樹(shù)中
  • Element 是 Widget 和 RenderObject 的粘合劑,可以理解為一個(gè)中間代理。
/*假設(shè)有如下 Widget 樹(shù):
  Container 內(nèi)部會(huì)創(chuàng)建一個(gè)新的 ColoredBox 來(lái)填充背景
  Image 內(nèi)部會(huì)通過(guò) RawImage 來(lái)渲染圖片
  Text 內(nèi)部會(huì)通過(guò) RichText 來(lái)渲染文本
*/
Container( // 一個(gè)容器 widget
  color: Colors.blue, // 設(shè)置容器背景色
  child: Row( // 可以將子widget沿水平方向排列
    children: [
      Image.network('https://www.example.com/1.png'), // 顯示圖片的 widget
      const Text('A'),
    ],
  ),
);

?Widget樹(shù)、Element 樹(shù)、渲染樹(shù)結(jié)構(gòu):

Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(一)Widget,Flutter,flutter,學(xué)習(xí)

1.4?StatelessWidget

1.4.1 簡(jiǎn)介

  • 無(wú)狀態(tài)的組件,用于不需要維護(hù)狀態(tài)的場(chǎng)景
  • 繼承自widget類(lèi),重寫(xiě)了createElement()方法
  • 通常在build方法中通過(guò)嵌套其他 widget 來(lái)構(gòu)建UI,在構(gòu)建過(guò)程中會(huì)遞歸的構(gòu)建其嵌套的 widget
//main 函數(shù)為應(yīng)用程序的入口
void main() {
  //runApp(Widget參數(shù)),它的功能是啟動(dòng)Flutter應(yīng)用
  runApp(const MyApp()); 
}

//MyApp對(duì)象 
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // 應(yīng)用的根組件
  @override
  Widget build(BuildContext context) {
      // 調(diào)用自定義的 widget 
      return Echo(text: "hello world");
  }
}

// 自定義 widget 
class Echo extends StatelessWidget  {
  //使用命名參數(shù),定義 widget 的構(gòu)造函數(shù)
  const Echo({
    Key? key, //在繼承 widget 時(shí),第一個(gè)參數(shù)通常應(yīng)該是Key
    required this.text, //必需要傳的參數(shù)要添加required關(guān)鍵字
    this.backgroundColor = Colors.grey, //默認(rèn)為灰色
  }):super(key:key);
  
  // widget 的屬性應(yīng)盡可能的被聲明為final,防止被意外改變
  final String text;
  final Color backgroundColor;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        color: backgroundColor,
        child: Text(text),  //child或children參數(shù)通常應(yīng)被放在參數(shù)列表的最后
      ),
    );
  }

1.4.2?Context上下文

  • ?build方法有一個(gè)context參數(shù)
  • 它是BuildContext類(lèi)的一個(gè)實(shí)例,表示當(dāng)前 widget 在 widget 樹(shù)中的上下文
  • 每一個(gè) widget 都會(huì)對(duì)應(yīng)一個(gè) context 對(duì)象
  • 它提供了從當(dāng)前 widget 開(kāi)始向上遍歷 widget 樹(shù)的方法
  • 它提供了按照 widget 類(lèi)型查找父級(jí) widget 的方法
class ContextRoute extends StatelessWidget  {
  @override
  Widget build(BuildContext context) {
    /*
      Scaffold 是 Material 庫(kù)中提供的頁(yè)面腳手架
      它提供了默認(rèn)的導(dǎo)航欄、標(biāo)題和包含主屏幕 widget 樹(shù)的body屬性
    */
    return Scaffold(
      appBar: AppBar(
        title: Text("Context測(cè)試"),
      ),
      body: Container( // 一個(gè)容器 widget
        child: Builder(builder: (context) {
          // 在 widget 樹(shù)中向上查找最近的父級(jí)`Scaffold`  widget 
          Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
          // 直接返回 AppBar的title, 此處實(shí)際上是Text("Context測(cè)試")
          return (scaffold.appBar as AppBar).title;
        }),
      ),
    );
  }
}

1.5?StatefulWidget

  • 有狀態(tài)的組件,用于需要維護(hù)狀態(tài)的場(chǎng)景
  • 繼承自widget類(lèi),重寫(xiě)了createElement()方法
  • 添加了一個(gè)新的接口createState()
  • State 對(duì)象和StatefulElement具有一一對(duì)應(yīng)的關(guān)系
/*
StatefulWidget的類(lèi)定義:
*/
abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
    
  @override
  StatefulElement createElement() => StatefulElement(this); 

  /*
     用于創(chuàng)建和 StatefulWidget 相關(guān)的狀態(tài),
     在StatefulWidget 的生命周期中可能會(huì)被多次調(diào)用,
     一個(gè)StatefulElement對(duì)應(yīng)一個(gè)State實(shí)例
  */
  @protected
  State createState(); 
}

1.6??State

1.6.1 簡(jiǎn)介

一個(gè) StatefulWidget 類(lèi)會(huì)對(duì)應(yīng)一個(gè) State 類(lèi),State表示與其對(duì)應(yīng)的 StatefulWidget 要維護(hù)的狀態(tài),State 中保存的狀態(tài)信息可以:

  1. 在 widget 構(gòu)建時(shí)可以被同步讀取。
  2. 在 widget 生命周期中可以被改變,當(dāng)State被改變時(shí),可以手動(dòng)調(diào)用其setState()方法通知Flutter 框架狀態(tài)發(fā)生改變,F(xiàn)lutter 框架在收到消息后,會(huì)重新調(diào)用其build方法重新構(gòu)建 widget 樹(shù),從而達(dá)到更新UI的目的。

?State 中有兩個(gè)常用屬性:

  1. widget,它表示與該 State 實(shí)例關(guān)聯(lián)的 widget 實(shí)例,由Flutter 框架動(dòng)態(tài)設(shè)置。注意,這種關(guān)聯(lián)并非永久的,因?yàn)樵趹?yīng)用生命周期中,UI樹(shù)上的某一個(gè)節(jié)點(diǎn)的 widget 實(shí)例在重新構(gòu)建時(shí)可能會(huì)變化,但State實(shí)例只會(huì)在第一次插入到樹(shù)中時(shí)被創(chuàng)建,當(dāng)在重新構(gòu)建時(shí),如果 widget 被修改了,F(xiàn)lutter 框架會(huì)動(dòng)態(tài)設(shè)置State. widget 為新的 widget 實(shí)例。
  2. context。StatefulWidget對(duì)應(yīng)的 BuildContext,作用同StatelessWidget 的BuildContext。

1.6.2?State生命周期

  • initState當(dāng) widget 第一次插入到 widget 樹(shù)時(shí)會(huì)被調(diào)用,對(duì)于每一個(gè)State對(duì)象,F(xiàn)lutter 框架只會(huì)調(diào)用一次該回調(diào)。所以,通常在該回調(diào)中做一些一次性的操作,如狀態(tài)初始化、訂閱子樹(shù)的事件通知等。
  • didChangeDependencies()當(dāng)State對(duì)象的依賴(lài)發(fā)生變化時(shí)會(huì)被調(diào)用。組件第一次被創(chuàng)建后掛載的時(shí)候(包括重創(chuàng)建)對(duì)應(yīng)的didChangeDependencies也會(huì)被調(diào)用。
  • build()用于構(gòu)建 widget 子樹(shù)的,會(huì)在如下場(chǎng)景被調(diào)用:

    1. 在調(diào)用initState()之后。
    2. 在調(diào)用didUpdateWidget()之后。
    3. 在調(diào)用setState()之后。
    4. 在調(diào)用didChangeDependencies()之后。
    5. 在State對(duì)象從樹(shù)中一個(gè)位置移除后(會(huì)調(diào)用deactivate)又重新插入到樹(shù)的其他位置之后。
  • reassemble()專(zhuān)門(mén)為了開(kāi)發(fā)調(diào)試而提供的,在熱重載(hot reload)時(shí)會(huì)被調(diào)用,在Release模式下永遠(yuǎn)不會(huì)被調(diào)用。

  • didUpdateWidget()在 widget 重新構(gòu)建時(shí),F(xiàn)lutter 框架會(huì)調(diào)用widget.canUpdate來(lái)檢測(cè) widget 樹(shù)中同一位置的新舊節(jié)點(diǎn),然后決定是否需要更新,如果widget.canUpdate返回true則會(huì)調(diào)用此回調(diào)。widget.canUpdate會(huì)在新舊 widget 的?key?和?runtimeType?同時(shí)相等時(shí)會(huì)返回true。

  • deactivate()當(dāng) State 對(duì)象從樹(shù)中被移除時(shí),會(huì)調(diào)用此回調(diào)。在一些場(chǎng)景下,F(xiàn)lutter 框架會(huì)將 State 對(duì)象重新插到樹(shù)中,如包含此 State 對(duì)象的子樹(shù)在樹(shù)的一個(gè)位置移動(dòng)到另一個(gè)位置時(shí)。如果移除后沒(méi)有重新插入到樹(shù)中則緊接著會(huì)調(diào)用dispose()方法。

  • dispose()當(dāng) State 對(duì)象從樹(shù)中被永久移除時(shí)調(diào)用;通常在此回調(diào)中釋放資源。

  • 注意:在繼承StatefulWidget重寫(xiě)其方法時(shí),對(duì)于包含@mustCallSuper標(biāo)注的父類(lèi)方法,都要在子類(lèi)方法中調(diào)用父類(lèi)方法。

/*
  實(shí)現(xiàn)一個(gè)計(jì)數(shù)器 CounterWidget 組件 ,點(diǎn)擊它可以使計(jì)數(shù)器加1,
  由于要保存計(jì)數(shù)器的數(shù)值狀態(tài),所以應(yīng)繼承StatefulWidget
*/
class CounterWidget extends StatefulWidget {
  //構(gòu)造函數(shù)
  const CounterWidget({Key? key, this.initValue = 0});

  //組件的參數(shù)
  final int initValue;

  //重寫(xiě)createState方法
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

/*
  createState方法
*/
class _CounterWidgetState extends State<CounterWidget> {
  int _counter = 0;

  @override
  void initState() {
    super.initState();
    //初始化狀態(tài)
    _counter = widget.initValue;
    print("initState");
  }

  @override
  Widget build(BuildContext context) {
    print("build");
    return Scaffold(
      body: Center(
        child: TextButton(
          child: Text('$_counter'),
          //點(diǎn)擊后計(jì)數(shù)器自增
          onPressed: () => setState(
            () => ++_counter,
          ),
        ),
      ),
    );
  }

  @override
  void didUpdateWidget(CounterWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("didUpdateWidget ");
  }

  @override
  void deactivate() {
    super.deactivate();
    print("deactivate");
  }

  @override
  void dispose() {
    super.dispose();
    print("dispose");
  }

  @override
  void reassemble() {
    super.reassemble();
    print("reassemble");
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("didChangeDependencies");
  }
}

/*
  調(diào)用自定義的CounterWidget
*/
class StateLifecycleTest extends StatelessWidget {
  const StateLifecycleTest({Key? key}) : super(key: key);

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

/*
 1.運(yùn)行應(yīng)用,屏幕中央就會(huì)出現(xiàn)一個(gè)數(shù)字0,然后控制臺(tái)日志輸出:
    I/flutter ( 5436): initState
    I/flutter ( 5436): didChangeDependencies
    I/flutter ( 5436): build
 2.熱重載,控制臺(tái)輸出日志如下:
    I/flutter ( 5436): reassemble
    I/flutter ( 5436): didUpdateWidget 
    I/flutter ( 5436): build
 3.將return CounterWidget();改為 return Text("xxx");然后熱重載,日志如下:
    I/flutter ( 5436): reassemble
    I/flutter ( 5436): deactive
    I/flutter ( 5436): dispose   
*/

?StatefulWidget 生命周期如下圖所示:

Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(一)Widget,Flutter,flutter,學(xué)習(xí)

1.7??在 widget 樹(shù)中獲取State對(duì)象

在子 widget 樹(shù)中獲取父級(jí) StatefulWidget 的State 對(duì)象的兩種方法:

  1. 通過(guò)Context獲?。?code>context對(duì)象有一個(gè)findAncestorStateOfType()方法,該方法可以從當(dāng)前節(jié)點(diǎn)沿著 widget 樹(shù)向上查找指定類(lèi)型的 StatefulWidget 對(duì)應(yīng)的 State 對(duì)象。
  2. 通過(guò)GlobalKey獲取:GlobalKey 是 Flutter 提供的一種在整個(gè) App 中引用 element 的機(jī)制。如果一個(gè) widget 設(shè)置了GlobalKey,則可以通過(guò)globalKey.currentState來(lái)獲得該 widget 對(duì)應(yīng)的state對(duì)象。(開(kāi)銷(xiāo)大,不推薦這種方法)

1.7.1 通過(guò)Context獲取

通過(guò)Context獲取State 對(duì)象的兩種方法:

  1. 通過(guò)?context.findAncestorStateOfType?獲取 StatefulWidget 的狀態(tài)的方法是通用的。
  2. 但如果 StatefulWidget 的狀態(tài)是公共的(希望暴露出的),F(xiàn)lutter SDK默認(rèn)在 StatefulWidget 中提供一個(gè)of?靜態(tài)方法來(lái)供開(kāi)發(fā)者獲取其 State 對(duì)象。開(kāi)發(fā)者在自定義StatefulWidget 時(shí)也應(yīng)遵守這一規(guī)則。
//  Scaffold組件對(duì)應(yīng)的狀態(tài)類(lèi)ScaffoldState中定義了打開(kāi) SnackBar(路由頁(yè)底部提示條)的方法
//  下面是實(shí)現(xiàn)打開(kāi) SnackBar 的示例:

/*
   1.通過(guò)context.findAncestorStateOfType獲取ScaffoldState
*/
class GetStateObjectRoute extends StatefulWidget {
  const GetStateObjectRoute({Key? key}) : super(key: key);

  @override
  State<GetStateObjectRoute> createState() => _GetStateObjectRouteState();
}

class _GetStateObjectRouteState extends State<GetStateObjectRoute> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("子樹(shù)中獲取State對(duì)象"),
      ),
      body: Center(
        child: Column(
          children: [
            Builder(builder: (context) {
              return ElevatedButton(
                onPressed: () {
                  // 查找父級(jí)最近的Scaffold對(duì)應(yīng)的ScaffoldState對(duì)象
                  ScaffoldState _state = context.findAncestorStateOfType<ScaffoldState>()!;
                  // 打開(kāi)抽屜菜單
                  _state.openDrawer();
                },
                child: Text('打開(kāi)抽屜菜單1'),
              );
            }),
          ],
        ),
      ),
      drawer: Drawer(),
    );
  }
}


/*
  2.通過(guò)of靜態(tài)方法來(lái)獲取ScaffoldState
*/

Builder(builder: (context) {
  return ElevatedButton(
    onPressed: () {
      // 直接通過(guò)of靜態(tài)方法來(lái)獲取ScaffoldState
      ScaffoldState _state=Scaffold.of(context);
      // 打開(kāi)抽屜菜單
      _state.openDrawer();
    },
    child: Text('打開(kāi)抽屜菜單2'),
  );
}),


/*
  顯示 snack bar 的代碼
*/
Builder(builder: (context) {
  return ElevatedButton(
    onPressed: () {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("我是SnackBar")),
      );
    },
    child: Text('顯示SnackBar'),
  );
}),

1.7.2 通過(guò)GlobalKey獲取

如果一個(gè) widget 設(shè)置了GlobalKey,則:

  • 可以通過(guò)globalKey.currentWidget獲得該 widget 對(duì)象
  • 可以通過(guò)globalKey.currentElement來(lái)獲得 widget 對(duì)應(yīng)的element對(duì)象
  • 可以通過(guò)globalKey.currentState來(lái)獲得該 widget 對(duì)應(yīng)的state對(duì)象

注意事項(xiàng):

  1. 使用 GlobalKey 開(kāi)銷(xiāo)較大,如果有其他可選方案,應(yīng)盡量避免使用它。
  2. 同一個(gè) GlobalKey 在整個(gè) widget 樹(shù)中必須是唯一的,不能重復(fù)。?
/*
  Flutter還有一種通用的獲取State對(duì)象的方法——通過(guò)GlobalKey來(lái)獲??! 步驟分兩步:
*/

/*
  1.給目標(biāo)StatefulWidget添加GlobalKey。
*/
//定義一個(gè)globalKey, 由于GlobalKey要保持全局唯一性,我們使用靜態(tài)變量存儲(chǔ)
static GlobalKey<ScaffoldState> _globalKey= GlobalKey();
...
Scaffold(
    key: _globalKey , //設(shè)置key
    ...  
)

/*
  2.通過(guò)GlobalKey來(lái)獲取State對(duì)象
*/
_globalKey.currentState.openDrawer()

1.8?通過(guò) RenderObject 自定義 Widget

  • Flutter 最原始的定義組件的方式是通過(guò)定義RenderObject 來(lái)實(shí)現(xiàn)的。
  • StatelessWidget?和?StatefulWidget?本身沒(méi)有對(duì)應(yīng)的 RenderObject,它們是用于組合其他組件的,F(xiàn)lutter 組件庫(kù)中的很多基礎(chǔ)組件都不是通過(guò)它們來(lái)實(shí)現(xiàn)的。
  • 就好比搭積木,StatelessWidget 和?StatefulWidget?可以將積木搭成不同的樣子,但前提是得有積木,而這些積木都是通過(guò)自定義 RenderObject 來(lái)實(shí)現(xiàn)的,比如 Text 、Column、Align等。

通過(guò)RenderObject定義組件的方式:

  • 如果自定義的 widget 不會(huì)包含子組件,可以直接繼承LeafRenderObjectWidget
  • 如果自定義的 widget 可以包含子組件,則可以根據(jù)子組件的數(shù)量來(lái)選擇繼承SingleChildRenderObjectWidget 或 MultiChildRenderObjectWidget
  • 它們都繼承自RenderObjectWidget
  • 它們都實(shí)現(xiàn)了createElement() 方法,返回不同類(lèi)型的 Element 對(duì)象
  • createRenderObject 方法被組件對(duì)應(yīng)的 Element 調(diào)用(構(gòu)建渲染樹(shù)時(shí))用于生成渲染對(duì)象。
  • updateRenderObject 方法是用于在組件樹(shù)狀態(tài)發(fā)生變化但不需要重新創(chuàng)建 RenderObject 時(shí)用于更新組件渲染對(duì)象的回調(diào)。
/*
    自定義Widget 繼承 葉渲染器Widget
*/
class CustomWidget extends LeafRenderObjectWidget{
  @override
  RenderObject createRenderObject(BuildContext context) {
    // 創(chuàng)建 RenderObject
    return RenderCustomObject();
  }
  @override
  void updateRenderObject(BuildContext context, RenderCustomObject  renderObject) {
    // 更新 RenderObject
    super.updateRenderObject(context, renderObject);
  }
}

/*
  自定義RenderObject,繼承自 RenderBox,RenderBox 繼承自 RenderObject,
  需要在 RenderCustomObject 中實(shí)現(xiàn)布局、繪制、事件響應(yīng)等邏輯
*/
class RenderCustomObject extends RenderBox{

  @override
  void performLayout() {
    // 實(shí)現(xiàn)布局邏輯
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    // 實(shí)現(xiàn)繪制
  }
}

/*
  如果組件不會(huì)包含子組件,可以直接繼承自 LeafRenderObjectWidget ,
  它是 RenderObjectWidget 的子類(lèi),而 RenderObjectWidget 繼承自 Widget, 
  LeafRenderObjectWidget 的實(shí)現(xiàn)如下:
*/
abstract class LeafRenderObjectWidget extends RenderObjectWidget {
  const LeafRenderObjectWidget({ Key? key }) : super(key: key);

  @override
  LeafRenderObjectElement createElement() => LeafRenderObjectElement(this);
}

1.9?Flutter SDK內(nèi)置組件庫(kù)介紹

Flutter 提供了一套豐富、強(qiáng)大的基礎(chǔ)組件庫(kù),在基礎(chǔ)組件庫(kù)之上 Flutter 又提供了:

  • 一套 Material 風(fēng)格( Android 默認(rèn)的視覺(jué)風(fēng)格)的組件庫(kù)
  • 一套 Cupertino 風(fēng)格(iOS視覺(jué)風(fēng)格)的組件庫(kù)

1.9.1?基礎(chǔ)組件

?要使用基礎(chǔ)組件,需要先導(dǎo)入:

import 'package:flutter/widgets.dart';

常用的基礎(chǔ)組件:

  • Text?(opens new window):該組件可讓您創(chuàng)建一個(gè)帶格式的文本。
  • Row?(opens new window)、?Column?(opens new window): 這些具有彈性空間的布局類(lèi) widget 可讓您在水平(Row)和垂直(Column)方向上創(chuàng)建靈活的布局。其設(shè)計(jì)是基于 Web 開(kāi)發(fā)中的 Flexbox 布局模型。
  • Stack?(opens new window): 取代線性布局 (和 Android 中的FrameLayout相似),[Stack](https://docs.flutter.dev/flutter/ widgets/Stack-class.html)允許子 widget 堆疊, 你可以使用?Positioned?(opens new window)來(lái)定位他們相對(duì)于Stack的上下左右四條邊的位置。Stacks是基于Web開(kāi)發(fā)中的絕對(duì)定位(absolute positioning )布局模型設(shè)計(jì)的。
  • Container?(opens new window):?Container?(opens new window)可讓您創(chuàng)建矩形視覺(jué)元素。Container 可以裝飾一個(gè)BoxDecoration?(opens new window), 如 background、一個(gè)邊框、或者一個(gè)陰影。?Container?(opens new window)也可以具有邊距(margins)、填充(padding)和應(yīng)用于其大小的約束(constraints)。另外,?Container?(opens new window)可以使用矩陣在三維空間中對(duì)其進(jìn)行變換。

1.9.2 Material組件

?要使用Material組件,需要先導(dǎo)入:

import 'package:flutter/material.dart';
  • Flutter 提供了一套豐富 的Material 組件,它可以幫助我們構(gòu)建遵循 Material Design 設(shè)計(jì)規(guī)范的應(yīng)用程序。
  • Material 應(yīng)用程序以MaterialApp?(opens new window)?組件開(kāi)始, 該組件在應(yīng)用程序的根部創(chuàng)建了一些必要的組件,比如Theme、Scaffold、AppBar、TextButton等。
  • Material 組件庫(kù)中有一些組件可以根據(jù)實(shí)際運(yùn)行平臺(tái)來(lái)切換表現(xiàn)風(fēng)格,比如MaterialPageRoute,在路由切換時(shí),如果是 Android 系統(tǒng),它將會(huì)使用 Android 系統(tǒng)默認(rèn)的頁(yè)面切換動(dòng)畫(huà)(從底向上);如果是 iOS 系統(tǒng),它會(huì)使用 iOS 系統(tǒng)默認(rèn)的頁(yè)面切換動(dòng)畫(huà)(從右向左)。

1.9.3 ?Cupertino組件

?要使用Cupertino組件,需要先導(dǎo)入:

import 'package:flutter/cupertino.dart';

Flutter 也提供了一套豐富的 Cupertino 風(fēng)格的組件,盡管目前還沒(méi)有 Material 組件那么豐富,但是它仍在不斷的完善中。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-586928.html

/*
  一個(gè)簡(jiǎn)單的 Cupertino 組件風(fēng)格的頁(yè)面
*/

//導(dǎo)入cupertino  widget 庫(kù)
import 'package:flutter/cupertino.dart';

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

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: const CupertinoNavigationBar(
        middle: Text("Cupertino Demo"),
      ),
      child: Center(
        child: CupertinoButton(
            color: CupertinoColors.activeBlue,
            child: const Text("Press"),
            onPressed: () {}
        ),
      ),
    );
  }
}

1.10 總結(jié)

  • Flutter 的 widget 類(lèi)型分為StatefulWidget?和?StatelessWidget?兩種,widget 是構(gòu)建Flutter應(yīng)用的基石。
  • Flutter 提供了豐富的組件,在實(shí)際的開(kāi)發(fā)中可以根據(jù)需要隨意使用它們,而不必?fù)?dān)心引入過(guò)多組件庫(kù)會(huì)讓?xiě)?yīng)用安裝包變大,這不是 web 開(kāi)發(fā),dart 在編譯時(shí)只會(huì)編譯你使用了的代碼。
  • 由于 Material 和 Cupertino 都是在基礎(chǔ)組件庫(kù)之上的,所以如果我們的應(yīng)用中引入了這兩者之一,則不需要再引入flutter/ widgets.dart了,因?yàn)樗鼈儍?nèi)部已經(jīng)引入過(guò)了。

到了這里,關(guān)于Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(一)Widget的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • flutter開(kāi)發(fā)實(shí)戰(zhàn)-BackdropFilter高斯模糊子Widget控件

    flutter開(kāi)發(fā)實(shí)戰(zhàn)-BackdropFilter高斯模糊子Widget。 最近開(kāi)發(fā)過(guò)程中遇到需要將控件進(jìn)行模糊,比如iOS的effect的模糊效果。那在flutter中就需要用到了BackdropFilter BackdropFilter屬性定義 其中ImageFilter的filter是必須傳的,child為子控件。 ImageFilter一下兩種兩種構(gòu)造方法 設(shè)置背景高斯模糊

    2024年02月14日
    瀏覽(21)
  • flutter開(kāi)發(fā)實(shí)戰(zhàn)-自定義Switch開(kāi)關(guān)控件Widget

    flutter開(kāi)發(fā)實(shí)戰(zhàn)-自定義Switch開(kāi)關(guān)控件Widget

    flutter開(kāi)發(fā)實(shí)戰(zhàn)-自定義Switch開(kāi)關(guān)控件 在flutter中實(shí)現(xiàn)自定義Switch,主要實(shí)現(xiàn)類(lèi)似IOS的UISwitch樣式的開(kāi)關(guān)控件 實(shí)現(xiàn)自定義Switch的Widget,主要實(shí)現(xiàn)交織動(dòng)畫(huà)。 交織動(dòng)畫(huà) 有些時(shí)候我們可能會(huì)需要一些復(fù)雜的動(dòng)畫(huà),這些動(dòng)畫(huà)可能由一個(gè)動(dòng)畫(huà)序列或重疊的動(dòng)畫(huà)組成。一個(gè)動(dòng)畫(huà)組合在不同

    2024年02月13日
    瀏覽(27)
  • Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(六)調(diào)試Flutter應(yīng)用

    Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(六)調(diào)試Flutter應(yīng)用

    目錄 0 引言 1 調(diào)試Flutter應(yīng)用 1.1?日志與斷點(diǎn) 1.1.1?debugger()?聲明 1.1.2?print和debugPrint 1.1.3 調(diào)試模式、中間模式、發(fā)布模式 1.1.4?斷點(diǎn) 1.2?調(diào)試應(yīng)用程序?qū)?1.2.1?轉(zhuǎn)儲(chǔ)Widgets樹(shù) 1.2.2??轉(zhuǎn)儲(chǔ)渲染樹(shù) 1.2.3 轉(zhuǎn)儲(chǔ)Layer樹(shù) 1.2.4 轉(zhuǎn)儲(chǔ)語(yǔ)義樹(shù) 1.2.5?調(diào)度(打印幀的開(kāi)始和結(jié)束) 1.2.6 可視化調(diào)試

    2024年02月12日
    瀏覽(27)
  • Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(四)包管理

    Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(四)包管理

    目錄 0 引言 1?包管理 1.1 簡(jiǎn)介 1.2?Pub倉(cāng)庫(kù) 1.3 依賴(lài)Pub倉(cāng)庫(kù) 1.3.1 查找包 ?1.3.2 添加包 1.3.3 下載包 1.3.4 引入包 ?1.3.5 使用包 1.4?其他依賴(lài)方式 1.4.1?依賴(lài)本地包 1.4.2?依賴(lài)git倉(cāng)庫(kù) 1.4.3?不常用的依賴(lài)方式 本文是對(duì)第二版序 | 《Flutter實(shí)戰(zhàn)·第二版》 (flutterchina.club)的學(xué)習(xí)和總結(jié)。 在

    2024年02月12日
    瀏覽(26)
  • Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(三)路由管理

    目錄 0 引言 1?路由管理 ?1.1?MaterialPageRoute 1.2?Navigator ?1.2.1 Future push(BuildContext context, Route route) 1.2.2? bool pop(BuildContext context, [ result ]) 1.2.3??Future pushNamed(BuildContext context, String routeName,{Object arguments}) 1.3 非命名路由傳值 1.4?命名路由 ?1.4.1?路由表 1.4.2?注冊(cè)路由表 1.4.3?通過(guò)

    2024年02月09日
    瀏覽(26)
  • Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(五)資源管理

    Flutter學(xué)習(xí)四:Flutter開(kāi)發(fā)基礎(chǔ)(五)資源管理

    目錄 0 引言 1?資源管理 1.1?指定 assets 1.2?Asset 變體(variant) 1.3?加載 assets 1.3.1??加載文本 1.3.2 加載圖片 1.3.2.1 聲明分辨率相關(guān)的圖片 1.3.2.2 加載圖片 1.3.3?依賴(lài)包中的資源圖片 ?1.3.4?打包包中的 assets 1.3.5??特定平臺(tái) assets? 1.3.5.1 設(shè)置APP圖標(biāo) ?1.3.5.2?更新啟動(dòng)頁(yè) 1.4?平臺(tái)

    2024年02月11日
    瀏覽(51)
  • flutter筆記-萬(wàn)物皆是widget

    flutter筆記-萬(wàn)物皆是widget

    這篇文章后就不見(jiàn)寫(xiě)了,學(xué)flutter主要是為了更好的使用 flutter-webrtc,所以到這里基本就了解了大部分的知識(shí),后續(xù)邊用邊查; 在flutter中所有的view都叫widget,類(lèi)似文本組件Text也是集成自widget; 創(chuàng)建第一個(gè)項(xiàng)目如下: runApp傳入的參數(shù)就是一個(gè)Widget;所以我們可以傳入Text,示例

    2024年04月28日
    瀏覽(17)
  • Flutter Widget 生命周期 & key探究

    Flutter Widget 生命周期 & key探究

    在Flutter中,一切皆是Widget(組件),Widget的功能是“描述一個(gè)UI元素的配置數(shù)據(jù)”,它就是說(shuō),Widget其實(shí)并不是表示最終繪制在設(shè)備屏幕上的顯示元素,它只是描述顯示元素的一個(gè)配置數(shù)據(jù)。 實(shí)際上,F(xiàn)lutter中真正代表屏幕上顯示元素的類(lèi)是 Element,也就是說(shuō)Widget 只是描述

    2024年02月08日
    瀏覽(25)
  • Flutter通過(guò)flutter_unity_widget嵌入U(xiǎn)nity3D

    Flutter通過(guò)flutter_unity_widget嵌入U(xiǎn)nity3D

    實(shí)現(xiàn)方案:采用flutter開(kāi)源組件flutter_unity_widget 1、創(chuàng)建flutter項(xiàng)目flutter_unity_demo 2、在pubspec.paml文件dependencies添加flutter_unity_widget: ^2022.2.0,執(zhí)行Pub?get導(dǎo)入組件 3、在工程目錄下創(chuàng)建unity文件夾 4、在unity目錄下創(chuàng)建unity_demo的3D工程 5、下載flutter_unity_widget提供的unity插件 在unity_d

    2024年02月11日
    瀏覽(26)
  • 【Flutter 工程】005-代碼分離實(shí)踐:flutter_hooks & functional_widget

    【Flutter 工程】005-代碼分離實(shí)踐:flutter_hooks & functional_widget

    在Flutter開(kāi)發(fā)中,“嵌套地獄”(Nesting Hell)是指在構(gòu)建復(fù)雜的UI布局時(shí),由于多層嵌套的組件結(jié)構(gòu),代碼變得冗長(zhǎng)、難以維護(hù)和理解的情況。 Flutter使用組件樹(shù)的方式來(lái)構(gòu)建用戶界面,每個(gè)UI元素都是一個(gè)組件,可以包含其他組件。在某些情況下,特別是當(dāng)需要實(shí)現(xiàn)復(fù)雜的布局

    2024年02月06日
    瀏覽(25)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包