drip_flutter 0.5.1-alpha
drip_flutter: ^0.5.1-alpha copied to clipboard
Flutter render layer for DRIP — direct RenderObject binding with zero widget rebuilds.
drip_flutter #
Flutter render layer for the DRIP framework.
Provides direct RenderObject bindings that update the UI with zero widget rebuilds, a scoped business-logic architecture via DripNode, and a high-performance reactive list via DripList.
⚠️ Early Alpha: APIs are stable within the alpha series but subject to change before v1.0.0.
Features #
- Zero Rebuilds — State changes call
markNeedsPaint()/markNeedsLayout()directly onRenderObjects, bypassing the Widget → Element → RenderObject traversal entirely. - Reactive Builder Widgets — Scoped, optimized builders (
DripBuilder,DripSelect,DripAsyncBuilder) for complex UI updates when rebuilding widgets is necessary. DripReadable<T>binding — All render widgets accept bothDripState<T>andDripComputed<T>via the sharedDripReadable<T>interface.DripLifecycle&DripNode— Explicit, context-free management of business logic modules. NoInheritedWidgetmagic.DripSemantics— Full accessibility support with zero-rebuild reactivity.
Render Widgets #
| Widget | Bound Property | RenderObject call |
|---|---|---|
DripText |
DripValue<String> |
markNeedsLayout() |
DripOpacity |
DripValue<double> |
markNeedsPaint() |
DripColor |
DripValue<Color> |
markNeedsPaint() |
DripTransform |
DripValue<Matrix4> |
markNeedsPaint() |
DripImage |
DripValue<ImageProvider> |
async image resolution |
DripCustomBinding<T> |
any | developer-defined |
Builder Widgets #
When you need to rebuild a subtree conditionally or construct new widgets, use DRIP's reactive builders:
| Widget | Purpose |
|---|---|
DripBuilder<T> |
Rebuilds its subtree whenever the bound DripReadable<T> changes. |
DripSelect |
Combines multiple sources via an internal DripComputed and rebuilds only when the evaluated combination changes. |
DripAsyncBuilder<T> |
Handles exhaustive sealed-class state rendering for DripAsync<T> (loading, data, error), automatically passing previousData to handlers. |
Usage #
1. Zero-rebuild UI #
import 'package:drip_flutter/drip_flutter.dart';
final label = dripState('Hello');
final opacity = DripComputed(() => label.value.isEmpty ? 0.0 : 1.0);
// In build() — no setState ever:
Column(children: [
DripText(label, style: TextStyle(fontSize: 24)),
DripOpacity(opacity: opacity, child: Text('visible!')),
])
// Anywhere in business logic:
label.write('World'); // → 0 widget builds
2. Business logic with DripNode #
class CounterNode extends DripNode {
late final DripState<int> count;
late final DripComputed<String> displayText;
late final DripComputed<double> opacity;
@override
void onInit() {
count = state(0);
displayText = computed(() => count.value.toString());
opacity = computed(() => count.value == 0 ? 0.4 : 1.0);
}
void increment() => count.write(count.value + 1);
void decrement() => count.write(count.value - 1);
}
Provide and consume (Context-Free):
// Explicit dependency injection via constructor
DripLifecycle<CounterNode>(
create: () => CounterNode(),
child: DripBuilder<CounterNode>(
builder: (context, node) => Column(children: [
DripText(node.displayText),
DripOpacity(opacity: node.opacity, child: ElevatedButton(
onPressed: node.increment,
child: Icon(Icons.add),
)),
]),
),
)
3. Accessibility with DripSemantics #
DripSemantics<int>(
value: node.count,
label: (value) => "Current count is $value",
child: DripText(node.displayText),
)
4. Reactive Lists #
For lists, use standard ListView.builder combined with DripBuilder for item-level granularity, or use the legacy DripList (deprecated) for O(1) tile updates.
Architecture Invariants #
- Zero
setState(): NosetState()calls exist in the binding code path.DripFrameis the sole intentional exception, explicitly documented. - Binding Lifecycle: All bindings are synchronously deregistered in
didUnmountRenderObject— zero subscriber leaks. - Context Correctness:
DripNodeProviderwraps the builder child in aBuilder, ensuringcontext.node<N>()resolves from a context below theInheritedWidget.
Benchmarking #
Run the demo_grid app in profile mode to observe the zero-rebuild guarantee:
cd apps/demo_grid
flutter run --profile
Open Flutter DevTools → Performance → Track Widget Builds: 1,000 DripText cells update every 16 ms — widget build count stays at 0.
Installation #
dependencies:
drip_flutter: ^0.5.1-alpha
Requires Flutter >=3.27.0.
Part of the DRIP Framework.