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

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key

這篇具有很好參考價(jià)值的文章主要介紹了Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、Android界面渲染流程UI樹與FlutterUI樹的設(shè)計(jì)思路對(duì)比

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

二、Widget組件生命周期詳解

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

1、Widget組件生命周期

和其他的視圖框架比如android的Activity一樣,flutter中的視圖Widget也存在生命周期,生命周期的回調(diào)函數(shù)體現(xiàn)在了State上面。組件State的生命周期整理如下圖所示:

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

createState:

當(dāng)一個(gè)StatefulWidget插入到渲染樹結(jié)構(gòu)、或者從渲染樹結(jié)構(gòu)移除時(shí),都會(huì)調(diào)用StatefulWidget.createState方法,從而達(dá)到更新UI的效果;

initState:

initState是StatefulWidget創(chuàng)建后調(diào)用的第一個(gè)方法,而且只執(zhí)行一次。在執(zhí)行initState時(shí),View沒(méi)有渲染,但是StatefulWidget 已經(jīng)被加載到渲染樹里了;

didChangeDependencies:

didChangeDependencies會(huì)在initState后立即調(diào)用,當(dāng)StatefulWidget依賴的InheritedWidget發(fā)生變化之后,didChangeDependencies會(huì)調(diào)用,所以didChangeDependencies可以調(diào)用多次;

build:

build方法會(huì)在didChangeDeoendencies之后立即調(diào)用,在之后setState()刷新時(shí),會(huì)重新調(diào)用build繪制頁(yè)面,所以build方法可以調(diào)用多次。一般不在build中創(chuàng)建除了創(chuàng)建Widget的方法,否則會(huì)影響渲染效率。

setState:

[State] 對(duì)象可以通過(guò)調(diào)用它們的 [setState]方法自發(fā)地請(qǐng)求重建其子樹,這表明它們的某些內(nèi)部狀態(tài)已經(jīng)改變,可能會(huì)影響該子樹中的用戶界面,setState方法會(huì)被多次調(diào)用。

didUpdateWidget:

1、當(dāng)調(diào)用setState更新UI的時(shí)候,都會(huì)調(diào)用didUpdateWidget;

2、框架在調(diào)用[didUpdateWidget]之后總是調(diào)用[build],在[didUpdateWidget]中對(duì)[setState]的任何調(diào)用都是多余的。

deactivate:

1、當(dāng)框架從樹中移除此 State 對(duì)象時(shí)將會(huì)調(diào)用此方法;

2、在某些情況下,框架將重新插入State 對(duì)象到樹的其他位置(例如,如果包含該樹的子樹State 對(duì)象從樹中的一個(gè)位置移植到另一位置),框架將會(huì)調(diào)用 build 方法來(lái)提供 State 對(duì)象適應(yīng)其在樹中的新位置。

dispose:

當(dāng)框架從樹中永久移除此 State對(duì)象時(shí)將會(huì)調(diào)用此方法,與deactivate的區(qū)別是,deactivate 還可以重新插入到樹中,而 dispose 表示此 State對(duì)象永遠(yuǎn)不會(huì)在 build。調(diào)用完 dispose后,mounted 屬性被設(shè)置為false,也代表組件生命周期的結(jié)束,此時(shí)再調(diào)用setState方法將會(huì)拋出異常。子類重寫此方法,釋放相關(guān)資源,比如動(dòng)畫等。

2、生命周期調(diào)用

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

A Page:
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/DemoPages.dart';


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

class MyApp extends StatelessWidget {
  const MyApp({super.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 Demo(),
    );
  }
}


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

  @override
  State<Demo> createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    print("------main--------build");
    return Scaffold(
      appBar: AppBar(

        title: const Text("StatefulWidget key"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: (){
                Navigator.of(context).push(
                    MaterialPageRoute(builder:(setting){
                      return const DemoPage();
                    }
                  )
                );
              },
              child: const Text("頁(yè)面跳轉(zhuǎn)"),
            ),

          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          setState(() {
            print("調(diào)用....");
          });
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print("------main--------initState");
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print("-------main-------didChangeDependencies");
  }

  @override
  void setState(VoidCallback fn) {
    // TODO: implement setState
    super.setState(fn);
    print("------main--------setState");
  }

  @override
  void deactivate() {
    // TODO: implement deactivate
    super.deactivate();
    print("------main--------deactivate");
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print("------main--------dispose");
  }
}
B Page:

