getx_plus 5.0.1 copy "getx_plus: ^5.0.1" to clipboard
getx_plus: ^5.0.1 copied to clipboard

Manage states, inject dependencies, and navigate without context easily with GetX Plus.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:getx_plus/get.dart';

import 'stress_test_page.dart';

// ══════════════════════════════════════════════════════════
//  服务 — GetxService (永久实例,不会被自动回收)
// ══════════════════════════════════════════════════════════
class AuthService extends GetxService {
  final username = 'Flutter Dev'.obs;
  final isLoggedIn = true.obs;

  Future<AuthService> init() async {
    // 模拟异步初始化(网络请求、读取 token 等)
    await Future.delayed(const Duration(milliseconds: 300));
    Get.log('AuthService initialized');
    return this;
  }
}

// ══════════════════════════════════════════════════════════
//  控制器 — GetxController + 响应式 & Workers
// ══════════════════════════════════════════════════════════
class CounterController extends GetxController {
  final count = 0.obs;
  final history = <String>[].obs;

  late Worker _everWorker;
  late Worker _debounceWorker;
  late Worker _intervalWorker;

  @override
  void onInit() {
    super.onInit();
    // ever: 每次 count 变化都触发
    _everWorker = ever(count, (val) {
      history.add('[ever] count=$val');
    });
    // debounce: 停止变化 500ms 后触发
    _debounceWorker = debounce(count, (val) {
      history.add('[debounce] settled at $val');
    }, time: const Duration(milliseconds: 500));
    // interval: 最多每 1s 触发一次
    _intervalWorker = interval(count, (val) {
      history.add('[interval] sampled $val');
    }, time: const Duration(seconds: 1));
  }

  void increment() => count.value++;
  void decrement() => count.value--;
  void reset() => count.value = 0;

  @override
  void onClose() {
    _everWorker.dispose();
    _debounceWorker.dispose();
    _intervalWorker.dispose();
    super.onClose();
  }
}

// ══════════════════════════════════════════════════════════
//  控制器 — 使用 update() 的经典模式 (GetBuilder)
// ══════════════════════════════════════════════════════════
class TodoController extends GetxController {
  final todos = <String>[];
  final textCtrl = TextEditingController();

  void addTodo() {
    final text = textCtrl.text.trim();
    if (text.isNotEmpty) {
      todos.add(text);
      textCtrl.clear();
      update(); // 通知 GetBuilder 刷新
    }
  }

  void removeTodo(int index) {
    todos.removeAt(index);
    update(); // 通知 GetBuilder 刷新
  }

  @override
  void onClose() {
    textCtrl.dispose();
    super.onClose();
  }
}

// ══════════════════════════════════════════════════════════
//  控制器 — ScrollMixin 演示无限滚动
// ══════════════════════════════════════════════════════════
class InfiniteListController extends GetxController with ScrollMixin {
  final items = <int>[].obs;
  final isLoading = false.obs;

  @override
  void onInit() {
    super.onInit();
    _loadMore();
  }

  Future<void> _loadMore() async {
    isLoading.value = true;
    await Future.delayed(const Duration(milliseconds: 500));
    final start = items.length;
    items.addAll(List.generate(20, (i) => start + i));
    isLoading.value = false;
  }

  @override
  Future<void> onEndScroll() async {
    await _loadMore();
  }

  @override
  Future<void> onTopScroll() async {
    Get.log('Scrolled to top');
  }
}

// ══════════════════════════════════════════════════════════
//  控制器 — 设置页,演示主题切换
// ══════════════════════════════════════════════════════════
class SettingsController extends GetxController {
  final isDark = false.obs;

  void toggleTheme() {
    isDark.toggle();
    Get.changeThemeMode(isDark.value ? ThemeMode.dark : ThemeMode.light);
  }
}

// ══════════════════════════════════════════════════════════
//  路由中间件 — GetMiddleware
// ══════════════════════════════════════════════════════════
class LogMiddleware extends GetMiddleware {
  @override
  int get priority => 0;

  @override
  GetPage? onPageCalled(GetPage? page) {
    Get.log('🔀 Middleware: navigating to ${page?.name}');
    return page;
  }
}

class AuthMiddleware extends GetMiddleware {
  @override
  int get priority => 1;

  @override
  RouteSettings? redirect(String? route) {
    final auth = Get.find<AuthService>();
    if (!auth.isLoggedIn.value) {
      return const RouteSettings(name: '/');
    }
    return null; // 允许通过
  }
}

