Add linear and radial gradients for shape fills - #123
Conversation
|
Will add iOS impl before merging the PR |
🎉 Bazel & CI Test Results
All Bazel configuration and CI tests passed! ✨ The build system and core tooling are working correctly. 🚀 Bazel remote cache is now enabled - future builds will be faster! Workflow: Valdi CI |
| view.resetFillGradient() | ||
| } else if (valdiGradient.colors.size == 1) { | ||
| view.resetFillGradient() | ||
| view.setFillColor(valdiGradient.colors[0]) |
There was a problem hiding this comment.
Seems like the one-color path replaces the shape's stored fillColor. Android calls setFillColor() here, while iOS similarly assigns the gradient color to _fillColor. When the gradient is removed, the reset path restores the gradient color rather than the original bound fill color.
tested this by starting with fillColor="green", applying a one-color red gradient, and then removing the gradient. The shape stayed red on both Android and iOS. Just wanted to double check if that was intended
| ) | ||
| } | ||
| GradientDrawable.RADIAL_GRADIENT -> { | ||
| fillPaint.shader = RadialGradient( |
There was a problem hiding this comment.
When either shape dimension is zero, the calculated radius is also zero. Android's RadialGradient requires a radius greater than zero, so constructing the shader in that state crashes.
I double-checked this by changing the shape's width and height to zero independently. Android crashed in both cases, but iOS handled them.
Since zero bounds can occur temporarily during layout, could we skip creating the shader until valid bounds return?
| fillPaint.shader = RadialGradient( | ||
| fillGradientBounds.centerX(), | ||
| fillGradientBounds.centerY(), | ||
| min(fillGradientBounds.width(), fillGradientBounds.height()) / 2.0f, |
There was a problem hiding this comment.
It looks like Android calculates one circular radius using min(width, height) / 2, while iOS and SnapDrawing scale the radial gradient with the non-square bounds. This seems to produce different results for rectangular shapes. Tested the same red-to-blue gradient in a 2:1 shape. Android rendered a circle, while iOS and SnapDrawing rendered an ellipse.
Is the Android-specific behavior intentional? If not, could we align it with the other backends and add a non-square radial test?
| auto fillPaint = _fillPaint; | ||
| if (_fillGradientWrapper.hasGradient()) { | ||
| fillPaint.setColor(Color::black()); | ||
| _fillGradientWrapper.update(path.getBounds().value_or(drawingContext.drawBounds())); |
There was a problem hiding this comment.
It looks like SnapDrawing sizes the gradient using the path bounds, while Android and iOS use the full shape layer. This can produce different results when the path does not occupy the complete layer.
I double-checked with a 120×100 layer whose path only occupies the top half. The Android and iOS versions ended around purple, while SnapDrawing reached blue.
Is the path-relative behavior expected here? If not, would using the drawing/layer bounds make the backends more consistent?
Description
This change adds support for fillGradient on the shape element.
Type of Change
Testing
bazel test //...)Testing Details
Checklist
Related Issues
Additional Context