import 'package:flutter/material.dart';


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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Demo頁(yè)面"),
      ),
      body: const DemoWidget(),
    );
  }
}

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

  @override
  State<DemoWidget> createState() => _DemoWidgetState();
}

class _DemoWidgetState extends State<DemoWidget> {


  String btnText = "test";


  @override
  Widget build(BuildContext context) {
    print("------_DemoWidgetState--------build");
    return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
              onPressed: (){
                setState(() {
                  if(btnText == "test"){
                    btnText = "測(cè)試";
                  }else{
                    btnText = "test";
                  }
                });
              },
              child: Text(btnText),
            ),
            ElevatedButton(
              onPressed: (){
                print("返回......");
                Navigator.of(context).pop();
              },
              child: const Text("返回"),
            ),
          ],
        ),
    );
  }
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print("------_DemoWidgetState--------initState");
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print("-------_DemoWidgetState-------didChangeDependencies");
  }

  @override
  void setState(VoidCallback fn) {
    // TODO: implement setState
    super.setState(fn);
    print("------_DemoWidgetState--------setState");
  }

  @override
  void deactivate() {
    // TODO: implement deactivate
    super.deactivate();
    print("------_DemoWidgetState--------deactivate");
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print("-----_DemoWidgetState---------dispose");
  }
}

三、頁(yè)面間數(shù)據(jù)傳遞(共享)的幾種常用方式

公共頁(yè)面:

import 'package:flutter/material.dart';
import 'transfer_constructor_page.dart';
import 'transfer_data_entity.dart';
import 'transfer_data_inherited.dart';
import 'transfer_data_singleton.dart';
import 'transfer_router_page.dart';
import 'transfer_singleton_page.dart';
import 'transfer_stream_singleton.dart';
import 'transfer_stream_singleton_page.dart';

import 'inherited_data_provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  var params = TransferDataEntity(name:"王五", id:"009", age:16);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Data Transfer Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(title: 'Data Transfer Demo'),
    );
  }
}

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

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var data = TransferDataEntity(name:"張三豐", id:"001", age:18);
  List<String> itemNames = [
    "構(gòu)造器傳遞數(shù)據(jù)",
    "返回上個(gè)頁(yè)面時(shí)攜帶參數(shù)",
    "InheritedWidget方式",
    "Singleton方式",
    "Singleton結(jié)合Stream",
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          Container(
              alignment: Alignment.center,
              height: 60.0,
              color: Colors.black12,
              child: Text("${data.id},${data.name},${data.age}")),
          Expanded(
            child: ListView.separated(
              separatorBuilder: (BuildContext contex, int index) {
                return const Divider(
                  color: Colors.black12,
                  height: 0.5,
                );
              },
              itemBuilder: (BuildContext context, int index) {
                return InkWell(
                  onTap: () => _onClick(index, data, context),
                  child: Container(
                    alignment: Alignment.center,
                    height: 48.0,
                    width: double.infinity,
                    child:  Text(
                      itemNames[index],
                      style: const TextStyle(
                        color: Colors.black,
                        fontWeight: FontWeight.bold,
                        fontSize: 14.0,
                      ),
                    ),
                  ),
                );
              },
              itemCount: itemNames.length,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  _onClick(int index, TransferDataEntity data, BuildContext context) {
    switch (index) {
      case 0:
        _transferDataByConstructor(context, data);
        break;
      case 1:
        _toTransferForResult(context, data);
        break;

      case 2:
        _inheritedToPage(context, data);
        break;
      case 3:
        _singletonDataTransfer(context);
        break;
      case 4:
        _streamDataTransfer(context);
        break;

    }
  }

  //通過(guò)構(gòu)造器方法傳遞數(shù)據(jù)
  _transferDataByConstructor(BuildContext context, TransferDataEntity data) {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => DataTransferByConstructorPage(data: data)));
  }

  _toTransferForResult(BuildContext context, TransferDataEntity data) async {
    final dataFromOtherPage = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => TransferRouterPage(data: data)),
    ) as TransferDataEntity;

   setState(() {
     data.name = dataFromOtherPage.name;
     data.id = dataFromOtherPage.id;
     data.age = dataFromOtherPage.age;
   });
  }

  _inheritedToPage(BuildContext context, TransferDataEntity data) {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => IDataProvider(
                  data: data,
                  child: IDataWidget(),
                )));
  }


  _singletonDataTransfer(BuildContext context) {
    var transferData = TransferDataEntity(name:"三喵2", id:"002", age:20);
    transSingletonData.transData = transferData;
    Navigator.push(context,
        MaterialPageRoute(builder: (context) => TransferSingletonPage()));
  }


  _streamDataTransfer(BuildContext context) {
    var transferData = TransferDataEntity(name:"三喵", id:"005", age:20);
    streamSingletonData.setTransferData(transferData);
    Navigator.push(context,
        MaterialPageRoute(builder: (context) => TransferStreamPage()));
  }
}

1、通過(guò)構(gòu)造器(constructor)傳遞數(shù)據(jù)

通過(guò)構(gòu)造器傳遞數(shù)據(jù)是一種最簡(jiǎn)單的方式,也是最常用的方式,在第一個(gè)頁(yè)面,我們模擬創(chuàng)建一個(gè)我們需要傳遞數(shù)據(jù)的對(duì)象。當(dāng)點(diǎn)擊跳轉(zhuǎn)的時(shí)候,我們把數(shù)據(jù)傳遞DataTransferByConstructorPage頁(yè)面,并把攜帶過(guò)來(lái)的數(shù)據(jù)展示到頁(yè)面上。

1)創(chuàng)建一個(gè)傳遞數(shù)據(jù)對(duì)象 :final data=TransferDataEntity("001","張三豐",18);

2)定義一個(gè)跳轉(zhuǎn)到DataTransferByConstructorPage頁(yè)面的方法:

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

3)在DataTransferByConstructorPage頁(yè)面接收到數(shù)據(jù)并展示出來(lái):

import 'package:flutter/material.dart';
import 'transfer_data_entity.dart';

///通過(guò)構(gòu)造器的方式傳遞參數(shù)
class DataTransferByConstructorPage extends StatelessWidget {
  final TransferDataEntity data;

  const DataTransferByConstructorPage({super.key, required this.data});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("構(gòu)造器方式"),
      ),
      body: Column(
        children: <Widget>[
          Container(
            width: double.infinity,
            height: 40.0,
            alignment: Alignment.center,
            child: Text(data.id),
          ),
          Container(
            width: double.infinity,
            height: 40.0,
            alignment: Alignment.center,
            child: Text(data.name),
          ),
          Container(
            width: double.infinity,
            height: 40.0,
            alignment: Alignment.center,
            child: Text("${data.age}"),
          )
        ],
      ),
    );
  }
}

2、當(dāng)一個(gè)頁(yè)面關(guān)閉時(shí)攜帶數(shù)據(jù)到上一個(gè)頁(yè)面(Navigator.pop)

在Android開(kāi)發(fā)中我們需要將數(shù)據(jù)傳遞給上一個(gè)頁(yè)面通常使用的傳統(tǒng)方式是startActivityForResult()方法。但是在flutter就不用這么麻煩了。只需要使用Navigator.pop方法即可將數(shù)據(jù)結(jié)果帶回去。但是我們跳轉(zhuǎn)的時(shí)候需要注意兩點(diǎn):

1)我們需要定義一個(gè)異步方法用于接收返回來(lái)的結(jié)果:

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

2)在我們要關(guān)閉的頁(yè)面使用Navigator.pop 返回第一個(gè)頁(yè)面:

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

import 'package:flutter/material.dart';
import 'transfer_data_entity.dart';

class TransferRouterPage extends StatelessWidget {
  final TransferDataEntity data;

  const TransferRouterPage({super.key, required this.data});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("返回上個(gè)頁(yè)面?zhèn)鬟f參數(shù)"),
        leading: Builder(builder: (BuildContext context) {
          return IconButton(
              icon: const Icon(Icons.arrow_back_ios),
              onPressed: () {
                _backToData(context);
              });
        }),
      ),
      body: Column(
        children: <Widget>[
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text(data.name),
          ),
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text(data.id),
          ),
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text("${data.age}"),
          ),
          ElevatedButton(
              onPressed: () {
                _backToData(context);
              },
              child: const Text("點(diǎn)我返回上一個(gè)頁(yè)面并把數(shù)據(jù)傳回去"))
        ],
      ),
    );
  }

  //返回并攜帶數(shù)據(jù)
  _backToData(BuildContext context) {
    var transferData = TransferDataEntity(name: "嘻嘻哈哈", id: "007", age: 20);
    Navigator.pop(context, transferData);
  }
}