// ══════════════════════════════════════════════════════════
//  Bindings
// ══════════════════════════════════════════════════════════
class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => CounterController());
    Get.lazyPut(() => TodoController());
    Get.lazyPut(() => SettingsController());
  }
}

class InfiniteListBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => InfiniteListController());
  }
}

// ══════════════════════════════════════════════════════════
//  App 入口
// ══════════════════════════════════════════════════════════
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 预先注册永久服务 (Get.put permanent)
  await Get.put(AuthService(), permanent: true).init();

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      enableLog: true,
      smartManagement: SmartManagement.full,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.indigo,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.indigo,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      themeMode: ThemeMode.light,
      routingCallback: (routing) {
        // 全局路由监听
        if (routing != null) {
          Get.log('📍 Route: ${routing.current}');
        }
      },
      initialRoute: '/',
      getPages: [
        GetPage(
          name: '/',
          page: () => const HomePage(),
          binding: HomeBinding(),
          transition: Transition.fadeIn,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/reactive',
          page: () => const ReactiveDemoPage(),
          transition: Transition.rightToLeftWithFade,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/workers',
          page: () => const WorkerDemoPage(),
          transition: Transition.zoom,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/todos',
          page: () => const TodoPage(),
          transition: Transition.downToUp,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/infinite',
          page: () => const InfiniteListPage(),
          binding: InfiniteListBinding(),
          transition: Transition.cupertino,
          middlewares: [LogMiddleware(), AuthMiddleware()],
        ),
        GetPage(
          name: '/settings',
          page: () => const SettingsPage(),
          transition: Transition.leftToRight,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/detail/:id',
          page: () => const DetailPage(),
          transition: Transition.circularReveal,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/di',
          page: () => const DiDemoPage(),
          transition: Transition.size,
          middlewares: [LogMiddleware()],
        ),
        GetPage(
          name: '/nav',
          page: () => const NavDemoPage(),
          transition: Transition.fade,
          middlewares: [LogMiddleware()],
          children: [
            GetPage(
              name: '/child',
              page: () => const NavChildPage(),
              transition: Transition.upToDown,
            ),
          ],
        ),
        GetPage(name: '/stress', page: () => const StressTestPage()),
      ],
      unknownRoute: GetPage(name: '/404', page: () => const NotFoundPage()),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  首页 — 导航入口 + GetView 演示
// ══════════════════════════════════════════════════════════
class HomePage extends GetView<CounterController> {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Obx(() => Text('GetX Plus 全功能演示  (${controller.count})')),
        actions: [
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: () => Get.toNamed('/settings'),
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [..._buildMenuItems()],
      ),
      // Obx 自动追踪 count 变化
      floatingActionButton: Obx(
        () => FloatingActionButton.extended(
          onPressed: controller.increment,
          icon: const Icon(Icons.add),
          label: Text('${controller.count}'),
        ),
      ),
    );
  }

  List<Widget> _buildMenuItems() {
    final items = [
      ('响应式演示', Icons.bolt, '/reactive'),
      ('Worker 演示', Icons.timer, '/workers'),
      ('待办事项', Icons.checklist, '/todos'),
      ('路由演示', Icons.navigation, '/nav'),
      ('依赖注入', Icons.hub, '/di'),
      ('Infinite Scroll', Icons.all_inclusive, '/infinite'),
      ('⚡ 性能压力测试', Icons.speed, '/stress'),
    ];
    return items.map((e) {
      final (label, icon, route) = e;
      return Card(
        child: ListTile(
          leading: Icon(icon),
          title: Text(label),
          trailing: const Icon(Icons.chevron_right),
          onTap: () => Get.toNamed(route),
        ),
      );
    }).toList();
  }
}

// ══════════════════════════════════════════════════════════
//  响应式演示 — Rx 各种类型 + Obx / ObxValue
// ══════════════════════════════════════════════════════════
class ReactiveDemoPage extends StatelessWidget {
  const ReactiveDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    // 局部响应式变量(不需要控制器)
    final name = 'Alice'.obs;
    final score = 99.5.obs;
    final isActive = true.obs;
    final tags = <String>{'flutter', 'dart'}.obs;
    final scores = <String, int>{'math': 100, 'eng': 95}.obs;
    final items = <int>[1, 2, 3].obs;

