Flutter中的`InkWell`组件使用示例

Flutter中你从未见过的的InkWell组件使用示例

InkWell 是 Flutter 中最实用的组件之一. 它用于为原本不可交互的组件添加涟漪效果和交互处理功能.

InkWell 的关键特性

  • 点击时生成 Material Design 风格的墨迹飞溅效果
  • 支持多种手势操作(单击, 双击, 长按)
  • 在 Material 组件中工作以显示正确的视觉反馈
  • 可以自定义不同的溅射颜色和形状

使用 InkWell 的自定义组件

自定义按钮

具有独特设计且保持正确触摸反馈的自定义按钮.

less 复制代码
class EngageButton extends StatelessWidget {
  final IconData icon;
  final String label;
  final Color color;
  final VoidCallback onTap;

  const EngageButton({
    super.key,
    required this.icon,
    required this.label,
    required this.color,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Material(
          color: color.withValues(alpha: 0.1),
          borderRadius: BorderRadius.circular(16),
          child: InkWell(
            onTap: onTap,
            borderRadius: BorderRadius.circular(16),
            splashColor: color.withValues(alpha: 0.3),
            highlightColor: color.withValues(alpha: 0.1),
            child: Container(
              padding: const EdgeInsets.all(12),
              child: Icon(icon, color: color, size: 28),
            ),
          ),
        ),
        const SizedBox(height: 4),
        Text(
          label,
          style: TextStyle(color: color, fontWeight: FontWeight.bold),
        ),
      ],
    );
  }
} 

View中使用它们:

less 复制代码
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                EngageButton(
                  icon: Icons.favorite,
                  label: 'Like',
                  color: Colors.red,
                  onTap: () =>(){},
                ),
                EngageButton(
                  icon: Icons.share,
                  label: 'Share',
                  color: Colors.blue,
                  onTap: () => (){},
                ),
                EngageButton(
                  icon: Icons.comment,
                  label: 'Comment',
                  color: Colors.green,
                  onTap: () =>(){},
                ),
              ],
            ),

交互式卡片

可点击的卡片组件, 带有视觉反馈

less 复制代码
class InteractiveCard extends StatelessWidget {
  final String title;
  final String description;
  final IconData icon;
  final VoidCallback onTap;

  const InteractiveCard({
    super.key,
    required this.title,
    required this.description,
    required this.icon,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.white,
      elevation: 2,
      borderRadius: BorderRadius.circular(8),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(8),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Row(
            children: [
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.blue.withValues(alpha: 0.1),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Icon(icon, color: Colors.blue, size: 24),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 16,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      description,
                      style: TextStyle(
                        color: Colors.grey[600],
                        fontSize: 14,
                      ),
                    ),
                  ],
                ),
              ),
              const Icon(Icons.chevron_right),
            ],
          ),
        ),
      ),
    );
  }
}

View中使用:

less 复制代码
           InteractiveCard(
              title: 'Morning Routine',
              description: 'Simple steps to start your day right',
              icon: Icons.wb_sunny,
              onTap: () =>(){},
            ),
            const SizedBox(height: 16),
            InteractiveCard(
              title: 'Evening Reflection',
              description: 'Review your day and plan for tomorrow',
              icon: Icons.nightlight_round,
              onTap: () => (){},
            ),

交互式列表项

具有自定义布局但标准交互模式的列表.

php 复制代码
class InteractiveListItem extends StatelessWidget {
  final Widget leading;
  final String title;
  final String subtitle;
  final Widget trailing;
  final VoidCallback onTap;

  const InteractiveListItem({
    super.key,
    required this.leading,
    required this.title,
    required this.subtitle,
    required this.trailing,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: onTap,
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0),
          child: Row(
            children: [
              leading,
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 16,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      subtitle,
                      style: TextStyle(
                        color: Colors.grey[600],
                        fontSize: 14,
                      ),
                    ),
                  ],
                ),
              ),
              trailing,
            ],
          ),
        ),
      ),
    );
  }
}

View中使用:

less 复制代码
            InteractiveListItem(
              leading: const CircleAvatar(
                backgroundColor: Colors.purple,
                child: Icon(Icons.person, color: Colors.white),
              ),
              title: 'Artem Novikov',
              subtitle: 'UX Designer',
              trailing: const Icon(Icons.arrow_forward_ios, size: 16),
              onTap: () =>(){},
            ),
            const Divider(),
            InteractiveListItem(
              leading: const CircleAvatar(
                backgroundColor: Colors.orange,
                child: Icon(Icons.person, color: Colors.white),
              ),
              title: 'Yuriy Novikov',
              subtitle: 'Software Engineer',
              trailing: const Icon(Icons.arrow_forward_ios, size: 16),
              onTap: (){},
            ),

ImageButton

具有涟漪效果和点击处理程序的图像.

less 复制代码
class ImageButton extends StatelessWidget {
  final ImageProvider imageProvider;
  final String label;
  final VoidCallback onTap;

