Flutter中如何为GridView添加onTap实现跳转至指定页面
为Flutter GridView中的ServiceBox添加点击跳转功能
我已完成包含GridView组件的首页HomePage开发,通过ServiceBox组件构建网格项,现需要为每个网格容器添加onTap点击事件,实现点击后跳转至对应专属页面的功能。
原代码
HomePage代码
import 'package:flutter/material.dart'; import '../util/service_box.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final double horizontalPadding = 25; final double verticalPadding = 25; // list of services List services = [ ["Background\nRemover", "assets/background_remove.png", true], ["QR\nGenerator", "assets/qr.png", false], ["Scanner", "assets/scanner.png", false], ["Calculator", "assets/calculator.png", true], ["Text to\nSpeech", "assets/tts.png", false], ]; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[300], body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.symmetric( horizontal: horizontalPadding, vertical: verticalPadding), child: IconButton( iconSize: 50, icon: const Icon( Icons.tips_and_updates, ), onPressed: () {}, ), ), const SizedBox(height: 20), Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Welcome to", style: TextStyle(fontSize: 15, color: Colors.grey[700]), ), const Text( "APPY TOOLBOX", style: TextStyle( fontSize: 37, fontWeight: FontWeight.bold, ), ), ], ), ), const SizedBox(height: 25), Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), child: Divider( color: Colors.grey[500], thickness: 1, ), ), Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), child: const Text('Services'), ), Expanded( child: GridView.builder( itemCount: services.length, padding: const EdgeInsets.all(10.0), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1/1.3, ), itemBuilder: (context, index) { return ServiceBox( serviceName: services[index][0], iconPath: services[index][1], color: services[index][2], ); }, )), ], ), ), ); } }
ServiceBox组件代码
import 'package:flutter/material.dart'; class ServiceBox extends StatelessWidget { final String serviceName; final String iconPath; final bool color; ServiceBox( {Key? key, required this.serviceName, required this.iconPath, required this.color}) : super(key: key); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(15.0), child: Container( decoration: BoxDecoration( color: color ? Colors.grey[900] : Colors.grey[200], borderRadius: BorderRadius.circular(24), ), child: Padding( padding: const EdgeInsets.symmetric(vertical: 25.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Image.asset(iconPath, height: 50, color: color ? Colors.white : Colors.black,), Row( children: [ Expanded( child: Padding( padding: const EdgeInsets.only(left: 20.0, right: 20.0), child: Text( serviceName, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 17, color: color ? Colors.white : Colors.black, ), ), ), ), ], ), ], ), ), ), ); } }
实现方案
步骤1:修改ServiceBox组件,添加点击回调
给ServiceBox新增VoidCallback类型的参数,并用InkWell(带水波纹交互效果)包裹容器,绑定点击事件:
import 'package:flutter/material.dart'; class ServiceBox extends StatelessWidget { final String serviceName; final String iconPath; final bool color; final VoidCallback onTap; // 新增点击回调参数 ServiceBox( {Key? key, required this.serviceName, required this.iconPath, required this.color, required this.onTap}) // 加入参数列表 : super(key: key); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(15.0), // 用InkWell实现点击交互,水波纹圆角与容器一致 child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(24), child: Container( decoration: BoxDecoration( color: color ? Colors.grey[900] : Colors.grey[200], borderRadius: BorderRadius.circular(24), ), child: Padding( padding: const EdgeInsets.symmetric(vertical: 25.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Image.asset(iconPath, height: 50, color: color ? Colors.white : Colors.black,), Row( children: [ Expanded( child: Padding( padding: const EdgeInsets.only(left: 20.0, right: 20.0), child: Text( serviceName, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 17, color: color ? Colors.white : Colors.black, ), ), ), ), ], ), ], ), ), ), ), ); } }
步骤2:更新HomePage,添加页面跳转逻辑
- 导入所有目标页面
- 扩展services列表,添加每个服务对应的目标页面构造器
- 在GridView的itemBuilder中,给ServiceBox传入点击回调,通过
Navigator.push实现跳转:
import 'package:flutter/material.dart'; import '../util/service_box.dart'; // 替换成你实际的页面路径和类名 import '../pages/background_remover_page.dart'; import '../pages/qr_generator_page.dart'; import '../pages/scanner_page.dart'; import '../pages/calculator_page.dart'; import '../pages/text_to_speech_page.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final double horizontalPadding = 25; final double verticalPadding = 25; // 扩展列表,添加对应页面构造器 List services = [ ["Background\nRemover", "assets/background_remove.png", true, () => const BackgroundRemoverPage()], ["QR\nGenerator", "assets/qr.png", false, () => const QrGeneratorPage()], ["Scanner", "assets/scanner.png", false, () => const ScannerPage()], ["Calculator", "assets/calculator.png", true, () => const CalculatorPage()], ["Text to\nSpeech", "assets/tts.png", false, () => const TextToSpeechPage()], ]; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[300], body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.symmetric( horizontal: horizontalPadding, vertical: verticalPadding), child: IconButton( iconSize: 50, icon: const Icon( Icons.tips_and_updates, ), onPressed: () {}, ), ), const SizedBox(height: 20), Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Welcome to", style: TextStyle(fontSize: 15, color: Colors.grey[700]), ), const Text( "APPY TOOLBOX", style: TextStyle( fontSize: 37, fontWeight: FontWeight.bold, ), ), ], ), ), const SizedBox(height: 25), Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), child: Divider( color: Colors.grey[500], thickness: 1, ), ), Padding( padding: EdgeInsets.symmetric(horizontal: horizontalPadding), child: const Text('Services'), ), Expanded( child: GridView.builder( itemCount: services.length, padding: const EdgeInsets.all(10.0), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1/1.3, ), itemBuilder: (context, index) { return ServiceBox( serviceName: services[index][0], iconPath: services[index][1], color: services[index][2], // 绑定点击跳转逻辑 onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => services[index][3](), ), ); }, ); }, )), ], ), ), ); } }
补充说明
- 请确保导入的页面路径和类名与你的实际代码一致
- 若不需要水波纹效果,可将
InkWell替换为GestureDetector,用法完全一致 - 页面较多时,推荐使用命名路由优化跳转逻辑,只需将services列表中的页面构造器替换为路由名称,再通过
Navigator.pushNamed实现跳转
内容的提问来源于stack exchange,提问作者Riddhipratim Adhikari
相关产品推荐
相关产品推荐