    return Scaffold(
      appBar: AppBar(title: const Text('响应式演示')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // RxString
          _section('RxString'),
          Obx(
            () => Text('Name: ${name.value}  (length: ${name.value.length})'),
          ),
          ElevatedButton(
            onPressed: () =>
                name.value = name.value == 'Alice' ? 'Bob' : 'Alice',
            child: const Text('Toggle Name'),
          ),
          const Divider(),

          // RxDouble
          _section('RxDouble'),
          Obx(() => Text('Score: ${score.value.toStringAsFixed(1)}')),
          Obx(
            () => Slider(
              value: score.value.clamp(0.0, 100.0),
              min: 0,
              max: 100,
              onChanged: (v) => score.value = v,
            ),
          ),
          const Divider(),

          // RxBool + toggle()
          _section('RxBool'),
          Obx(
            () => SwitchListTile(
              title: Text('Active: ${isActive.isTrue ? "YES" : "NO"}'),
              value: isActive.value,
              onChanged: (_) => isActive.toggle(),
            ),
          ),
          const Divider(),

          // RxList
          _section('RxList'),
          Obx(() => Text('Items: $items')),
          Wrap(
            spacing: 8,
            children: [
              ElevatedButton(
                onPressed: () => items.add(items.length + 1),
                child: const Text('Add'),
              ),
              ElevatedButton(
                onPressed: () {
                  if (items.isNotEmpty) items.removeLast();
                },
                child: const Text('Remove Last'),
              ),
            ],
          ),
          const Divider(),

          // RxSet
          _section('RxSet'),
          Obx(() => Text('Tags: ${tags.join(", ")}')),
          ElevatedButton(
            onPressed: () =>
                tags.contains('getx') ? tags.remove('getx') : tags.add('getx'),
            child: const Text('Toggle "getx" tag'),
          ),
          const Divider(),

          // RxMap
          _section('RxMap'),
          Obx(() => Text('Scores: $scores')),
          ElevatedButton(
            onPressed: () => scores['science'] = (scores['science'] ?? 0) + 10,
            child: const Text('Add 10 to Science'),
          ),
          const Divider(),

          // ObxValue — 局部状态管理小组件
          _section('ObxValue<RxBool>'),
          ObxValue<RxBool>(
            (data) => CheckboxListTile(
              title: const Text('Agree to terms'),
              value: data.value,
              onChanged: (_) => data.toggle(),
            ),
            false.obs,
          ),
        ],
      ),
    );
  }

  Widget _section(String title) => Padding(
    padding: const EdgeInsets.only(top: 8, bottom: 4),
    child: Text(
      title,
      style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
    ),
  );
}

