Commit 921d4320 authored by Hans Muller's avatar Hans Muller

Added Painter, ScrollingListPainter, MaterialScrollbarPainter

Enabled displaying a scrollbar in ScrollingLists. The scrollbar is painted as an "overlay", i.e. it's painted on top of the scrolling list's visible children.

Added an abstract Painter base class that encapsulates a paint method and the renderer that it's attached to. RenderBlockViewport and HomogenousViewport now support an overlayPainter property. If specified, RenderBlockViewport attaches itself to the overlayPainter when it's attached to the rendering tree. RenderBlockViewport now calls overlayPainter.paint() after it has painted its children.

Added an abstract ScrollingListPainter class that exposes ScrollingList's state which might be needed for painting. Like its scroll direction and scrollOffset. The ScrollingListPainter is notified when a scroll starts and ends.

Defined a Material-specific ScrollingListPainter that renders a scrollbar. The scrollbar thumb is faded in/out when the scroll starts/ends.

Added onScrollStart and onScrollEnd listeners to Scrollable.
parent faa7f818
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
class ScrollbarApp extends StatefulComponent {
ScrollbarApp({ this.navigator });
final NavigatorState navigator;
ScrollbarAppState createState() => new ScrollbarAppState();
}
class ScrollbarAppState extends State<ScrollbarApp> {
final int _itemCount = 20;
final double _itemExtent = 50.0;
final ScrollbarPainter _scrollbarPainter = new ScrollbarPainter();
Widget _buildMenu(BuildContext context) {
NumberFormat dd = new NumberFormat("00", "en_US");
return new ScrollableList<int>(
items: new List<int>.generate(_itemCount, (int i) => i),
itemExtent: _itemExtent,
itemBuilder: (BuildContext _, int i) => new Text('Item ${dd.format(i)}', style: Theme.of(context).text.title),
scrollableListPainter: _scrollbarPainter
);
}
Widget build(BuildContext context) {
Widget scrollable = new Container(
margin: new EdgeDims.symmetric(horizontal: 6.0), // TODO(hansmuller) 6.0 should be based on _kScrollbarThumbWidth
child: new Center(
shrinkWrap: ShrinkWrap.both,
child: new Container(
width: 80.0,
height: _itemExtent * 5.0,
child: _buildMenu(context)
)
)
);
return new Scaffold(
toolBar: new ToolBar(center: new Text('Scrollbar Demo')),
body: new Container(
decoration: new BoxDecoration(backgroundColor: Theme.of(context).primarySwatch[50]),
padding: new EdgeDims.all(12.0),
child: new Center(child: new Card(child: scrollable))
)
);
}
}
void main() {
runApp(new MaterialApp(
title: 'ScrollbarApp',
theme: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Colors.blue,
accentColor: Colors.redAccent[200]
),
routes: {
'/': (RouteArguments args) => new ScrollbarApp(navigator: args.navigator),
}
));
}
...@@ -33,6 +33,7 @@ export 'src/material/progress_indicator.dart'; ...@@ -33,6 +33,7 @@ export 'src/material/progress_indicator.dart';
export 'src/material/radio.dart'; export 'src/material/radio.dart';
export 'src/material/raised_button.dart'; export 'src/material/raised_button.dart';
export 'src/material/scaffold.dart'; export 'src/material/scaffold.dart';
export 'src/material/scrollbar_painter.dart';
export 'src/material/shadows.dart'; export 'src/material/shadows.dart';
export 'src/material/snack_bar.dart'; export 'src/material/snack_bar.dart';
export 'src/material/switch.dart'; export 'src/material/switch.dart';
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
const double _kMinScrollbarThumbLength = 18.0;
const double _kScrollbarThumbGirth = 6.0;
const Duration _kScrollbarThumbFadeDuration = const Duration(milliseconds: 300);
class ScrollbarPainter extends ScrollableListPainter {
double _opacity = 0.0;
int get _alpha => (_opacity * 0xFF).round();
// TODO(hansmuller): thumb color should come from ThemeData.
Color get thumbColor => const Color(0xFF9E9E9E);
void paintThumb(PaintingContext context, Rect thumbBounds) {
final Paint paint = new Paint()..color = thumbColor.withAlpha(_alpha);
context.canvas.drawRect(thumbBounds, paint);
}
void paintScrollbar(PaintingContext context, Offset offset) {
final Rect viewportBounds = offset & viewportSize;
Point thumbOrigin;
Size thumbSize;
if (isVertical) {
double thumbHeight = viewportBounds.height * viewportBounds.height / contentExtent;
thumbHeight = thumbHeight.clamp(_kMinScrollbarThumbLength, viewportBounds.height);
final double maxThumbTop = viewportBounds.height - thumbHeight;
double thumbTop = (scrollOffset / (contentExtent - viewportBounds.height)) * maxThumbTop;
thumbTop = viewportBounds.top + thumbTop.clamp(0.0, maxThumbTop);
thumbOrigin = new Point(viewportBounds.right - _kScrollbarThumbGirth, thumbTop);
thumbSize = new Size(_kScrollbarThumbGirth, thumbHeight);
} else {
double thumbWidth = viewportBounds.width * viewportBounds.width / contentExtent;
thumbWidth = thumbWidth.clamp(_kMinScrollbarThumbLength, viewportBounds.width);
final double maxThumbLeft = viewportBounds.width - thumbWidth;
double thumbLeft = (scrollOffset / (contentExtent - viewportBounds.width)) * maxThumbLeft;
thumbLeft = viewportBounds.left + thumbLeft.clamp(0.0, maxThumbLeft);
thumbOrigin = new Point(thumbLeft, viewportBounds.height - _kScrollbarThumbGirth);
thumbSize = new Size(thumbWidth, _kScrollbarThumbGirth);
}
paintThumb(context, thumbOrigin & thumbSize);
}
void paint(PaintingContext context, Offset offset) {
if (_alpha == 0)
return;
paintScrollbar(context, offset);
}
ValuePerformance<double> _fade;
Future scrollStarted() {
_fade ??= new ValuePerformance<double>()
..duration = _kScrollbarThumbFadeDuration
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease)
..addListener(() {
_opacity = _fade.value;
renderer?.markNeedsPaint();
});
return _fade.forward();
}
Future scrollEnded() {
return _fade.reverse();
}
void detach() {
super.detach();
_fade?.stop();
}
}
...@@ -237,6 +237,7 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -237,6 +237,7 @@ class RenderBlockViewport extends RenderBlockBase {
ExtentCallback totalExtentCallback, ExtentCallback totalExtentCallback,
ExtentCallback maxCrossAxisDimensionCallback, ExtentCallback maxCrossAxisDimensionCallback,
ExtentCallback minCrossAxisDimensionCallback, ExtentCallback minCrossAxisDimensionCallback,
Painter overlayPainter,
BlockDirection direction: BlockDirection.vertical, BlockDirection direction: BlockDirection.vertical,
double itemExtent, double itemExtent,
double minExtent: 0.0, double minExtent: 0.0,
...@@ -246,6 +247,7 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -246,6 +247,7 @@ class RenderBlockViewport extends RenderBlockBase {
_totalExtentCallback = totalExtentCallback, _totalExtentCallback = totalExtentCallback,
_maxCrossAxisExtentCallback = maxCrossAxisDimensionCallback, _maxCrossAxisExtentCallback = maxCrossAxisDimensionCallback,
_minCrossAxisExtentCallback = minCrossAxisDimensionCallback, _minCrossAxisExtentCallback = minCrossAxisDimensionCallback,
_overlayPainter = overlayPainter,
_startOffset = startOffset, _startOffset = startOffset,
super(children: children, direction: direction, itemExtent: itemExtent, minExtent: minExtent); super(children: children, direction: direction, itemExtent: itemExtent, minExtent: minExtent);
...@@ -298,6 +300,27 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -298,6 +300,27 @@ class RenderBlockViewport extends RenderBlockBase {
markNeedsLayout(); markNeedsLayout();
} }
Painter get overlayPainter => _overlayPainter;
Painter _overlayPainter;
void set overlayPainter(Painter value) {
if (_overlayPainter == value)
return;
_overlayPainter?.detach();
_overlayPainter = value;
_overlayPainter?.attach(this);
markNeedsPaint();
}
void attach() {
super.attach();
_overlayPainter?.attach(this);
}
void detach() {
super.detach();
_overlayPainter?.detach();
}
/// The offset at which to paint the first child /// The offset at which to paint the first child
/// ///
/// Note: you can modify this property from within [callback], if necessary. /// Note: you can modify this property from within [callback], if necessary.
...@@ -377,11 +400,15 @@ class RenderBlockViewport extends RenderBlockBase { ...@@ -377,11 +400,15 @@ class RenderBlockViewport extends RenderBlockBase {
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
context.canvas.save(); context.canvas.save();
context.canvas.clipRect(offset & size); context.canvas.clipRect(offset & size);
if (isVertical) if (isVertical)
defaultPaint(context, offset.translate(0.0, startOffset)); defaultPaint(context, offset.translate(0.0, startOffset));
else else
defaultPaint(context, offset.translate(startOffset, 0.0)); defaultPaint(context, offset.translate(startOffset, 0.0));
overlayPainter?.paint(context, offset);
context.canvas.restore(); context.canvas.restore();
} }
......
...@@ -394,6 +394,27 @@ class PaintingContext { ...@@ -394,6 +394,27 @@ class PaintingContext {
} }
/// An encapsulation of a renderer and a paint() method.
///
/// A renderer may allow its paint() method to be augmented or redefined by
/// providing a Painter. See for example overlayPainter in BlockViewport.
abstract class Painter {
RenderObject get renderObject => _renderObject;
RenderObject _renderObject;
void attach(RenderObject renderObject) {
assert(_renderObject == null);
_renderObject = renderObject;
}
void detach() {
assert(_renderObject != null);
_renderObject = null;
}
void paint(PaintingContext context, Offset offset);
}
/// An abstract set of layout constraints /// An abstract set of layout constraints
/// ///
/// Concrete layout models (such as box) will create concrete subclasses to /// Concrete layout models (such as box) will create concrete subclasses to
......
...@@ -18,7 +18,8 @@ class HomogeneousViewport extends RenderObjectWidget { ...@@ -18,7 +18,8 @@ class HomogeneousViewport extends RenderObjectWidget {
this.itemExtent, // required this.itemExtent, // required
this.itemCount, // optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it this.itemCount, // optional, but you cannot shrink-wrap this class or otherwise use its intrinsic dimensions if you don't specify it
this.direction: ScrollDirection.vertical, this.direction: ScrollDirection.vertical,
this.startOffset: 0.0 this.startOffset: 0.0,
this.overlayPainter
}) : super(key: key) { }) : super(key: key) {
assert(itemExtent != null); assert(itemExtent != null);
} }
...@@ -29,6 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget { ...@@ -29,6 +30,7 @@ class HomogeneousViewport extends RenderObjectWidget {
final int itemCount; final int itemCount;
final ScrollDirection direction; final ScrollDirection direction;
final double startOffset; final double startOffset;
final Painter overlayPainter;
_HomogeneousViewportElement createElement() => new _HomogeneousViewportElement(this); _HomogeneousViewportElement createElement() => new _HomogeneousViewportElement(this);
...@@ -70,6 +72,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor ...@@ -70,6 +72,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
renderObject.totalExtentCallback = getTotalExtent; renderObject.totalExtentCallback = getTotalExtent;
renderObject.minCrossAxisExtentCallback = getMinCrossAxisExtent; renderObject.minCrossAxisExtentCallback = getMinCrossAxisExtent;
renderObject.maxCrossAxisExtentCallback = getMaxCrossAxisExtent; renderObject.maxCrossAxisExtentCallback = getMaxCrossAxisExtent;
renderObject.overlayPainter = widget.overlayPainter;
} }
void unmount() { void unmount() {
...@@ -77,6 +80,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor ...@@ -77,6 +80,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
renderObject.totalExtentCallback = null; renderObject.totalExtentCallback = null;
renderObject.minCrossAxisExtentCallback = null; renderObject.minCrossAxisExtentCallback = null;
renderObject.maxCrossAxisExtentCallback = null; renderObject.maxCrossAxisExtentCallback = null;
renderObject.overlayPainter = null;
super.unmount(); super.unmount();
} }
...@@ -134,6 +138,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor ...@@ -134,6 +138,7 @@ class _HomogeneousViewportElement extends RenderObjectElement<HomogeneousViewpor
renderObject.itemExtent = widget.itemExtent; renderObject.itemExtent = widget.itemExtent;
renderObject.minExtent = getTotalExtent(null); renderObject.minExtent = getTotalExtent(null);
renderObject.startOffset = offset; renderObject.startOffset = offset;
renderObject.overlayPainter = widget.overlayPainter;
}); });
} }
......
...@@ -32,7 +32,9 @@ abstract class Scrollable extends StatefulComponent { ...@@ -32,7 +32,9 @@ abstract class Scrollable extends StatefulComponent {
Key key, Key key,
this.initialScrollOffset, this.initialScrollOffset,
this.scrollDirection: ScrollDirection.vertical, this.scrollDirection: ScrollDirection.vertical,
this.onScrollStart,
this.onScroll, this.onScroll,
this.onScrollEnd,
this.snapOffsetCallback, this.snapOffsetCallback,
this.snapAlignmentOffset: 0.0 this.snapAlignmentOffset: 0.0
}) : super(key: key) { }) : super(key: key) {
...@@ -42,7 +44,9 @@ abstract class Scrollable extends StatefulComponent { ...@@ -42,7 +44,9 @@ abstract class Scrollable extends StatefulComponent {
final double initialScrollOffset; final double initialScrollOffset;
final ScrollDirection scrollDirection; final ScrollDirection scrollDirection;
final ScrollListener onScrollStart;
final ScrollListener onScroll; final ScrollListener onScroll;
final ScrollListener onScrollEnd;
final SnapOffsetCallback snapOffsetCallback; final SnapOffsetCallback snapOffsetCallback;
final double snapAlignmentOffset; final double snapAlignmentOffset;
} }
...@@ -74,6 +78,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -74,6 +78,12 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return _scrollBehavior; return _scrollBehavior;
} }
GestureDragStartCallback _getDragStartHandler(ScrollDirection direction) {
if (config.scrollDirection != direction || !scrollBehavior.isScrollable)
return null;
return _handleDragStart;
}
GestureDragUpdateCallback _getDragUpdateHandler(ScrollDirection direction) { GestureDragUpdateCallback _getDragUpdateHandler(ScrollDirection direction) {
if (config.scrollDirection != direction || !scrollBehavior.isScrollable) if (config.scrollDirection != direction || !scrollBehavior.isScrollable)
return null; return null;
...@@ -88,8 +98,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -88,8 +98,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new GestureDetector( return new GestureDetector(
onVerticalDragStart: _getDragStartHandler(ScrollDirection.vertical),
onVerticalDragUpdate: _getDragUpdateHandler(ScrollDirection.vertical), onVerticalDragUpdate: _getDragUpdateHandler(ScrollDirection.vertical),
onVerticalDragEnd: _getDragEndHandler(ScrollDirection.vertical), onVerticalDragEnd: _getDragEndHandler(ScrollDirection.vertical),
onHorizontalDragStart: _getDragStartHandler(ScrollDirection.horizontal),
onHorizontalDragUpdate: _getDragUpdateHandler(ScrollDirection.horizontal), onHorizontalDragUpdate: _getDragUpdateHandler(ScrollDirection.horizontal),
onHorizontalDragEnd: _getDragEndHandler(ScrollDirection.horizontal), onHorizontalDragEnd: _getDragEndHandler(ScrollDirection.horizontal),
child: new Listener( child: new Listener(
...@@ -199,12 +211,22 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -199,12 +211,22 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return _startToEndAnimation(); return _startToEndAnimation();
} }
void dispatchOnScrollStart() {
if (config.onScrollStart != null)
config.onScrollStart(_scrollOffset);
}
// Derived classes can override this method and call super.dispatchOnScroll() // Derived classes can override this method and call super.dispatchOnScroll()
void dispatchOnScroll() { void dispatchOnScroll() {
if (config.onScroll != null) if (config.onScroll != null)
config.onScroll(_scrollOffset); config.onScroll(_scrollOffset);
} }
void dispatchOnScrollEnd() {
if (config.onScrollEnd != null)
config.onScrollEnd(_scrollOffset);
}
double _scrollVelocity(ui.Offset velocity) { double _scrollVelocity(ui.Offset velocity) {
double scrollVelocity = config.scrollDirection == ScrollDirection.horizontal double scrollVelocity = config.scrollDirection == ScrollDirection.horizontal
? -velocity.dx ? -velocity.dx
...@@ -216,14 +238,20 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -216,14 +238,20 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
_animation.stop(); _animation.stop();
} }
void _handleDragStart() {
scheduleMicrotask(dispatchOnScrollStart);
}
void _handleDragUpdate(double delta) { void _handleDragUpdate(double delta) {
// We negate the delta here because a positive scroll offset moves the // We negate the delta here because a positive scroll offset moves the
// the content up (or to the left) rather than down (or the right). // the content up (or to the left) rather than down (or the right).
scrollBy(-delta); scrollBy(-delta);
} }
void _handleDragEnd(Offset velocity) { Future _handleDragEnd(Offset velocity) {
fling(velocity); return fling(velocity).then((_) {
dispatchOnScrollEnd();
});
} }
} }
...@@ -379,6 +407,52 @@ class Block extends StatelessComponent { ...@@ -379,6 +407,52 @@ class Block extends StatelessComponent {
} }
} }
abstract class ScrollableListPainter extends Painter {
void attach(RenderObject renderObject) {
assert(renderObject is RenderBlockViewport);
super.attach(renderObject);
}
RenderBlockViewport get renderer => renderObject;
bool get isVertical => renderer.isVertical;
Size get viewportSize => renderer.size;
double get contentExtent => _contentExtent;
double _contentExtent = 0.0;
void set contentExtent (double value) {
assert(value != null);
assert(value >= 0.0);
if (_contentExtent == value)
return;
_contentExtent = value;
renderer?.markNeedsPaint();
}
double get scrollOffset => _scrollOffset;
double _scrollOffset = 0.0;
void set scrollOffset (double value) {
assert(value != null);
assert(value >= 0.0 && value <= 1.0);
if (_scrollOffset == value)
return;
_scrollOffset = value;
renderer?.markNeedsPaint();
}
/// Called when a scroll starts. Subclasses may override this method to
/// initialize some state or to play an animation. The returned Future should
/// complete when the computation triggered by this method has finished.
Future scrollStarted() => new Future.value();
/// Similar to scrollStarted(). Called when a scroll ends. For fling scrolls
/// "ended" means that the scroll animation either stopped of its own accord
/// or was canceled by the user.
Future scrollEnded() => new Future.value();
}
/// An optimized scrollable widget for a large number of children that are all /// An optimized scrollable widget for a large number of children that are all
/// the same size (extent) in the scrollDirection. For example for /// the same size (extent) in the scrollDirection. For example for
/// ScrollDirection.vertical itemExtent is the height of each item. Use this /// ScrollDirection.vertical itemExtent is the height of each item. Use this
...@@ -394,7 +468,8 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -394,7 +468,8 @@ abstract class ScrollableWidgetList extends Scrollable {
double snapAlignmentOffset: 0.0, double snapAlignmentOffset: 0.0,
this.itemsWrap: false, this.itemsWrap: false,
this.itemExtent, this.itemExtent,
this.padding this.padding,
this.scrollableListPainter
}) : super( }) : super(
key: key, key: key,
initialScrollOffset: initialScrollOffset, initialScrollOffset: initialScrollOffset,
...@@ -409,6 +484,7 @@ abstract class ScrollableWidgetList extends Scrollable { ...@@ -409,6 +484,7 @@ abstract class ScrollableWidgetList extends Scrollable {
final bool itemsWrap; final bool itemsWrap;
final double itemExtent; final double itemExtent;
final EdgeDims padding; final EdgeDims padding;
final ScrollableListPainter scrollableListPainter;
} }
abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ScrollableState<T> { abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ScrollableState<T> {
...@@ -480,18 +556,40 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ...@@ -480,18 +556,40 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends
return new EdgeDims.only(top: padding.top, bottom: padding.bottom); return new EdgeDims.only(top: padding.top, bottom: padding.bottom);
} }
void _updateScrollBehavior() { double get _contentExtent {
// if you don't call this from build(), you must call it from setState().
double contentExtent = config.itemExtent * itemCount; double contentExtent = config.itemExtent * itemCount;
if (config.padding != null) if (config.padding != null)
contentExtent += _leadingPadding + _trailingPadding; contentExtent += _leadingPadding + _trailingPadding;
return contentExtent;
}
void _updateScrollBehavior() {
// if you don't call this from build(), you must call it from setState().
if (config.scrollableListPainter != null)
config.scrollableListPainter.contentExtent = _contentExtent;
scrollTo(scrollBehavior.updateExtents( scrollTo(scrollBehavior.updateExtents(
contentExtent: contentExtent, contentExtent: _contentExtent,
containerExtent: _containerExtent, containerExtent: _containerExtent,
scrollOffset: scrollOffset scrollOffset: scrollOffset
)); ));
} }
void dispatchOnScrollStart() {
super.dispatchOnScrollStart();
config.scrollableListPainter?.scrollStarted();
}
void dispatchOnScroll() {
super.dispatchOnScroll();
if (config.scrollableListPainter != null)
config.scrollableListPainter.scrollOffset = scrollOffset;
}
void dispatchOnScrollEnd() {
super.dispatchOnScrollEnd();
config.scrollableListPainter?.scrollEnded();
}
Widget buildContent(BuildContext context) { Widget buildContent(BuildContext context) {
if (itemCount != _previousItemCount) { if (itemCount != _previousItemCount) {
_previousItemCount = itemCount; _previousItemCount = itemCount;
...@@ -508,7 +606,8 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends ...@@ -508,7 +606,8 @@ abstract class ScrollableWidgetListState<T extends ScrollableWidgetList> extends
itemExtent: config.itemExtent, itemExtent: config.itemExtent,
itemCount: itemCount, itemCount: itemCount,
direction: config.scrollDirection, direction: config.scrollDirection,
startOffset: scrollOffset - _leadingPadding startOffset: scrollOffset - _leadingPadding,
overlayPainter: config.scrollableListPainter
) )
) )
); );
...@@ -541,7 +640,8 @@ class ScrollableList<T> extends ScrollableWidgetList { ...@@ -541,7 +640,8 @@ class ScrollableList<T> extends ScrollableWidgetList {
this.itemBuilder, this.itemBuilder,
itemsWrap: false, itemsWrap: false,
double itemExtent, double itemExtent,
EdgeDims padding EdgeDims padding,
ScrollableListPainter scrollableListPainter
}) : super( }) : super(
key: key, key: key,
initialScrollOffset: initialScrollOffset, initialScrollOffset: initialScrollOffset,
...@@ -551,7 +651,9 @@ class ScrollableList<T> extends ScrollableWidgetList { ...@@ -551,7 +651,9 @@ class ScrollableList<T> extends ScrollableWidgetList {
snapAlignmentOffset: snapAlignmentOffset, snapAlignmentOffset: snapAlignmentOffset,
itemsWrap: itemsWrap, itemsWrap: itemsWrap,
itemExtent: itemExtent, itemExtent: itemExtent,
padding: padding); padding: padding,
scrollableListPainter: scrollableListPainter
);
final List<T> items; final List<T> items;
final ItemBuilder<T> itemBuilder; final ItemBuilder<T> itemBuilder;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment