Touch
Glass that answers a finger — and never moves.
Pass a touch: and the lens becomes a soft body. Press it and it swells under your finger; drag it and it elongates along the pull, pinches in the cross axis, leans after your thumb, then springs back with a wobble.
The lens never moves. Its footprint in layout is unchanged, so nothing around it shifts and no parent relayouts — only its shape and its content deform.
LiquidGlassLens(
touch: const LiquidGlassTouch(
flex: LiquidGlassFlex(),
),
style: const LiquidGlassStyle(
shape: LiquidGlassShape.continuousRoundedRectangle(cornerRadius: 26),
),
child: myContent,
)LiquidGlassTouch is a group, not a single effect: it carries the whole response a surface has to a finger, the way LiquidGlassStyle carries its whole look. Today it holds flex. Anything that lands later lands as a field on the group, not as a new parameter on every component that accepts touch.
Four independent edges#
A scale transform can only grow symmetrically around one anchor. This moves left, right, top and bottom independently, so the half nearest your finger deforms more than the far half — the asymmetry is what reads as soft.
Volume is preserved rather than gained: whatever the pull axis gains, the cross axis gives back, so an elongated lens genuinely gets thinner.
LiquidGlassFlex#
| Knob | Default | What it does |
|---|---|---|
stretch | 13 | Peak elongation along the pull, in px, reached as the drag saturates at maxPull. |
squeeze | 0.70 | How much of the along-axis gain comes back out of the cross axis. 1 preserves area exactly, 0 just grows. |
lean | 0.50 | How far the whole body slides after the finger, as a fraction of stretch. The "it is attached to my thumb" cue. |
grip | 0.70 | How local the deformation is. 0 — every edge shares it equally wherever you touched. 1 — the near edges take all of it. |
compressInward | true | Pushing an edge into the body squashes it. false restores the older behaviour where any pull grew the shape. |
holdScale | 0.030 | Signed size change while the finger is down, as a fraction of the lens. Positive swells, negative yields inward. |
tapScale | 0.020 | One-shot pop fired when a tap completes, so a quick click still reads as a click. |
maxPull | 48 | Drag distance in px at which the deformation saturates. |
lockAxis | null | Constrain deformation to Axis.horizontal or Axis.vertical. |
advanced | LiquidGlassFlexAdvanced() | The set-once knobs. See below. |
Presets#
Three tuned starting points ship alongside the default. The only honest way to choose is to feel them against each other on the same surface.
LiquidGlassFlex() // the default
LiquidGlassFlex.subtle() // barely there
LiquidGlassFlex.pronounced() // loose and rubbery
LiquidGlassFlex.uniform() // ignores where you grabbed itLiquidGlassFlexAdvanced#
Five things you set once and forget. They live behind advanced so they stay out of the way without being out of reach.
| Knob | Default | What it does |
|---|---|---|
childFollow | 1 | How much the child rides the deformation. 1 carries it fully, 0 leaves the content rigid inside moving glass. |
refractionBoost | 0.15 | Extra refraction while pressed — what makes it read as glass being compressed rather than rubber. |
magnificationBoost | 0 | Extra magnification while pressed. |
stiffness | 320 | Spring constant of the edges. |
damping | 24 | Damping while the finger is down. |
releaseDamping | 17 | Damping after release — lower than damping, which is where the wobble comes from. |
Multiple fingers#
A lens is owned by the finger that grabbed it. A second pointer landing on the same lens is ignored until the first lifts, so two thumbs on two lenses each drive their own, and two thumbs on one lens do not fight over it.
Put the gesture inside the lens, not around it#
An InkWell, a GestureDetector, an onTap of any kind — they belong in the lens's child, not wrapped around the lens. Inside, they work exactly as they always do: the lens's own listener is translucent and never enters the gesture arena, so it cannot swallow the taps and drags underneath it, and the glass deforms while your button still fires.
// ✗ wrapped around the lens — the ripple never shows
InkWell(
onTap: doThing,
child: LiquidGlassLens(touch: myTouch, child: myRow),
)
// ✓ inside it — the tap fires, the ink is visible, the glass still flexes
LiquidGlassLens(
touch: myTouch,
child: InkWell(onTap: doThing, child: myRow),
)
Comments
Comments are GitHub Discussions — reply from either place.