You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现可拖拽纹身图与手臂图叠加并隐藏超出边缘部分

实现方案

以下是基于你提供的代码,实现纹身叠加和拖拽控制的完整解决方案:

修改后的完整代码

class _MyHomePageState extends State<MyHomePage> {
  Offset imageOffset = Offset(0.0, 0.0); // 纹身初始偏移量
  double imageSize = 100.0; // 纹身尺寸(可调整)
  bool _isDraggable = true; // 控制拖拽与遮罩效果的开关状态

  @override
  Widget build(BuildContext context) {
    // 提取容器与手臂图的固定尺寸、位置,确保遮罩对齐
    final parentWidth = MediaQuery.of(context).size.width * 0.80;
    final parentHeight = MediaQuery.of(context).size.height * 0.45;
    final armWidth = MediaQuery.of(context).size.width * .60;
    final armHeight = MediaQuery.of(context).size.height * .30;
    final armLeft = (parentWidth - armWidth) / 2;
    final armTop = (parentHeight - armHeight) / 2;

    return Scaffold(
      appBar: AppBar(
        title: const Text('纹身叠加模拟器'),
        actions: [
          // 拖拽控制开关
          Switch(
            value: _isDraggable,
            onChanged: (value) => setState(() => _isDraggable = value),
            activeColor: Colors.orange,
          ),
        ],
      ),
      body: Center(
        child: Container(
          height: parentHeight,
          width: parentWidth,
          child: Stack(
            children: [
              // 黑色背景容器
              Container(
                height: parentHeight,
                width: parentWidth,
                decoration: BoxDecoration(
                  color: Colors.black,
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              // 固定显示的手臂图片
              Positioned(
                left: armLeft,
                top: armTop,
                child: Image.asset(
                  'assets/Images/arm.png',
                  height: armHeight,
                  width: armWidth,
                  fit: BoxFit.contain,
                ),
              ),
              // 可拖拽/带遮罩的纹身图片
              Positioned(
                left: imageOffset.dx,
                top: imageOffset.dy,
                child: GestureDetector(
                  // 仅在开启状态下允许拖拽
                  onPanUpdate: _isDraggable
                      ? (details) {
                          setState(() {
                            // 更新纹身位置,限制在容器边界内
                            imageOffset = Offset(
                              (imageOffset.dx + details.delta.dx).clamp(
                                  0.0, parentWidth - imageSize),
                              (imageOffset.dy + details.delta.dy).clamp(
                                  0.0, parentHeight - imageSize),
                            );
                          });
                        }
                      : null,
                  child: _isDraggable
                      ? // 开启拖拽时,直接显示完整纹身
                      Image.asset(
                          'assets/Images/Tattoo.png',
                          height: imageSize,
                          width: imageSize,
                          color: Colors.orange,
                          fit: BoxFit.cover,
                        )
                      : // 关闭拖拽时,用手臂图作为遮罩,仅显示重叠区域
                      ShaderMask(
                          shaderCallback: (bounds) {
                            return ImageShader(
                              AssetImage('assets/Images/arm.png'),
                              TileMode.clamp,
                              TileMode.clamp,
                              // 调整遮罩位置,与手臂图完全对齐
                              Matrix4.identity()
                                  .translate(-armLeft, -armTop)
                                  .storage,
                            );
                          },
                          // 混合模式:仅保留遮罩不透明区域的纹身内容
                          blendMode: BlendMode.dstIn,
                          child: Image.asset(
                            'assets/Images/Tattoo.png',
                            height: imageSize,
                            width: imageSize,
                            color: Colors.orange,
                            fit: BoxFit.cover,
                          ),
                        ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

关键功能说明

  • 拖拽控制开关:AppBar右侧的Switch按钮,切换_isDraggable状态,控制纹身是否可拖拽。
  • 边界限制:拖拽时通过clamp方法限制纹身位置,确保不会超出黑色容器边界。
  • 遮罩效果实现:
    • 关闭拖拽时,使用ShaderMask将手臂图作为遮罩层
    • 通过BlendMode.dstIn混合模式,只显示纹身与手臂图重叠的不透明部分,模拟真实纹身贴附效果
    • Matrix4.translate调整遮罩位置,确保与界面上显示的手臂图完全对齐,避免错位

内容的提问来源于stack exchange,提问作者Hassnain Nisar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 13:20:05