InkWell 的改变速度
Posted
技术标签:
【中文标题】InkWell 的改变速度【英文标题】:Changing speed of InkWell 【发布时间】:2018-12-09 10:55:53 【问题描述】:我无法在 Flutter 中复制正常的设置菜单。我正在使用 InkWell 来尝试创建通常在您点击设置选项时出现的飞溅效果。问题在于,与正常情况相比,飞溅效果显得太快了。基本上,我只是想减慢 InkWell 的速度。
【问题讨论】:
我会更改问题的标题,这极具误导性...... ✚1 Inkwell 褪色太快,用户可能不会注意到他们是否进行了正常点击。我的解决方法是让splashColor
更黑。
【参考方案1】:
如果您想要更慢的涟漪效果,则必须将 MaterialApp
主题中的 splashFactory
属性从 InkSplash.splashFactory
(默认)更改为 InkRipple.splashFactory
。 InkRipple 的启动画面看起来更像原生。
【讨论】:
如果正确,Flutter 团队应该替换默认值。 @SacWebDeveloper 我认为这是因为 Flutter 团队的目标是复制 Material Design 而不是原生 android @VadimOsovsky ios 行为怎么样?, ios 不遵循材料设计对吗?那么它如何根据“ios splash”(没有波纹只是突出显示)在 ios 上表现得应该如此?此外,还有更多预定义的 splashFactories 可用吗?除了 InkSplash 和 InkRipple? @MotiBartov 因为颤振不使用本机小部件,而是使用 Skia(颤振的图形引擎)绘制自己的小部件,除非您使用特定于 Cupertino 的小部件,否则它在 ios 和 android 上的行为和外观相同。不,据我所知只有 2 种类型。 @VadimOsovsky 谢谢,你是对的,但 Flutter 确实在某些地方尝试匹配平台行为,例如列表滚动。我所做的是,我创建了自定义 SplashFactory,就像 salihguler 在这里描述的那样,但它不是 InkSplash,而是受到没有涟漪效应的 InkHighlight (api.flutter.dev/flutter/material/InkHighlight-class.html) 的启发,只是突出显示更像“ios”。 【参考方案2】:可以创建您想要的内容,但需要在 InkWell
类下自定义 splashFactory
。
正如您在下面的变量中看到的,这些是私有值,它们不能在类中修改。
const Duration _kUnconfirmedSplashDuration = const Duration(seconds: 1);
const Duration _kSplashFadeDuration = const Duration(milliseconds: 200);
const double _kSplashInitialSize = 0.0; // logical pixels
const double _kSplashConfirmedVelocity = 1.0;
要回答您的问题,是的,您可以做到。我只是复制并粘贴了源代码中的所有内容并更改了动画值。在下面的代码之后,只需在splashFactory
中使用它。
///Part to use within application
new InkWell(
onTap: () ,
splashFactory: CustomSplashFactory(),
child: Container(
padding: EdgeInsets.all(12.0),
child: Text('Flat Button'),
),
//Part to copy from the source code.
const Duration _kUnconfirmedSplashDuration = const Duration(seconds: 10);
const Duration _kSplashFadeDuration = const Duration(seconds: 2);
const double _kSplashInitialSize = 0.0; // logical pixels
const double _kSplashConfirmedVelocity = 0.1;
class CustomSplashFactory extends InteractiveInkFeatureFactory
const CustomSplashFactory();
@override
InteractiveInkFeature create(
@required MaterialInkController controller,
@required RenderBox referenceBox,
@required Offset position,
@required Color color,
bool containedInkWell = false,
RectCallback rectCallback,
BorderRadius borderRadius,
double radius,
VoidCallback onRemoved,
)
return new CustomSplash(
controller: controller,
referenceBox: referenceBox,
position: position,
color: color,
containedInkWell: containedInkWell,
rectCallback: rectCallback,
borderRadius: borderRadius,
radius: radius,
onRemoved: onRemoved,
);
class CustomSplash extends InteractiveInkFeature
/// Used to specify this type of ink splash for an [InkWell], [InkResponse]
/// or material [Theme].
static const InteractiveInkFeatureFactory splashFactory = const CustomSplashFactory();
/// Begin a splash, centered at position relative to [referenceBox].
///
/// The [controller] argument is typically obtained via
/// `Material.of(context)`.
///
/// If `containedInkWell` is true, then the splash will be sized to fit
/// the well rectangle, then clipped to it when drawn. The well
/// rectangle is the box returned by `rectCallback`, if provided, or
/// otherwise is the bounds of the [referenceBox].
///
/// If `containedInkWell` is false, then `rectCallback` should be null.
/// The ink splash is clipped only to the edges of the [Material].
/// This is the default.
///
/// When the splash is removed, `onRemoved` will be called.
CustomSplash(
@required MaterialInkController controller,
@required RenderBox referenceBox,
Offset position,
Color color,
bool containedInkWell = false,
RectCallback rectCallback,
BorderRadius borderRadius,
double radius,
VoidCallback onRemoved,
) : _position = position,
_borderRadius = borderRadius ?? BorderRadius.zero,
_targetRadius = radius ?? _getTargetRadius(referenceBox, containedInkWell, rectCallback, position),
_clipCallback = _getClipCallback(referenceBox, containedInkWell, rectCallback),
_repositionToReferenceBox = !containedInkWell,
super(controller: controller, referenceBox: referenceBox, color: color, onRemoved: onRemoved)
assert(_borderRadius != null);
_radiusController = new AnimationController(duration: _kUnconfirmedSplashDuration, vsync: controller.vsync)
..addListener(controller.markNeedsPaint)
..forward();
_radius = new Tween<double>(
begin: _kSplashInitialSize,
end: _targetRadius
).animate(_radiusController);
_alphaController = new AnimationController(duration: _kSplashFadeDuration, vsync: controller.vsync)
..addListener(controller.markNeedsPaint)
..addStatusListener(_handleAlphaStatusChanged);
_alpha = new IntTween(
begin: color.alpha,
end: 0
).animate(_alphaController);
controller.addInkFeature(this);
final Offset _position;
final BorderRadius _borderRadius;
final double _targetRadius;
final RectCallback _clipCallback;
final bool _repositionToReferenceBox;
Animation<double> _radius;
AnimationController _radiusController;
Animation<int> _alpha;
AnimationController _alphaController;
@override
void confirm()
final int duration = (_targetRadius / _kSplashConfirmedVelocity).floor();
_radiusController
..duration = new Duration(milliseconds: duration)
..forward();
_alphaController.forward();
@override
void cancel()
_alphaController?.forward();
void _handleAlphaStatusChanged(AnimationStatus status)
if (status == AnimationStatus.completed)
dispose();
@override
void dispose()
_radiusController.dispose();
_alphaController.dispose();
_alphaController = null;
super.dispose();
RRect _clipRRectFromRect(Rect rect)
return new RRect.fromRectAndCorners(
rect,
topLeft: _borderRadius.topLeft, topRight: _borderRadius.topRight,
bottomLeft: _borderRadius.bottomLeft, bottomRight: _borderRadius.bottomRight,
);
void _clipCanvasWithRect(Canvas canvas, Rect rect, Offset offset)
Rect clipRect = rect;
if (offset != null)
clipRect = clipRect.shift(offset);
if (_borderRadius != BorderRadius.zero)
canvas.clipRRect(_clipRRectFromRect(clipRect));
else
canvas.clipRect(clipRect);
@override
void paintFeature(Canvas canvas, Matrix4 transform)
final Paint paint = new Paint()..color = color.withAlpha(_alpha.value);
Offset center = _position;
if (_repositionToReferenceBox)
center = Offset.lerp(center, referenceBox.size.center(Offset.zero), _radiusController.value);
final Offset originOffset = MatrixUtils.getAsTranslation(transform);
if (originOffset == null)
canvas.save();
canvas.transform(transform.storage);
if (_clipCallback != null)
_clipCanvasWithRect(canvas, _clipCallback());
canvas.drawCircle(center, _radius.value, paint);
canvas.restore();
else
if (_clipCallback != null)
canvas.save();
_clipCanvasWithRect(canvas, _clipCallback(), offset: originOffset);
canvas.drawCircle(center + originOffset, _radius.value, paint);
if (_clipCallback != null)
canvas.restore();
double _getTargetRadius(RenderBox referenceBox, bool containedInkWell, RectCallback rectCallback, Offset position)
if (containedInkWell)
final Size size = rectCallback != null ? rectCallback().size : referenceBox.size;
return _getSplashRadiusForPositionInSize(size, position);
return Material.defaultSplashRadius;
double _getSplashRadiusForPositionInSize(Size bounds, Offset position)
final double d1 = (position - bounds.topLeft(Offset.zero)).distance;
final double d2 = (position - bounds.topRight(Offset.zero)).distance;
final double d3 = (position - bounds.bottomLeft(Offset.zero)).distance;
final double d4 = (position - bounds.bottomRight(Offset.zero)).distance;
return math.max(math.max(d1, d2), math.max(d3, d4)).ceilToDouble();
RectCallback _getClipCallback(RenderBox referenceBox, bool containedInkWell, RectCallback rectCallback)
if (rectCallback != null)
assert(containedInkWell);
return rectCallback;
if (containedInkWell)
return () => Offset.zero & referenceBox.size;
return null;
【讨论】:
有没有办法改变 InkHighlight 消失的速度? 如果您在尝试实现此功能后遇到错误,您需要首先import 'package:flutter/material.dart';
和 import 'dart:math' as math;
然后在您的 InteractiveInkFeature create
覆盖添加 @required TextDirection textDirection
和 ShapeBorder customBorder
以上是关于InkWell 的改变速度的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 中的 Inkwell 小部件中添加边框半径