informasi kontak saya
Surat[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Daftar isi
1. Pentingnya penyegaran lokal
2. Beberapa cara untuk menerapkan penyegaran sebagian
1. Gunakan metode setState untuk penyegaran sebagian
2. Gunakan StatefulWidget dan InheritedWidget untuk menyegarkan sebagian UI
3.ValueNotifier dan ValueListenableBuilder
Di Flutter, manajemen status mengacu pada cara mengelola dan memperbarui status data dalam aplikasi, serta memperbarui UI sesuai dengan perubahan status. Manajemen status yang efektif dapat membantu pengembang menciptakan aplikasi yang lebih efisien dan mudah dipelihara.
setState adalah metode pengelolaan status paling dasar di Flutter. Saat status berubah, framework akan diberi tahu untuk membangun kembali UI. Tentu saja kita tahu bahwa ketika kita memanggil metode setState, halaman akan digambar ulang. Ketika tata letak halaman lebih kompleks, terkadang kita hanya perlu memperbarui UI terpisah. Saat ini, jika kita menggunakan metode setState, itu sudah cukup kinerja yang lebih besar. Gunakan untuk menggambar ulang UI halaman saat ini.
Jadi metode apa yang ada di Flutter untuk menyegarkan sebagian UI? Blog ini mencantumkan beberapa cara Flutter menerapkan penyegaran sebagian.
Penyegaran sebagian mengacu pada penyegaran hanya sebagian antarmuka, bukan keseluruhan halaman. Ini meningkatkan kinerja dan pengalaman pengguna.
setState adalah metode manajemen status yang paling umum digunakan di Flutter. Metode ini digunakan untuk memberi tahu framework tentang perubahan status, yang mengarah ke rekonstruksi antarmuka.
Saat kita membuat proyek Flutter, contoh timer yang dihasilkan oleh sistem secara default adalah contoh penyegaran parsial setState.
- import 'package:flutter/material.dart';
-
- class SetStateMainPage extends StatefulWidget {
- final String title;
- const SetStateMainPage({super.key, required this.title});
-
- @override
- State<SetStateMainPage> createState() => _SetStateMainPageMainPageState();
- }
-
- class _SetStateMainPageMainPageState extends State<SetStateMainPage> {
- int _count = 0;
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: Text(
- '您点击了$_count次',
- style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- ),
- ),
- floatingActionButton: FloatingActionButton(
- child: const Icon(Icons.add),
- onPressed: () {
- setState(() {
- _count++;
- });
- },
- )
- );
- }
- }
Gambar 1.setState penyegaran sebagian
Jika halamannya relatif sederhana, Anda dapat langsung menggunakan metode setState untuk menyegarkan sebagian UI.
Skenario penggunaan: perubahan status sederhana, seperti jumlah klik tombol, status peralihan, dll.
Tindakan pencegahan:
StatefulWidget
adalah komponen dengan negara,InheritedWidget
Digunakan untuk berbagi data dalam pohon komponen.
Saat kami perlu berbagi data, kami dapat mempertimbangkan StatefulWidget dan InheritedWidget untuk menyegarkan sebagian UI.
Kode lengkapnya adalah sebagai berikut:
Gambar 2. Refresh UI dengan berbagi data
- import 'package:flutter/material.dart';
-
- class MyInheritedWidget extends InheritedWidget {
- final int counter;
- const MyInheritedWidget({
- super.key,
- required this.counter,
- required super.child,
- });
- @override
- bool updateShouldNotify(covariant InheritedWidget oldWidget) {
- return true;
- }
- static MyInheritedWidget? of(BuildContext context) {
- return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
- }
- }
-
- class InheritedWidgetPage extends StatefulWidget {
- final String title;
- const InheritedWidgetPage({super.key, required this.title});
-
- @override
- State<InheritedWidgetPage> createState() => _InheritedWidgetPageState();
- }
-
- class _InheritedWidgetPageState extends State<InheritedWidgetPage> {
- int counter = 0;
- void _incrementCounter() {
- setState(() {
- counter++;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- return MyInheritedWidget(
- counter: counter,
- child: Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(child: Column(
- children: [
- const Divider(),
- const CounterDisplay(),
- const SizedBox(height: 20),
- ElevatedButton(
- onPressed: _incrementCounter,
- child: const Text('add'),
- ),
- ],
- ),),
- ),
- );
- }
- }
-
- class CounterDisplay extends StatelessWidget {
- const CounterDisplay({super.key});
- @override
- Widget build(BuildContext context) {
- final inheritedWidget = MyInheritedWidget.of(context);
- return Text('点击次数: ${inheritedWidget?.counter}');
- }
- }
Skenario penggunaan utama metode ini adalah sebagai berikut: saat berbagi status di pohon komponen, seperti tema, pengaturan bahasa, dll.
Keuntungannya adalah berbagi data menjadi mudah dan pengenalan kode
Kerugiannya adalah penggunaannya rumit dan kinerjanya mungkin terpengaruh.
ValueNotifier
Ini adalah alat manajemen status sederhana,ValueListenableBuilder
untuk pemantauanValueNotifier
Perubahan.
Penggunaannya juga sangat sederhana:
1. Buat instance ValueNotifier
2. Objek Widget yang akan dipantau dibungkus dengan ValueListenableBuilder
3. Cara mengubah data yang dipicu peristiwa
Dibandingkan dengan cara-cara sebelumnya, cara ini sangat sederhana dan mudah digunakan, serta performanya juga sangat tinggi.
Kekurangan: Hanya dapat menangani perubahan keadaan sederhana
Kode lengkapnya adalah sebagai berikut:
- import 'package:flutter/material.dart';
-
- class ValueNotifierPage extends StatefulWidget {
- final String title;
- const ValueNotifierPage({super.key, required this.title});
-
- @override
- State<ValueNotifierPage> createState() => _ValueNotifierPageState();
- }
-
- class _ValueNotifierPageState extends State<ValueNotifierPage> {
-
- final ValueNotifier<int> _counter = ValueNotifier<int>(0);
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: ValueListenableBuilder<int>(
- valueListenable: _counter,
- builder: (context, value, child) {
- return Text(
- '您点击了$value次',
- style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- );
- },
- )
- ),
- floatingActionButton: FloatingActionButton(
- child: const Icon(Icons.add),
- onPressed: () {
- _counter.value ++;
- },
- )
- );
- }
- }
Stream adalah objek yang digunakan untuk mengirimkan kejadian asinkron, dan kejadian dapat dikirim melalui StreamController. Jika Anda perlu menyegarkan UI, Anda dapat mengirim peristiwa ke Aliran, lalu menggunakan StreamBuilder untuk mendengarkan Aliran. Saat peristiwa baru diterima, StreamBuilder akan secara otomatis membangun kembali UI. Metode ini cocok untuk situasi di mana beberapa kejadian asinkron perlu dipantau.
Saat kita perlu memproses aliran data asinkron, seperti permintaan jaringan, data real-time, dll., kita dapat mempertimbangkan untuk menggunakan StreamBuilder. Misalnya, dalam contoh berikut, kami menulis metode asinkron yang menyimulasikan permintaan jaringan. Ketika permintaan jaringan tidak memberikan hasil yang benar, kami dapat memuat bilah kemajuan.
Keuntungan metode ini adalah dapat mengontrol permintaan asinkron dengan lebih akurat, seperti status permintaan jaringan, dll. Namun, Dior lebih kompleks dan mungkin memerlukan lebih banyak kode.
Kode lengkapnya adalah sebagai berikut:
- import 'dart:async';
- import 'package:flutter/material.dart';
-
- class StreamBuilderRefreshUIPage extends StatefulWidget {
- final String title;
- const StreamBuilderRefreshUIPage({super.key, required this.title});
-
- @override
- State<StreamBuilderRefreshUIPage> createState() =>
- _StreamBuilderRefreshUIPageState();
- }
-
- class _StreamBuilderRefreshUIPageState extends State<StreamBuilderRefreshUIPage> {
- late Future<String> _data;
-
- Future<String> fetchData() async {
- // 模拟网络请求延迟
- await Future.delayed(const Duration(seconds: 2));
- // 返回模拟数据
- return 'Hello, Flutter!';
- }
-
- @override
- void initState() {
- // TODO: implement initState
- super.initState();
- _data = fetchData();
- }
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: FutureBuilder<String>(
- future: _data,
- builder: (context, snapshot) {
- if (snapshot.connectionState == ConnectionState.waiting) {
- return const CircularProgressIndicator();
- } else if (snapshot.hasError) {
- return Text('Error: ${snapshot.error}');
- } else {
- return Text('Data: ${snapshot.data}');
- }
- },
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: fetchData,
- tooltip: 'Increment',
- child: const Icon(Icons.add),
- ),
- );
- }
- }
Provider
Ini adalah solusi manajemen negara yang direkomendasikan oleh Flutter.Consumer
Digunakan untuk membaca dan memantau status.
Mari kita ambil juga pengatur waktu sebagai contoh.
1. Pertama kita import Provider.
penyedia: ^6.1.2
2. Sesuaikan kelas ChangeNotifier.
ChangeNotifier adalah kelas sederhana di Flutter SDK. Ini digunakan untuk mengirim pemberitahuan kepada pendengar. Dengan kata lain, jika didefinisikan sebagai ChangeNotifier, Anda dapat berlangganan perubahan statusnya. (Ini mirip dengan pola pengamat yang lazim).
Dalam kode yang ingin kita implementasikan, ada dua variabel _counter1 dan _counter2. Kode tersebut didefinisikan sebagai berikut:
- class CounterModel extends ChangeNotifier {
- int _counter1 = 0;
- int _counter2 = 0;
- void addCounter1(){
- debugPrint('counter:$_counter1');
- _counter1 += 1;
- notifyListeners();
- }
- void addCounter2(){
- debugPrint('counter:$_counter2');
- _counter2 += 1;
- notifyListeners();
- }
- }
3. Gunakan Pelanggan untuk membungkus Widget yang ingin kita segarkan
- Consumer<CounterModel>(
- builder: (context, counterModel, child) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Text('计数器1个数: ${counterModel._counter1}'),
- ElevatedButton(onPressed: (){
- counterModel.addCounter1();
- }, child: const Icon(Icons.add),),
- ],
- );
- },
- ),
4. Kode lengkapnya adalah sebagai berikut:
- import 'package:flutter/material.dart';
- import 'package:provider/provider.dart';
-
- class ProviderRefreshPage extends StatefulWidget {
- final String title;
- const ProviderRefreshPage({super.key, required this.title});
-
- @override
- State<ProviderRefreshPage> createState() => _ProviderRefreshPageState();
- }
-
- class CounterModel extends ChangeNotifier {
- int _counter1 = 0;
- int _counter2 = 0;
- void addCounter1(){
- debugPrint('counter:$_counter1');
- _counter1 += 1;
- notifyListeners();
- }
- void addCounter2(){
- debugPrint('counter:$_counter2');
- _counter2 += 1;
- notifyListeners();
- }
- }
-
- class _ProviderRefreshPageState extends State<ProviderRefreshPage> {
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- const SizedBox(height: 10,), // 添加一些间距
- const Divider(),
- const Text('计数器实例',style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold),),
- Consumer<CounterModel>(
- builder: (context, counterModel, child) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Text('计数器1个数: ${counterModel._counter1}'),
- ElevatedButton(onPressed: (){
- counterModel.addCounter1();
- }, child: const Icon(Icons.add),),
- ],
- );
- },
- ),
-
- Consumer<CounterModel>(
- builder: (context, counterModel, child) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Text('计数器1个数: ${counterModel._counter2}'),
- ElevatedButton(onPressed: (){
- counterModel.addCounter2();
- }, child: const Icon(Icons.add),),
- ],
- );
- },
- ),
- const Divider(height: 20,),
- ],
- ),
- ),
- );
- }
- }
Kita juga dapat menggunakan GetX untuk mengimplementasikan penyegaran sebagian UI.
Instal pertama GetX:
get: ^4.6.6
Kemudian kami merangkum variabel di GetxController.
- class CounterManagerController extends GetxController {
- final counter1 = 0.obs;
- final counter2 = 0.obs;
- void incrementCount1() {
- counter1.value++;
- }
- void incrementCount2() {
- counter2.value++;
- }
- }
Kemudian gunakan Obx untuk membungkus Widget yang perlu menampilkan logika.
Obx(()=> Teks('Nomor penghitung 1: ${controller.counter2.value}'))
Kode lengkapnya adalah sebagai berikut:
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
-
-
- class CounterManagerController extends GetxController {
- final counter1 = 0.obs;
- final counter2 = 0.obs;
- void incrementCount1() {
- counter1.value++;
- }
- void incrementCount2() {
- counter2.value++;
- }
- }
-
- class GetXRefreshUIPage extends StatelessWidget {
- final String title;
- const GetXRefreshUIPage({super.key, required this.title});
-
- @override
- Widget build(BuildContext context) {
- final CounterManagerController controller = Get.put(CounterManagerController());
- return Scaffold(
- appBar: AppBar(
- title: Text(title),
- ),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- const SizedBox(
- height: 10,
- ), // 添加一些间距
- const Divider(),
- const Text(
- '计数器实例',
- style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Obx(()=> Text('计数器1个数: ${controller.counter1.value}')),
- ElevatedButton(
- onPressed: () {
- controller.incrementCount1();
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Obx(()=> Text('计数器1个数: ${controller.counter2.value}')),
- ElevatedButton(
- onPressed: () {
- controller.incrementCount2();
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- const Divider(
- height: 20,
- ),
- ],
- ),
- ),
- );
- }
- }
Tentu saja, ada beberapa cara lain untuk menerapkan penyegaran sebagian di GetX. Anda dapat melihat dokumentasinya. Ini hanyalah satu ide implementasi.
Ketiga metode implementasi di atas semuanya diimplementasikan melalui framework. Jika Anda tidak ingin mengimpor framework ini, kita dapat menggunakan GlobalKey untuk mengimplementasikan fungsi penyegaran sebagian pada UI.
Kunci yang unik di seluruh aplikasi GlobalKey secara unik mengidentifikasi elemen. GlobalKey menyediakan akses ke elemen terkait, sepertiBuildContext
.untukStatefulWidgets
, GlobalKey juga menyediakanState
Mengakses.
Dalam demo pengatur waktu kami, jika kami me-refresh sebagian UI melalui GlobalKey, pertama-tama kami mengeluarkan Widget untuk di-refresh sebagian dan merangkumnya ke dalam komponen terpisah.
Kode lengkapnya adalah sebagai berikut. Kami merangkum Widget untuk disegarkan sebagian dan menyediakan antarmuka untuk menyegarkan data internal, onPressed.
- class CounterText extends StatefulWidget {
- const CounterText(Key key) : super(key: key);
- @override
- State<StatefulWidget> createState() {
- return CounterTextState();
- }
- }
-
- class CounterTextState extends State<CounterText> {
- String _text="0";
-
- @override
- Widget build(BuildContext context) {
- return Center(
- child: Text(_text,style: const TextStyle(fontSize: 20),),
- );
- }
- void onPressed(int count) {
- setState(() {
- _text = count.toString();
- });
- }
- }
Kemudian buat instance GlobaKey di antarmuka utama kami:
- int _count = 0;
- int _count2 = 0;
- GlobalKey<CounterTextState> textKey = GlobalKey();
- GlobalKey<CounterTextState> textKey2 = GlobalKey();
Jika UI perlu disegarkan, panggil antarmuka yang disediakan pada langkah sebelumnya melalui GlobalKey dan segarkan.
Kode lengkapnya adalah sebagai berikut:
- import 'package:flutter/material.dart';
-
- class GlobalKeyRefreshPage extends StatefulWidget {
- final String title;
- const GlobalKeyRefreshPage({super.key, required this.title});
-
- @override
- State<GlobalKeyRefreshPage> createState() => _GlobalKeyRefreshPageState();
- }
-
- class _GlobalKeyRefreshPageState extends State<GlobalKeyRefreshPage> {
- int _count = 0;
- int _count2 = 0;
- //包裹你定义的需要更新的weight
- GlobalKey<CounterTextState> textKey = GlobalKey();
- GlobalKey<CounterTextState> textKey2 = GlobalKey();
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: Text(widget.title),
- ),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- children: <Widget>[
- const SizedBox(
- height: 10,
- ), // 添加一些间距
- const Divider(),
- const Text(
- '计数器实例',
- style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- CounterText(textKey),
- ElevatedButton(
- onPressed: () {
- _count++;
- textKey.currentState?.onPressed(_count);
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- CounterText(textKey2),
- ElevatedButton(
- onPressed: () {
- _count2++;
- textKey2.currentState?.onPressed(_count2);
- },
- child: const Icon(Icons.add),
- ),
- ],
- ),
- const Divider(
- height: 20,
- ),
- ],
- ),
- ),
- );
- }
- }
-
-
- class CounterText extends StatefulWidget {
- const CounterText(Key key) : super(key: key);
- @override
- State<StatefulWidget> createState() {
- return CounterTextState();
- }
- }
-
- class CounterTextState extends State<CounterText> {
- String _text="0";
-
- @override
- Widget build(BuildContext context) {
- return Center(
- child: Text(_text,style: const TextStyle(fontSize: 20),),
- );
- }
- void onPressed(int count) {
- setState(() {
- _text = count.toString();
- });
- }
- }