  const ImageButton({
    super.key,
    required this.imageProvider,
    required this.label,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Material(
          elevation: 4,
          borderRadius: BorderRadius.circular(12),
          child: InkWell(
            onTap: onTap,
            borderRadius: BorderRadius.circular(12),
            child: Ink.image(
              image: imageProvider,
              width: 120,
              height: 120,
              fit: BoxFit.cover,
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Container(
                  width: double.infinity,
                  color: Colors.black.withValues(alpha: 0.6),
                  padding: const EdgeInsets.symmetric(vertical: 8),
                  child: Text(
                    label,
                    textAlign: TextAlign.center,
                    style: const TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }
}

View中使用:

less 复制代码
                ImageButton(
                  imageProvider: const NetworkImage(
                   'https://images.unsplash.com/photo-1472396961693-142e6e269027?w=400&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NXx8bmF0dXJlfGVufDB8fDB8fHwy'                  
                  ),
                  label: 'Nature',
                  onTap: (){},
                ),
                ImageButton(
                  imageProvider: const NetworkImage(
                   'https://images.unsplash.com/photo-1575550959106-5a7defe28b56?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
                  ),
                  label: 'Wildlife',
                  onTap: (){},
                ),

IconButtononDoubleTap 处理程序

用于播放音频的按钮, onTap以正常速度播放, onDoubleTap以快速速度播放, onLongPress以慢速播放.

less 复制代码
class AudioIconButton extends StatelessWidget {
  final bool isPlaying;
  final VoidCallback onTap;
  final VoidCallback onDoubleTap;
  final VoidCallback onLongPress;
  final double size;
  final Color color;

  const AudioIconButton({
    super.key,
    required this.isPlaying,
    required this.onTap,
    required this.onDoubleTap,
    required this.onLongPress,
    this.size = 60.0,
    this.color = Colors.purple,
  });

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: size, 
      height: size,
      child: Material(  
         borderRadius: BorderRadius.circular(16),
        color: color.withValues(alpha: 0.1),     
        child: InkWell(
          onTap: onTap,
          onDoubleTap: onDoubleTap,
          onLongPress: onLongPress,
          borderRadius: BorderRadius.circular(16),
          splashColor: color.withValues(alpha: 0.3),
          highlightColor: color.withValues(alpha: 0.1),
          
          
          child: Container(
            padding: const EdgeInsets.all(12),
            child: Center(
              child: Icon(
                isPlaying ? Icons.pause : Icons.play_arrow,
                color: color,
                size: 28,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

View:

yaml 复制代码
           GetBuilder<AudioController>(
              id: 'play',
              builder: (controller) {
                return AudioIconButton(
                    color: Colors.blue,
                    isPlaying: controller.isPlaying,
                    onTap: () {
                      controller.handleTap();
                    },
                    onDoubleTap: () {
                      controller.handleDoubleTap();
                    },
                    onLongPress: () {
                      controller.handleLongPress();
                    });
              }
            ), 

Controller:

ini 复制代码
 bool isPlaying = false;

  void handleTap() {
    isPlaying = !isPlaying;
    var message = 'Playing is stopped';
    if (isPlaying) {
      message = 'Playing with normal speed';
    }
    Get.showSnackbar(GetSnackBar(
      message: message,
      duration: Duration(seconds: 1),
    ));

    update(['play']);
  }

  void handleDoubleTap() {
    isPlaying = !isPlaying;
    var message = 'Playing is stopped';
    if (isPlaying) {
      message = 'Playing fast';
    }
    Get.showSnackbar(GetSnackBar(
      message: message,
      duration: Duration(seconds: 1),
    ));
    update(['play']);
  }

  void handleLongPress() {
    isPlaying = !isPlaying;
    var message = 'Playing is stopped';
    if (isPlaying) {
      message = 'Playing slowly';
    }
    Get.showSnackbar(GetSnackBar(
      message: message,
      duration: Duration(seconds: 1),
    ));
    update(['play']);
  }

InkWellInkResponse

InkWellInkResponse 非常相似. 它们都实现了 InteractiveInkFeature 并位于 ink_well.dart 库中.

区别在于 InkResponse 允许对高亮形状的形式进行更多自定义, 而 InkWell 始终创建矩形高亮.

上述所有示例均可使用 InkResponse 重新实现.

InkWellInk

这两个类服务于完全不同的目的, 但经常被一起使用.

虽然 InkWell允许交互并以飞溅和高亮的形式提供视觉反馈, 但 Ink允许在底层 Material上绘制小部件, 而 InkWell提供的飞溅和高亮效果将在此可见.

我们已经使用 Ink 来实现我们的 ImageButton.

less 复制代码
        Material(
          elevation: 4,
          borderRadius: BorderRadius.circular(12),
          child: Ink.image(
            image: imageProvider,
            width: 120,
            height: 120,
            fit: BoxFit.cover,
            child: InkWell(

好吧, 今天的内容就分享到这里啦!

一家之言, 欢迎拍砖!

Happy Coding! Stay GOLDEN!

相关推荐
Steven Hank3 小时前
Flutter 替换镜像源
flutter
叽哥4 小时前
dart学习第 16 节:库与包管理 —— 高效开发的关键
flutter·dart
程序员老刘5 小时前
为什么暂时不推荐Qwen3-Coder?
flutter·程序员·ai编程
叽哥9 小时前
dart学习第 8 节:面向对象(下)—— 继承与多态
flutter·dart
叽哥9 小时前
dart学习第 6 节:函数进阶 —— 高阶函数与闭包
flutter·dart
叽哥12 小时前
dart学习第 13 节:异步编程基础 —— Future 与 async/await
flutter·dart
xiaoyan201512 小时前
基于flutter3.32+window_manager仿macOS/Wins风格桌面os系统
前端·flutter·dart
叽哥13 小时前
dart学习第 11 节: 空安全(下)—— 安全操作符详解
flutter·dart
weixin_411191841 天前
原生安卓与flutter混编的实现
android·flutter