// ══════════════════════════════════════════════════════════
//  Worker 演示 — ever / debounce / interval / once
// ══════════════════════════════════════════════════════════
class WorkerDemoPage extends GetView<CounterController> {
  const WorkerDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Worker 演示')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                IconButton.filled(
                  onPressed: controller.decrement,
                  icon: const Icon(Icons.remove),
                ),
                Obx(() => Text('${controller.count}')),
                IconButton.filled(
                  onPressed: controller.increment,
                  icon: const Icon(Icons.add),
                ),
              ],
            ),
          ),
          ElevatedButton(
            onPressed: controller.reset,
            child: const Text('Reset'),
          ),
          const Padding(
            padding: EdgeInsets.all(8),
            child: Text(
              'Worker History:',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ),
          Expanded(
            child: Obx(
              () => ListView.builder(
                itemCount: controller.history.length,
                itemBuilder: (_, i) {
                  final idx = controller.history.length - 1 - i;
                  return ListTile(
                    dense: true,
                    leading: const Icon(Icons.arrow_right, size: 16),
                    title: Text(
                      controller.history[idx],
                      style: const TextStyle(fontSize: 13),
                    ),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  Todo 页面 — GetBuilder + update() 经典模式
// ══════════════════════════════════════════════════════════
class TodoPage extends GetView<TodoController> {
  const TodoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('待办事项')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(12),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: controller.textCtrl,
                    decoration: InputDecoration(
                      hintText: '添加待办',
                      border: const OutlineInputBorder(),
                    ),
                    onSubmitted: (_) => controller.addTodo(),
                  ),
                ),
                const SizedBox(width: 8),
                IconButton.filled(
                  onPressed: controller.addTodo,
                  icon: const Icon(Icons.add),
                ),
              ],
            ),
          ),
          Expanded(
            // GetBuilder: 手动 update() 驱动刷新,支持 id 过滤
            child: GetBuilder<TodoController>(
              builder: (ctrl) {
                if (ctrl.todos.isEmpty) {
                  return Center(child: Text('暂无待办事项'));
                }
                return ListView.builder(
                  itemCount: ctrl.todos.length,
                  itemBuilder: (_, i) => Dismissible(
                    key: ValueKey('${ctrl.todos[i]}_$i'),
                    onDismissed: (_) => ctrl.removeTodo(i),
                    background: Container(
                      color: Colors.red.shade100,
                      alignment: Alignment.centerRight,
                      padding: const EdgeInsets.only(right: 16),
                      child: const Icon(Icons.delete),
                    ),
                    child: ListTile(
                      leading: CircleAvatar(child: Text('${i + 1}')),
                      title: Text(ctrl.todos[i]),
                    ),
                  ),
                );
              },
            ),
          ),
          // GetBuilder 全局刷新显示总数
          GetBuilder<TodoController>(
            builder: (ctrl) => Padding(
              padding: const EdgeInsets.all(8),
              child: Text('Total: ${ctrl.todos.length}'),
            ),
          ),
        ],
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  无限滚动 — ScrollMixin + AuthMiddleware 守卫
// ══════════════════════════════════════════════════════════
class InfiniteListPage extends GetView<InfiniteListController> {
  const InfiniteListPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Infinite Scroll (ScrollMixin)')),
      body: Obx(
        () => ListView.builder(
          controller: controller.scroll,
          itemCount: controller.items.length + 1,
          itemBuilder: (_, i) {
            if (i == controller.items.length) {
              return Padding(
                padding: const EdgeInsets.all(16),
                child: Center(
                  child: controller.isLoading.value
                      ? const CircularProgressIndicator()
                      : const Text('Scroll down for more'),
                ),
              );
            }
            return ListTile(
              leading: CircleAvatar(child: Text('${controller.items[i]}')),
              title: Text('Item #${controller.items[i]}'),
            );
          },
        ),
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  设置页面 — 主题切换
// ══════════════════════════════════════════════════════════
class SettingsPage extends GetView<SettingsController> {
  const SettingsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('设置')),
      body: Obx(
        () => ListView(
          children: [
            SwitchListTile(
              title: const Text('切换主题'),
              subtitle: Text(controller.isDark.value ? 'Dark' : 'Light'),
              secondary: Icon(
                controller.isDark.value ? Icons.dark_mode : Icons.light_mode,
              ),
              value: controller.isDark.value,
              onChanged: (_) => controller.toggleTheme(),
            ),
          ],
        ),
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  依赖注入演示 — put / lazyPut / find / delete / isRegistered
// ══════════════════════════════════════════════════════════
class _DemoService {
  final String id;
  _DemoService(this.id);
  @override
  String toString() => 'DemoService($id)';
}

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

  @override
  Widget build(BuildContext context) {
    final log = <String>[].obs;

    void addLog(String msg) => log.add(msg);

    return Scaffold(
      appBar: AppBar(title: const Text('依赖注入')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8),
            child: Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                ElevatedButton(
                  onPressed: () {
                    Get.put(_DemoService('singleton'), tag: 'demo');
                    addLog('✅ put _DemoService(singleton) tag=demo');
                  },
                  child: const Text('Get.put'),
                ),
                ElevatedButton(
                  onPressed: () {
                    Get.lazyPut(() => _DemoService('lazy'), tag: 'lazy');
                    addLog('✅ lazyPut _DemoService(lazy) tag=lazy');
                  },
                  child: const Text('Get.lazyPut'),
                ),
                ElevatedButton(
                  onPressed: () {
                    try {
                      final s = Get.find<_DemoService>(tag: 'demo');
                      addLog('🔍 find tag=demo → $s');
                    } catch (e) {
                      addLog('❌ find tag=demo → not found');
                    }
                  },
                  child: const Text('find(demo)'),
                ),
                ElevatedButton(
                  onPressed: () {
                    try {
                      final s = Get.find<_DemoService>(tag: 'lazy');
                      addLog('🔍 find tag=lazy → $s');
                    } catch (e) {
                      addLog('❌ find tag=lazy → not found');
                    }
                  },
                  child: const Text('find(lazy)'),
                ),
                ElevatedButton(
                  onPressed: () {
                    final r = Get.isRegistered<_DemoService>(tag: 'demo');
                    addLog('📋 isRegistered(demo)=$r');
                  },
                  child: const Text('isRegistered'),
                ),
                ElevatedButton(
                  onPressed: () {
                    final r = Get.isPrepared<_DemoService>(tag: 'lazy');
                    addLog('📋 isPrepared(lazy)=$r');
                  },
                  child: const Text('isPrepared'),
                ),
                ElevatedButton(
                  onPressed: () {
                    final deleted = Get.delete<_DemoService>(tag: 'demo');
                    addLog('🗑 delete(demo)=$deleted');
                  },
                  child: const Text('delete(demo)'),
                ),
                ElevatedButton(
                  onPressed: () {
                    // putOrFind: 有则返回,无则注册
                    final s = Get.putOrFind(() => _DemoService('putOrFind'));
                    addLog('🔄 putOrFind → $s');
                  },
                  child: const Text('putOrFind'),
                ),
                ElevatedButton(
                  onPressed: () {
                    // AuthService 是永久的 GetxService
                    final auth = Get.find<AuthService>();
                    addLog('🔒 AuthService: ${auth.username}');
                  },
                  child: const Text('find AuthService'),
                ),
              ],
            ),
          ),
          const Divider(),
          Expanded(
            child: Obx(
              () => ListView.builder(
                reverse: true,
                itemCount: log.length,
                itemBuilder: (_, i) {
                  final idx = log.length - 1 - i;
                  return Padding(
                    padding: const EdgeInsets.symmetric(
                      horizontal: 12,
                      vertical: 2,
                    ),
                    child: Text(log[idx], style: const TextStyle(fontSize: 13)),
                  );
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  路由演示 — to / toNamed / off / back / arguments / parameters
// ══════════════════════════════════════════════════════════
class NavDemoPage extends StatelessWidget {
  const NavDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('路由演示')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          _navButton('Get.to (anonymous route)', () {
            Get.to(
              () => const _AnonymousPage(),
              transition: Transition.rightToLeft,
              duration: const Duration(milliseconds: 400),
            );
          }),
          _navButton('Get.toNamed with arguments', () {
            Get.toNamed('/detail/42', arguments: {'title': 'Item 42'});
          }),
          _navButton('Get.toNamed with query params', () {
            Get.toNamed('/detail/7?color=blue&size=large');
          }),
          _navButton('Get.toNamed → child route', () {
            Get.toNamed('/nav/child');
          }),
          _navButton('Get.offNamed (replace)', () {
            Get.offNamed('/reactive');
          }),
          _navButton('Navigate to unknown → 404', () {
            Get.toNamed('/this-does-not-exist');
          }),
          _navButton('Get.back with result', () {
            Get.back(result: 'Hello from NavDemo!');
          }),
          const Divider(),
          Padding(
            padding: const EdgeInsets.all(8),
            child: Text(
              'currentRoute: ${Get.currentRoute}\n'
              'previousRoute: ${Get.previousRoute}',
              style: const TextStyle(fontSize: 13),
            ),
          ),
        ],
      ),
    );
  }

  Widget _navButton(String label, VoidCallback onTap) => Padding(
    padding: const EdgeInsets.only(bottom: 8),
    child: ElevatedButton(onPressed: onTap, child: Text(label)),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Child Route (/nav/child)')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => Get.back(),
          child: const Text('Go Back'),
        ),
      ),
    );
  }
}

