Flutter GetX kullanarak TabView nasıl oluşturulur
Durum Yönetimi için GetX ile Flutter kullanarak bir uygulama oluşturmaya çalışıyorum ve sayfalarımdan birinde, sayfanın ortasına bir TabView widget'ı oluşturmam gerekiyor, bir TabView olarak widget, bu gönderi ve bu makale gibi , ancak bunların tümü bir SingleTickerProviderStateMixin ile bir Durum denetleyicisini genişletir .
Belgeleri okumayı anladığım için, StatefulWidgets ve States'i bu şekilde kullanmam gerekiyor, ancak GetX mimarisini kullanarak bir çözümü nasıl detaylandıracağımı bulamıyorum.
Sayfamda şu gibi şeyleri zaten denedim:
class CourseDetailPage extends StatelessWidget {
final TabController _tabController = Get.put(TabController(vsync: null, length: 2));
}
ve
class CourseDetailPage extends StatelessWidget {
final TabController _tabController = TabController(vsync: null, length: 2);
}
Ancak TabController için VSYNC bağımsız değişkeni boş olamaz ve onu doldurmak için bir TickerProvider'ı nasıl elde edemeyeceğimi anlamıyorum.
Yanıtlar
Aşağıdakiler, bir TabView'ı kontrol etmek için bir GetX denetleyicisi kullanmanın bir çözümü olabilir mi?
GetTicker
TickerProvider arabirimini uygulayan SingleTickerProviderMixin'in bir Get sürümü vardır (Flutter SDK'daki aynı Ticker sınıfını kullanarak).
Akılda kalıcı bir adı var: SingleGetTickerProviderMixin
Aşağıdaki örnek temelde TabController için Flutter belgelerinden alınmıştır .
Bağlantılı örneğin StatefulWidget içeriğinden, içeriğini bir GetxController ( MyTabController) 'e çevirdim ve şunların karışımını ekledim SingleGetTickerProviderMixin:
class MyTabController extends GetxController with SingleGetTickerProviderMixin {
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController controller;
@override
void onInit() {
super.onInit();
controller = TabController(vsync: this, length: myTabs.length);
}
@override
void onClose() {
controller.dispose();
super.onClose();
}
}
MyTabControllerDurum Bilgisi İçermeyen bir pencere öğesinin içinde kullanmak için :
class MyTabbedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyTabController _tabx = Get.put(MyTabController());
// ↑ init tab controller
return Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: _tabx.controller,
tabs: _tabx.myTabs,
),
),
body: TabBarView(
controller: _tabx.controller,
children: _tabx.myTabs.map((Tab tab) {
final String label = tab.text.toLowerCase();
return Center(
child: Text(
'This is the $label tab',
style: const TextStyle(fontSize: 36),
),
);
}).toList(),
),
);
}
}
İşte çalıştırmak için Android Studio / VisualStudio Koduna kopyalayıp yapıştırmak için uygulama örneğinin geri kalanı:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GetX Tab Example'),
),
body: Column(
children: [
Expanded(
flex: 1,
child: Container(
alignment: Alignment.center,
child: Text('Some random stuff'),
),
),
Expanded(
flex: 4,
child: MyTabbedWidget(),
)
],
),
);
}
}
class MyTabController extends GetxController with SingleGetTickerProviderMixin {
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController controller;
@override
void onInit() {
super.onInit();
controller = TabController(vsync: this, length: myTabs.length);
}
@override
void onClose() {
controller.dispose();
super.onClose();
}
}
class MyTabbedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyTabController _tabx = Get.put(MyTabController());
// ↑ init tab controller
return Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: _tabx.controller,
tabs: _tabx.myTabs,
),
),
body: TabBarView(
controller: _tabx.controller,
children: _tabx.myTabs.map((Tab tab) {
final String label = tab.text.toLowerCase();
return Center(
child: Text(
'This is the $label tab',
style: const TextStyle(fontSize: 36),
),
);
}).toList(),
),
);
}
}
Dediğin gibi genişledikleri tüm makalelerde State, SingleTickerProviderStateMixinçünkü bir durumu yönet ( doc ) gibi TabControllerdışını başlatamayacaksın .StateTabController
Çözüm, denetleyiciniz için bir değişken kullanmamak ve sizin TabBarve TabViewpencere öğesi ağacınızı bir DefaultTabController.
İşte resmi belgeden bir örnek :
class MyDemo extends StatelessWidget {
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: myTabs.length,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: myTabs,
),
),
body: TabBarView(
children: myTabs.map((Tab tab) {
final String label = tab.text.toLowerCase();
return Center(
child: Text(
'This is the $label tab',
style: const TextStyle(fontSize: 36),
),
);
}).toList(),
),
),
);
}
}
Bunu yaparak TabViewiçinizin a sahip olmanız gerekmeyecek, Stateancak GetXikisini de kullanmayacaksınız .
Kesin sorunla karşılaştım ve GetX çerçevesinin birçok olası senaryo için hazır olmadığını ve onu dikkatli kullanmanız gerektiğini gösteriyor.
Bulduğum çözüm bir sarmalayıcı gereci. Önerilen örnekte kullandım, HookWidgetancak siz de Stateful widget'ı kullanmakta özgürsünüz.
class TabWidget extends HookWidget {
final List<Widget> children;
final RxInt currentTab;
final int initialIndex;
TabWidget({
@required this.children,
@required this.currentTab,
@required this.initialIndex,
});
@override
Widget build(BuildContext context) {
final controller = useTabController(
initialLength: children.length,
initialIndex: initialIndex,
);
currentTab.listen((page) {
controller.animateTo(page);
});
return TabBarView(controller: controller, children: children);
}
}
Gördüğünüz gibi tabView'in durumunu kontrol eden bir Rx değişkeni var. Bu nedenle, dışarıdan bir RxInt geçirmeniz gerekir ve değeri her değiştiğinde tabView sırasıyla güncellenir.
class TestView extends GetView<TestController> {
@override
Widget build(BuildContext context) {
final screen = 0.obs;
return SafeArea(
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.forward),
onPressed: () => screen.value = screen.value + 1,
)
],
),
body: TabWidget(
initialIndex: 1,
currentTab: screen,
children: [
child1,
child2,
child3,
...,
],
),
),
);
}
Şu anda HookWidget yardımıyla kontrol cihazına bakıyoruz. Durum bilgisi olan pencere aracını kullanıyorsanız, doğru şekilde atmanız gerekir.