3、InheritedWidget方式?

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

使用lnheritedWidget方式如下幾步:

1)繼承l(wèi)nheritedWidget提供一個(gè)數(shù)據(jù)源:

import 'package:flutter/material.dart';
import 'transfer_data_entity.dart';

//所有的子組件共享數(shù)據(jù)
class IDataProvider extends InheritedWidget {

  final TransferDataEntity data;

  const IDataProvider({super.key, required super.child, required this.data});


  @override
  bool updateShouldNotify(IDataProvider oldWidget) {
    return data != oldWidget.data;
  }

  //版本問(wèn)題
  //InheritedWidget
  static IDataProvider? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<IDataProvider>();
  }

// static _InheritedProviders of(BuildContext context) {
//   final widget = context.inheritFromWidgetOfExactType(_InheritedProviders);
//   return widget is _InheritedProviders ? widget : null;
// }

}

2)定義頁(yè)面跳轉(zhuǎn)時(shí)候攜帶數(shù)據(jù)的方法:

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

3)跳轉(zhuǎn)的到的頁(yè)面并展示數(shù)據(jù)代碼如下:

import 'package:flutter/material.dart';

import 'inherited_data_provider.dart';

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

  @override
  Widget build(BuildContext context) {
    final data = IDataProvider.of(context)!.data;

    return Scaffold(
      appBar: AppBar(
        title: const Text("Inherited方式傳遞數(shù)據(jù)"),
      ),
      body: Column(
        children: <Widget>[
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text(data.name),
          ),
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text(data.id),
          ),
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text("${data.age}"),
          ),
          const IDataChildWidget()
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final data = IDataProvider.of(context)!.data;
    return Text(data.name);
  }
}

4、全局的提供數(shù)據(jù)的方式

這種方式我們還是使用lnheritedWidget,區(qū)別就是我們不是跳轉(zhuǎn)的時(shí)候去創(chuàng)建IGenericDataProvider。而是把他放在最頂層注意:這種方式一定要把數(shù)據(jù)放在頂層;

1)定義頂部數(shù)據(jù):

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

2)接收數(shù)據(jù)的方式基本和 lnheritedWidget相同:

final data=IGenericDataProvider.of<TransferDataEntity>(context) 獲取數(shù)據(jù)

3)使用代碼:

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

5、通過(guò)全局單例模式來(lái)使用?

這種方式就是創(chuàng)建一個(gè)全局單例對(duì)象,任何地方都可以操控這個(gè)對(duì)象,存儲(chǔ)和取值都可以通過(guò)這個(gè)對(duì)象。

1)創(chuàng)建單例對(duì)象:

import 'transfer_data_entity.dart';

class TransferDataSingleton {
  static final TransferDataSingleton _instanceTransfer =
      TransferDataSingleton.__internal();

  TransferDataEntity? transData;

  factory TransferDataSingleton() {
    return _instanceTransfer;
  }

  TransferDataSingleton.__internal();
}

final transSingletonData = TransferDataSingleton();

?2)給單例對(duì)象存放數(shù)據(jù):

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

3)接收并使用傳遞的值:

import 'package:flutter/material.dart';
import 'transfer_data_singleton.dart';

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

  @override
  _TransferSingletonPageState createState() => _TransferSingletonPageState();
}

class _TransferSingletonPageState extends State<TransferSingletonPage> {
  @override
  Widget build(BuildContext context) {
    var data = transSingletonData.transData;
    return Scaffold(
      appBar: AppBar(
        title: const Text("全局單例傳遞數(shù)據(jù)"),
      ),
      body: Column(
        children: <Widget>[
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text(data!.name),
          ),
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text(data.id),
          ),
          Container(
            alignment: Alignment.center,
            height: 40.0,
            child: Text("${data.age}"),
          ),
        ],
      ),
    );
  }
}

6、全局單例結(jié)合Stream的方式傳遞數(shù)據(jù)

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

1)單例模式:

import 'dart:async';

import 'transfer_data_entity.dart';

class TransferStreamSingleton {
  static final TransferStreamSingleton _instanceTransfer =
      TransferStreamSingleton.__internal();
  StreamController? streamController;

  void setTransferData(TransferDataEntity transData) {
    streamController = StreamController<TransferDataEntity>();
    streamController!.sink.add(transData);
  }

