项目中或许会对水印进行运用偏移作用,为此针对水印自绘再进行一次优化。

计划1:

依据上文中界说的TextWaterMarkPainter的padding进行设置.
运用示例:

class TestTextWaterState extends State<TestTextWater>{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: const Text("SSL Water Mark"),
      ),
      body:
        Stack(
          children: [
            Center(
              child: ElevatedButton(onPressed: (){
                debugPrint("Chick Button");
              }, child: const Text("Chick Button")
              ),
            ),
            IgnorePointer(
              child: SSLWaterMark(
                painter: TextWaterMarkPainter(
                  text: "SSL white monkey",
                  textStyle: const TextStyle(color: Colors.purple,fontSize: 5),
                  padding: const EdgeInsets.only(right: 50),
                  rotate: -10
                ),
                repeat: ImageRepeat.repeat,
              )
            ),
          ],
        ),
    );
  }
}

作用:

Flutter-水印偏移
能够看到,偏移是偏移了,可是最左边的并没有开端偏移,并没有到达全体偏移的作用。

计划2

运用Transform组件对Widget进行偏移。
修正代码:

IgnorePointer(
  child: Transform.translate(
    offset: const Offset(- 50,0),
    child: SSLWaterMark(
      painter: TextWaterMarkPainter(
          text: "SSL white monkey",
          textStyle: const TextStyle(color: Colors.purple,fontSize: 5),
          // padding: const EdgeInsets.only(right: 50),
          rotate: -10
      ),
      repeat: ImageRepeat.repeat,
    ),
  ),
),

作用:

Flutter-水印偏移
全体上是到达了偏移作用,可是最右边出现了空白,作用仍旧有所短缺。原因是WaterMark占用空间原本和屏幕等宽,所以制作时的区域也就和屏幕相同大,而Transform.translate的作用适当所以在制作时将制作点做平移了50dpt,所以右边出现了空白。

假如这样的话,那假如让WaterMark的制作区域超越屏幕宽度30像素,平移后是不是就能够了,理论上应该可行,可是WaterMark时经过DecoratedBox去制作背景,我们不能去修正DecoratedBox的制作逻辑,所以计划不可取。

计划3:

运用可翻滚组件加大运用偏移区。
大多数组件的制作区和本身布局巨细是相同的,那么强制让WaterMark的宽度超出屏幕宽度50dpt是不是也能够?理论上似乎可行,翻滚组件的原理就是这样完成的,那么必定有一个办法能强制指定WaterMark的宽度比屏幕宽度大50,然后用SingleChildScrollView包裹:

IgnorePointer(
  child: LayoutBuilder(builder: (context, constraints){
   return SingleChildScrollView(
     scrollDirection: Axis.horizontal,
     child: Transform.translate(
       offset: const Offset(- 50,0),
       child: SizedBox(
         width: constraints.maxWidth + 50,
         height: constraints.maxHeight,
         child: SSLWaterMark(
           painter: TextWaterMarkPainter(
               text: "SSL white monkey",
               textStyle: const TextStyle(color: Colors.purple,fontSize: 5),
               // padding: const EdgeInsets.only(right: 50),
               rotate: -10
           ),
           repeat: ImageRepeat.repeat,
         ),
       )
     ),
   );
  },
  )
),

Flutter-水印偏移
能够看到基本上完成了我们的期望作用。需求注意的是由于SingleChildScrollView被IgnorePointer包裹,所以它不能接纳事情,不会受用户滑动。

缺陷:SingleChildScrollView内部需求创立Scrollable和Viewport目标,在这个场景下SingleChildScrollView是不会响应事情的,创立Scrollable属于多余的开支。

计划4:

先经过UnconstrainedBox撤销组件对子组件巨细的束缚,然后经过SizedBox指定WaterMark宽比屏幕长30来完成。

IgnorePointer(
  child: LayoutBuilder(builder: (context, constraints){
      return UnconstrainedBox(
        alignment: Alignment.topRight,
        child: SizedBox(
          width: constraints.maxWidth + 30,
          height: constraints.maxHeight,
          child: SSLWaterMark(
            painter: TextWaterMarkPainter(
                text: "SSL white monkey",
                textStyle: const TextStyle(color: Colors.purple,fontSize: 5),
                // padding: const EdgeInsets.only(right: 50),
                rotate: -10
            ),
            repeat: ImageRepeat.repeat,
          ),
        ),
      );
  },
  )
),

作用:

Flutter-水印偏移

控制台提示:A RenderConstraintsTransformBox overflowed by 30 pixels on the left.

左边出现了溢出提示条,这是由于UnconstrainedBox虽然其子组件布局时能够撤销束缚(子组件能够为无限大),可是UnconstrainedBox本身是受其父组件束缚的,所以当UnconstrainedBox随其子组件变大后,假如UnconstrainedBox的巨细超越其父组件巨细时,就会导致溢出。
假如没有溢出,作用就现已失效了,超出的宽度就会在父组件的左鸿沟之外,从而就完成了期望的作用,大家需求注意的是在Release形式下是不会有制作溢出提示条的,溢出条制作逻辑是在assert函数中,比如:

// Display the overflow indicator.
assert(() {
  paintOverflowIndicator(context, offset, _overflowContainerRect, _overflowChildRect);
  return true;
}());

所以在Release形式下上面的代码也能够完成预期的作用,可是应该遵守代码规矩,不应该运用这种办法。已然有提示,则代表UnconstrainedBox子元素溢出不是预期的行为。
处理思路:在撤销束缚的一起不要让组件巨细超出父组件的空间即可。之前有运用FittedBox,它能够撤销父组件对子组件的束缚并一起让其子组件适配FittedBox父组件的巨细,正契合我们的需求。

计划5:

IgnorePointer(
  child: LayoutBuilder(builder: (context, constraints){
    return FittedBox(
      alignment: Alignment.topRight,
      fit: BoxFit.none,
      child: SizedBox(
        width: constraints.maxWidth + 50,
        height: constraints.maxHeight,
        child: SSLWaterMark(
          painter: TextWaterMarkPainter(
              text: "SSL white monkey",
              textStyle: const TextStyle(color: Colors.purple,fontSize: 5),
              // padding: const EdgeInsets.only(right: 50),
              rotate: -10
          ),
          repeat: ImageRepeat.repeat,
        ),
      ),
    );
    },
  )
),

作用:

Flutter-水印偏移
能够看到作用现已到达预期,且没有任何溢出提示。可是FittedBox的主要运用场景是对子组件进行一些缩放、拉伸等以适配父组件的空间,而本例中并没有用到这个功能,适配方法指定的:BoxFit.none,还是有点杀鸡用牛刀。

计划6:

运用OverflowBox来运用偏移。
OverflowBox和UnconstrainedBox相同的是能够撤销父组件对子组件的束缚,但不同的是OverflowBox本身的巨细不会随子组件巨细而改变,它的巨细只取决于其父组件的束缚(束缚为constraints.binggest),即在满足父组件束缚的前提下会尽或许的大。封装一个TrabslateWithExpandedPaintingArea组件来包裹WaterMark组件:

class SSLTranslateWithExpandedPaintingArea extends StatelessWidget{
  final Widget? child;
  final Offset offset;
  final Clip clipBehavior;
  const SSLTranslateWithExpandedPaintingArea({
    Key? key,
    required this.offset,
    this.clipBehavior = Clip.none,
    this.child
  }):super(key: key);
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return LayoutBuilder(
        builder: (context, constraints){
          final dx = offset.dx.abs();
          final dy = offset.dy.abs();
          Widget widget = OverflowBox(
            //平移多少,则子组件相应轴的长度添加多少
            minWidth: constraints.minWidth + dx,
            minHeight: constraints.minHeight + dy,
            maxWidth: constraints.maxWidth + dx,
            maxHeight: constraints.maxHeight + dy,
            alignment: Alignment(
              //不同方向的平移,要指定不同的对其方法
              offset.dx <= 0 ? 1 : -1,
              offset.dy <= 0 ? 1 : -1,
            ),
            child: child,
          );
          if (clipBehavior != Clip.none){
            widget = ClipRect(clipBehavior: clipBehavior, child: widget,);
          }
          return widget;
        }
    );
  }
}

需求注意:

  • 会依据用户指定的偏移来动态给子组件宽高添加对应的值
  • 需求依据用户指定的偏移来动态调整OverflowBox的对齐方法,比如要向左平移时,OverflowBox就必须右对齐,由于右对齐超出父容器部分会在左鸿沟之外。
  • 超出鸿沟之外的内容默认会显现,测验中水印组件巨细和屏幕剩下显现空间相同大,所以超出会不会显现,可是假如水印指定小于屏幕巨细的尺寸,就能够看到超出之后的内容,因此,界说了一个裁剪的装备参数,能够依据实际情况决议是否进行裁剪。

测验:

IgnorePointer(
  child: LayoutBuilder(builder: (context, constraints){
    return SSLTranslateWithExpandedPaintingArea(
      offset: const Offset(-50,0),
      child: SSLWaterMark(
        painter: TextWaterMarkPainter(
            text: "SSL white monkey",
            textStyle: const TextStyle(color: Colors.purple,fontSize: 5),
            // padding: const EdgeInsets.only(right: 50),
            rotate: -10
        ),
        repeat: ImageRepeat.repeat,
      ),
    );
  },
 )
),

作用

Flutter-水印偏移

能够看到作用到达了预期,而且也没有额定的开支。应该是比较抱负的计划。

总结

  1. 计划1是基础的作用,并不抱负;计划3和5虽然都能到达抱负的作用,可是却随同额定的开支;计划6是作用的最佳答案。
  2. 经过这些尝试,也能更进一步了解FittedBox、SingleChileScrollView、UnconstrainedBox、OverflowBox的各个特点,巩固所学常识。