class _AnonymousPage extends StatelessWidget {
  const _AnonymousPage();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Anonymous Route')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('This page was pushed via Get.to()'),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () => Get.back(),
              child: const Text('Back'),
            ),
          ],
        ),
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  详情页 — URL 参数 + arguments 演示
// ══════════════════════════════════════════════════════════
class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    final id = Get.parameters['id'] ?? 'unknown';
    final args = Get.arguments;
    final query = Uri.base.queryParameters;

    return Scaffold(
      appBar: AppBar(title: Text('Detail #$id')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Path parameter id: $id'),
            const SizedBox(height: 8),
            Text('Arguments: $args'),
            const SizedBox(height: 8),
            Text('Query parameters: $query'),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: () => Get.back(),
              child: const Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

// ══════════════════════════════════════════════════════════
//  404 页面
// ══════════════════════════════════════════════════════════
class NotFoundPage extends StatelessWidget {
  const NotFoundPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('404')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error_outline, size: 64, color: Colors.red),
            const SizedBox(height: 16),
            const Text('Page Not Found', style: TextStyle(fontSize: 24)),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () => Get.offAllNamed('/'),
              child: const Text('Back to Home'),
            ),
          ],
        ),
      ),
    );
  }
}
2
likes
0
points
307
downloads

Publisher

unverified uploader

Weekly Downloads

Manage states, inject dependencies, and navigate without context easily with GetX Plus.

Homepage
Repository (GitHub)
View/report issues

Topics

#widget #state-management #dependency-injection #navigation

License

unknown (license)

Dependencies

equatable, flutter, flutter_web_plugins, web

More

Packages that depend on getx_plus