  factory TransferStreamSingleton() {
    return _instanceTransfer;
  }

  TransferStreamSingleton.__internal();
}

final streamSingletonData = TransferStreamSingleton();

2)傳遞要攜帶的數(shù)據(jù):

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter3)接收要傳遞的值:

import 'dart:async';

import 'package:flutter/material.dart';
import 'transfer_data_entity.dart';
import 'transfer_stream_singleton.dart';

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

  @override
  _TransferStreamPageState createState() => _TransferStreamPageState();
}

class _TransferStreamPageState extends State<TransferStreamPage> {
  final StreamController? _streamController =
      streamSingletonData.streamController;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("全局單例結(jié)合Stream"),
        ),
        body: StreamBuilder(
            stream: _streamController!.stream,
            initialData: TransferDataEntity(),
            builder: (context, snapshot) {
              return Column(
                children: <Widget>[
                  Container(
                    alignment: Alignment.center,
                    height: 40.0,
                    child: Text(snapshot.data.name),
                  ),
                  Container(
                    alignment: Alignment.center,
                    height: 40.0,
                    child: Text(snapshot.data.id),
                  ),
                  Container(
                    alignment: Alignment.center,
                    height: 40.0,
                    child: Text("${snapshot.data.age}"),
                  ),
                ],
              );
            }));
  }

  @override
  void dispose() {
    _streamController?.close();
    super.dispose();
  }
}

四、Flutter Key

我們平時(shí)一定接觸過(guò)很多的Widget,比如 Container、Row、Column等,它們?cè)谖覀兝L制界面的過(guò)程中發(fā)揮著重要的作用。但是不知道你有沒(méi)有注意到,在幾乎每個(gè)Widget的構(gòu)造函數(shù)中,都有一個(gè)共同的參數(shù),它們通常在參數(shù)列表的第一個(gè),那就是Key。

在Flutter中,Key是不能重復(fù)使用的,所以Key一般用來(lái)做唯一標(biāo)識(shí)。組件在更新的時(shí)候,其狀態(tài)的保存主要是通過(guò)判斷組件的類型或者key值是否一致。因此,當(dāng)各組件的類型不同的時(shí)候,類型已經(jīng)足夠用來(lái)區(qū)分不同的組件了,此時(shí)我們可以不必使用key。但是如果同時(shí)存在多個(gè)同一類型的控件的時(shí)候,此時(shí)類型已經(jīng)無(wú)法作為區(qū)分的條件了,我們就需要使用到key。?

1、沒(méi)有Key 會(huì)發(fā)生什么現(xiàn)象:

如下面例:定義了一個(gè)StatefulWidget的Box,點(diǎn)擊Box的時(shí)候可以改變Box里面的數(shù)字,當(dāng)我們重新對(duì)Box排序的時(shí)候,F(xiàn)lutter就無(wú)法識(shí)別到Box的變化了,這是什么原因呢?

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

運(yùn)行后我們發(fā)現(xiàn)改變list Widget順序后,Widget顏色會(huì)變化,但是每個(gè)Widget里面的文本內(nèi)容并沒(méi)有變化,為什么會(huì)這樣呢?當(dāng)我們List重新排序后Flutter檢測(cè)到了Widget的順序變化,所以重新繪制List Widget,但是Flutter發(fā)現(xiàn)List Widget里面的元素沒(méi)有變化,所以就沒(méi)有改變Widget里面的內(nèi)容。

把List 里面的Box的顏色改成一樣,這個(gè)時(shí)候您重新對(duì)list進(jìn)行排序,就很容易理解了。重新排序后雖然 執(zhí)行了setState,但Flutter沒(méi)法通過(guò)Box里面?zhèn)魅氲膮?shù)是代碼和以前是一樣的,所以Flutter不會(huì)重構(gòu)List Widget里面的內(nèi)容,也就是來(lái)識(shí)別Box是否改變。如果要讓FLutter能識(shí)別到List Widget子元素的改變,就需要給每個(gè)Box指定一個(gè)key。?

實(shí)現(xiàn)代碼:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.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 MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  List<Widget> list = [
    // Center(
    //   child: Box(
    //     color: Colors.blue,
    //   ),
    // ),
    Box(
      color: Colors.blue,
    ),
    Box(
      color: Colors.red,
    ),
    Box(
      color: Colors.orange,
    )
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            list.shuffle(); //打亂list的順序
          });
        },
        child: const Icon(Icons.refresh),
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: list,
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  Color color;

  Box({super.key, required this.color});

  @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: Center(
          child: Text("$_count"),
        ),
      ),
    );
  }
}

2、LocalKey與GlobalKey

在Flutter中,Key是不能重復(fù)使用的,所以Key一般用來(lái)做唯一標(biāo)識(shí)。組件在更新的時(shí)候,其狀態(tài)的保存主要是通過(guò)判斷組件的類型或者key值是否一致。因此,當(dāng)各組件的類型不同的時(shí)候,類型已經(jīng)足夠用來(lái)區(qū)分不同的組件了,此時(shí)我們可以不必使用key。但是如果同時(shí)存在多個(gè)同一類型的控件的時(shí)候,此時(shí)類型已經(jīng)無(wú)法作為區(qū)分的條件了,我們就需要使用到key。

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter?

Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key,flutter,flutter

運(yùn)用key變更上面案例業(yè)務(wù):

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.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 MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  List<Widget> list = [
    Center(
      key: UniqueKey(),
      child: Box(
        color: Colors.blue,
      ),
    ),
    // Box(
    //   // key: const ValueKey("1"),//指定值
    //   color: Colors.blue,
    // ),
    Box(
      key: UniqueKey(), //唯一值, 自動(dòng)生成
      color: Colors.red,
    ),
    Box(
      key: const ObjectKey("2"), //類似于ValueKey
      // key: const ObjectKey(2),//類似于ValueKey
      color: Colors.orange,
    )
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            list.shuffle(); //打亂list的順序
          });
        },
        child: const Icon(Icons.refresh),
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: list,
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  Color color;

  Box({super.key, required this.color});

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

class _BoxState extends State<Box> {
  int _count = 0;

  _BoxState() {
    print("--------_BoxState----------構(gòu)造");
  }

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

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print("------_BoxState--------initState");
  }

  @override
  void didChangeDependencies() {
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
    print("-------_BoxState-------didChangeDependencies");
  }

  @override
  void setState(VoidCallback fn) {
    // TODO: implement setState
    super.setState(fn);
    print("------_BoxState--------setState");
  }

  @override
  void deactivate() {
    // TODO: implement deactivate
    super.deactivate();
    print("------_BoxState--------deactivate");
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print("------_BoxState--------dispose");
  }
}

3、GlobalKey的使用

如果把LocalKey比作局部變量,GlobalKey就類似于全局變量;

下面使用了LocalKey,當(dāng)屏幕狀態(tài)改變的時(shí)候把Colum換成了Row,Box的狀態(tài)就會(huì)丟失。一個(gè)Widget狀態(tài)的保存主要是通過(guò)判斷組件的類型或者key值是否一致。 LocalKey只在當(dāng)前的組件樹有效,所以把Colum換成了Row的時(shí)候Widget的狀態(tài)就丟失了。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.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 MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  List<Widget> list = [
    Box(
      key: const ValueKey(1), //int double string
      color: Colors.blue,
    ),
    Box(
      key: ObjectKey(Object()),
      color: Colors.red,
    ),
    Box(
      key: UniqueKey(), //程序自動(dòng)生成一個(gè)key
      color: Colors.orange,
    )
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            list.shuffle(); //打亂list的順序
          });
        },
        child: const Icon(Icons.refresh),
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: MediaQuery.of(context).orientation == Orientation.portrait
            ? Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: list,
              )
            : Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: list,
              ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  Color color;

  Box({super.key, required this.color});

  @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: Center(
          child: Text("$_count"),
        ),
      ),
    );
  }
}

為了解決這個(gè)問(wèn)題我們就可以使用GlobalKey。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.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 MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  // List<Widget> list = [
  //   Box(
  //     key: const ValueKey(1),
  //     color: Colors.blue,
  //   ),
  //   Box(
  //     key: ObjectKey(Box(color: Colors.red)),
  //     color: Colors.red,
  //   ),
  //   Box(
  //     key:UniqueKey(), //程序自動(dòng)生成一個(gè)key
  //     color: Colors.orange,
  //   )
  // ];
  List<Widget> list = [
    Box(
      key: GlobalKey(),
      color: Colors.blue,
    ),
    Box(
      key: GlobalKey(),
      color: Colors.red,
    ),
    Box(
      key: GlobalKey(), //程序自動(dòng)生成一個(gè)key
      color: Colors.orange,
    )
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            list.shuffle(); //打亂list的順序
          });
        },
        child: const Icon(Icons.refresh),
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: MediaQuery.of(context).orientation == Orientation.portrait
            ? Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: list,
              )
            : Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: list,
              ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  Color color;

  Box({super.key, required this.color});

  @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: Center(
          child: Text("$_count"),
        ),
      ),
    );
  }
}

4、GlobalKey 獲取子組件

globalKey.currentState 可以獲取子組件的狀態(tài),執(zhí)行子組件的方法,globalKey.currentWidget可以獲取子組件的屬性,_globalKey.currentContext!.findRenderObject()可以獲取渲染的屬性。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.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> {
  final GlobalKey _globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          //1、獲取子組件的狀態(tài) 調(diào)用子組件的屬性
          var state = (_globalKey.currentState as _BoxState);
          setState(() {
            state._count++;
          });

          //2、獲取子組件的屬性
          var box = (_globalKey.currentWidget as Box);
          print(box.color);

          //3、獲取子組件渲染的屬性
          var renderBox =
              (_globalKey.currentContext?.findRenderObject() as RenderBox);
          print(renderBox.size);
        },
      ),
      appBar: AppBar(
        title: const Text('Title'),
      ),
      body: Center(
        child: Box(
          key: _globalKey,
          color: Colors.red,
        ),
      ),
    );
  }
}

class Box extends StatefulWidget {
  final Color color;

  const Box({super.key, required this.color});

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

class _BoxState extends State<Box> {
  int _count = 0;

  run() {
    print("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: Center(
          child: Text("$_count"),
        ),
      ),
    );
  }
}

?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-744858.html

?

到了這里,關(guān)于Flutter 05 組件狀態(tài)、生命周期、數(shù)據(jù)傳遞(共享)、Key的文章就介紹完了。如果您還想了解更多內(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 Widget 生命周期 & key探究

    Flutter Widget 生命周期 & key探究

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

    2024年02月08日
    瀏覽(25)
  • MediaPlayer狀態(tài)圖及生命周期

    MediaPlayer狀態(tài)圖及生命周期

    MediaPlayer狀態(tài)圖及生命周期 MediaPlayer是Android中的uoge多媒體播放類,我們能通過(guò)它控制音視頻流或本地音視頻資源的播放過(guò)程。 這一片博客主要介紹MediaPlayer狀態(tài)圖及生命周期。先看一張官網(wǎng)很經(jīng)典的MediaPlayer狀態(tài)機(jī)的圖片。 其中橢圓代表MediaPlayer駐留狀態(tài),弧代表播放器控制

    2023年04月08日
    瀏覽(23)
  • K8s: 關(guān)于Kubernetes中的Pod的生命周期(狀態(tài))以及生命周期的鉤子函數(shù)處理

    pod 的生命周期 1 ) pod 幾種常用狀態(tài) 1.1 )Pending(掛起) Pod 已被 Kubernetes 系統(tǒng)接受,但有一個(gè)或者多個(gè)容器尚未創(chuàng)建亦未運(yùn)行 此階段包括等待 Pod 被調(diào)度的時(shí)間和通過(guò)網(wǎng)絡(luò)下載鏡像的時(shí)間。 1.2 )Running(運(yùn)行中) Pod 已經(jīng)綁定到了某個(gè)節(jié)點(diǎn),Pod 中所有的容器都已被創(chuàng)建 至少有

    2024年04月22日
    瀏覽(42)
  • HarmonyOS Stage模型 UIAbility生命周期狀態(tài)

    HarmonyOS Stage模型 UIAbility生命周期狀態(tài)

    UIAbility的生命周期包括Create、Foreground、Background、Destroy四個(gè)狀態(tài) Create 狀態(tài),在UIAbility實(shí)例 創(chuàng)建 時(shí)觸發(fā),對(duì)應(yīng)onCreate回調(diào)??梢栽趏nCreate回調(diào)中進(jìn)行相關(guān)初始化操作 Foreground 狀態(tài),在UIAbility 切換至前臺(tái) 時(shí)觸發(fā)。對(duì)應(yīng)onForeground回調(diào),在UIAbility的UI頁(yè)面可見(jiàn)之前,即UIAbility切換至

    2024年01月16日
    瀏覽(59)
  • Flutter中的AppLifecycleListener:應(yīng)用生命周期監(jiān)聽(tīng)器介紹及使用

    引言 當(dāng)你在Flutter中需要監(jiān)聽(tīng)?wèi)?yīng)用程序的生命周期變化時(shí),可以使用 AppLifecycleListener 。在Flutter 3.13中, AppLifecycleListener 被添加到Framework中,用于監(jiān)聽(tīng)?wèi)?yīng)用程序的生命周期變化,并響應(yīng)退出應(yīng)用程序的請(qǐng)求等支持。 在Flutter 3.13之前,我們通常使用 WidgetsBindingObserver 的 didChange

    2024年01月20日
    瀏覽(25)
  • Android Jetpack中Lifecycle使用生命周期感知型組件處理生命周期

    在使用Kotlin實(shí)現(xiàn)Android Jetpack中Lifecycle使用生命周期感知型組件處理生命周期的功能時(shí),你需要以下步驟: 首先,在app的build.gradle文件中添加Lifecycle相關(guān)庫(kù)的依賴項(xiàng): 然后,在你的Activity或Fragment中創(chuàng)建一個(gè)LifecycleObserver對(duì)象,并使用@OnLifecycleEvent注解來(lái)實(shí)現(xiàn)相應(yīng)的生命周期方法

    2024年01月21日
    瀏覽(29)
  • 【Jetpack】ViewModel 架構(gòu)組件 ( 視圖 View 和 數(shù)據(jù)模型 Model | ViewModel 作用 | ViewModel 生命周期 | 代碼示例 | 使用注意事項(xiàng) )

    【Jetpack】ViewModel 架構(gòu)組件 ( 視圖 View 和 數(shù)據(jù)模型 Model | ViewModel 作用 | ViewModel 生命周期 | 代碼示例 | 使用注意事項(xiàng) )

    Activity 遇到的問(wèn)題 : 瞬態(tài)數(shù)據(jù)丟失 : 操作 Activity 時(shí) , 如果 屏幕 自動(dòng)旋轉(zhuǎn) , 當(dāng)前 Activity 組件會(huì) 執(zhí)行銷毀操作 , 并重新創(chuàng)建新的 Activity 組件 , 該操作會(huì) 導(dǎo)致 Activity 的 瞬態(tài)數(shù)據(jù) 丟失 ; 內(nèi)存泄漏 : 在 系統(tǒng)組件 如 Activity 中 , 啟動(dòng)了一個(gè)線程 , 在線程中執(zhí)行一系列操作 , 如果 A

    2024年01月25日
    瀏覽(19)
  • 【React】組件生命周期、組件通信、setState

    【React】組件生命周期、組件通信、setState

    ? 組件化思想的應(yīng)用: ? ? 有了組件化的思想,我們?cè)谥蟮拈_(kāi)發(fā)中就要充分的利用它。 ? ? 盡可能的將頁(yè)面拆分成一個(gè)個(gè)小的、可復(fù)用的組件。 ? ? 這樣讓我們的代碼更加方便組織和管理,并且擴(kuò)展性也更強(qiáng)。 ? React的組件相對(duì)于Vue更加的靈活和多樣,按照不同的

    2024年01月20日
    瀏覽(22)
  • 小程序組件的生命周期

    小程序組件的生命周期

    組件的生命周期,指的是組件自身的一些函數(shù),這些函數(shù)在特殊的時(shí)間點(diǎn)或遇到一些特殊的框架事件時(shí)被自動(dòng)觸發(fā)。 其中,最重要的生命周期是 created attached detached ,包含一個(gè)組件實(shí)例生命流程的最主要時(shí)間點(diǎn)。 ? ? ? ? ?·組件實(shí)例剛剛被創(chuàng)建好時(shí), created 生命周期被觸發(fā)

    2023年04月15日
    瀏覽(23)
  • 學(xué)習(xí)Vue:組件生命周期

    在Vue.js中,組件的生命周期是指組件從創(chuàng)建到銷毀的整個(gè)過(guò)程,而生命周期鉤子函數(shù)則是在不同階段執(zhí)行的函數(shù),允許您在特定時(shí)間點(diǎn)添加自定義邏輯。本文將詳細(xì)介紹組件的生命周期以及常用的生命周期鉤子函數(shù)。 組件的生命周期可以分為以下幾個(gè)階段: 創(chuàng)建階段: 在這

    2024年02月12日
    瀏覽(26)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包