mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Replace Scrollbar with Scrollbar2 (#8133)
This commit is contained in:
parent
ef004ae97d
commit
fd30f63161
|
@ -190,7 +190,7 @@ class ListDemoState extends State<ListDemo> {
|
|||
),
|
||||
],
|
||||
),
|
||||
body: new Scrollbar2(
|
||||
body: new Scrollbar(
|
||||
child: new ListView(
|
||||
padding: new EdgeInsets.symmetric(vertical: _dense ? 4.0 : 8.0),
|
||||
children: listItems.toList(),
|
||||
|
|
|
@ -447,7 +447,7 @@ class _LicensePageState extends State<LicensePage> {
|
|||
),
|
||||
body: new DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
child: new Scrollbar2(
|
||||
child: new Scrollbar(
|
||||
child: new ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 12.0),
|
||||
shrinkWrap: true,
|
||||
|
|
|
@ -184,7 +184,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
|
|||
textStyle: route.style,
|
||||
child: new ScrollConfiguration(
|
||||
delegate: new _DropdownScrollConfigurationDelegate(Theme.of(context).platform),
|
||||
child: new Scrollbar2(
|
||||
child: new Scrollbar(
|
||||
child: new ListView(
|
||||
controller: config.route.scrollController,
|
||||
padding: _kMenuVerticalPadding,
|
||||
|
|
|
@ -10,22 +10,22 @@ import 'package:flutter/widgets.dart';
|
|||
|
||||
import 'theme.dart';
|
||||
|
||||
class Scrollbar2 extends StatefulWidget {
|
||||
Scrollbar2({
|
||||
class Scrollbar extends StatefulWidget {
|
||||
Scrollbar({
|
||||
Key key,
|
||||
this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The subtree to place inside the [Scrollbar2]. This should include
|
||||
/// The subtree to place inside the [Scrollbar]. This should include
|
||||
/// a source of [ScrollNotification2] notifications, typically a [Scrollable2]
|
||||
/// widget.
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
_Scrollbar2State createState() => new _Scrollbar2State();
|
||||
_ScrollbarState createState() => new _ScrollbarState();
|
||||
}
|
||||
|
||||
class _Scrollbar2State extends State<Scrollbar2> with TickerProviderStateMixin {
|
||||
class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
|
||||
_ScrollbarController _controller;
|
||||
|
||||
@override
|
||||
|
@ -179,193 +179,3 @@ class _ScrollbarPainter extends CustomPainter {
|
|||
return oldDelegate.controller != controller;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DELETE EVERYTHING BELOW THIS LINE WHEN REMOVING LEGACY SCROLLING CODE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const double _kMinScrollbarThumbExtent = 18.0;
|
||||
const double _kScrollbarThumbGirth = 6.0;
|
||||
const Duration _kScrollbarThumbFadeDuration = const Duration(milliseconds: 300);
|
||||
|
||||
class _Painter extends CustomPainter {
|
||||
_Painter({
|
||||
this.scrollOffset,
|
||||
this.scrollDirection,
|
||||
this.contentExtent,
|
||||
this.containerExtent,
|
||||
this.color
|
||||
});
|
||||
|
||||
final double scrollOffset;
|
||||
final Axis scrollDirection;
|
||||
final double contentExtent;
|
||||
final double containerExtent;
|
||||
final Color color;
|
||||
|
||||
void paintScrollbar(Canvas canvas, Size size) {
|
||||
Point thumbOrigin;
|
||||
Size thumbSize;
|
||||
|
||||
switch (scrollDirection) {
|
||||
case Axis.vertical:
|
||||
double thumbHeight = size.height * containerExtent / contentExtent;
|
||||
thumbHeight = thumbHeight.clamp(_kMinScrollbarThumbExtent, size.height);
|
||||
final double maxThumbTop = size.height - thumbHeight;
|
||||
double thumbTop = (scrollOffset / (contentExtent - containerExtent)) * maxThumbTop;
|
||||
thumbTop = thumbTop.clamp(0.0, maxThumbTop);
|
||||
thumbOrigin = new Point(size.width - _kScrollbarThumbGirth, thumbTop);
|
||||
thumbSize = new Size(_kScrollbarThumbGirth, thumbHeight);
|
||||
break;
|
||||
case Axis.horizontal:
|
||||
double thumbWidth = size.width * containerExtent / contentExtent;
|
||||
thumbWidth = thumbWidth.clamp(_kMinScrollbarThumbExtent, size.width);
|
||||
final double maxThumbLeft = size.width - thumbWidth;
|
||||
double thumbLeft = (scrollOffset / (contentExtent - containerExtent)) * maxThumbLeft;
|
||||
thumbLeft = thumbLeft.clamp(0.0, maxThumbLeft);
|
||||
thumbOrigin = new Point(thumbLeft, size.height - _kScrollbarThumbGirth);
|
||||
thumbSize = new Size(thumbWidth, _kScrollbarThumbGirth);
|
||||
break;
|
||||
}
|
||||
|
||||
final Paint paint = new Paint()..color = color;
|
||||
canvas.drawRect(thumbOrigin & thumbSize, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
if (scrollOffset == null || color.alpha == 0)
|
||||
return;
|
||||
paintScrollbar(canvas, size);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_Painter oldPainter) {
|
||||
return oldPainter.scrollOffset != scrollOffset
|
||||
|| oldPainter.scrollDirection != scrollDirection
|
||||
|| oldPainter.contentExtent != contentExtent
|
||||
|| oldPainter.containerExtent != containerExtent
|
||||
|| oldPainter.color != color;
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a scrollbar that tracks the scrollOffset of its child's [Scrollable]
|
||||
/// descendant. If the Scrollbar's child has more than one Scrollable descendant
|
||||
/// the scrollableKey parameter can be used to identify the one the Scrollbar
|
||||
/// should track.
|
||||
class Scrollbar extends StatefulWidget {
|
||||
/// Creates a scrollbar.
|
||||
///
|
||||
/// The child argument must not be null.
|
||||
Scrollbar({ Key key, this.scrollableKey, this.child }) : super(key: key) {
|
||||
assert(child != null);
|
||||
}
|
||||
|
||||
/// Identifies the [Scrollable] descendant of child that the scrollbar will
|
||||
/// track. Can be null if there's only one [Scrollable] descendant.
|
||||
final Key scrollableKey;
|
||||
|
||||
/// The scrollbar will be stacked on top of this child. The scrollbar will
|
||||
/// display when child's [Scrollable] descendant is scrolled.
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
_ScrollbarState createState() => new _ScrollbarState();
|
||||
}
|
||||
|
||||
class _ScrollbarState extends State<Scrollbar> with SingleTickerProviderStateMixin {
|
||||
AnimationController _fade;
|
||||
CurvedAnimation _opacity;
|
||||
double _scrollOffset;
|
||||
Axis _scrollDirection;
|
||||
double _containerExtent;
|
||||
double _contentExtent;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fade = new AnimationController(duration: _kScrollbarThumbFadeDuration, vsync: this);
|
||||
_opacity = new CurvedAnimation(parent: _fade, curve: Curves.fastOutSlowIn);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_fade.stop();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _updateState(ScrollableState scrollable) {
|
||||
if (scrollable.scrollBehavior is! ExtentScrollBehavior)
|
||||
return;
|
||||
if (_scrollOffset != scrollable.scrollOffset)
|
||||
setState(() { _scrollOffset = scrollable.scrollOffset; });
|
||||
if (_scrollDirection != scrollable.config.scrollDirection)
|
||||
setState(() { _scrollDirection = scrollable.config.scrollDirection; });
|
||||
final ExtentScrollBehavior scrollBehavior = scrollable.scrollBehavior;
|
||||
if (_contentExtent != scrollBehavior.contentExtent)
|
||||
setState(() { _contentExtent = scrollBehavior.contentExtent; });
|
||||
if (_containerExtent != scrollBehavior.containerExtent)
|
||||
setState(() { _containerExtent = scrollBehavior.containerExtent; });
|
||||
}
|
||||
|
||||
void _onScrollStarted(ScrollableState scrollable) {
|
||||
_updateState(scrollable);
|
||||
}
|
||||
|
||||
void _onScrollUpdated(ScrollableState scrollable) {
|
||||
_updateState(scrollable);
|
||||
if (_fade.status != AnimationStatus.completed)
|
||||
_fade.forward();
|
||||
}
|
||||
|
||||
void _onScrollEnded(ScrollableState scrollable) {
|
||||
_updateState(scrollable);
|
||||
_fade.reverse();
|
||||
}
|
||||
|
||||
bool _handleScrollNotification(ScrollNotification notification) {
|
||||
if (config.scrollableKey == null) {
|
||||
if (notification.depth != 0)
|
||||
return false;
|
||||
} else if (config.scrollableKey != notification.scrollable.config.key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ScrollableState scrollable = notification.scrollable;
|
||||
switch(notification.kind) {
|
||||
case ScrollNotificationKind.started:
|
||||
_onScrollStarted(scrollable);
|
||||
break;
|
||||
case ScrollNotificationKind.updated:
|
||||
_onScrollUpdated(scrollable);
|
||||
break;
|
||||
case ScrollNotificationKind.ended:
|
||||
_onScrollEnded(scrollable);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new NotificationListener<ScrollNotification>(
|
||||
onNotification: _handleScrollNotification,
|
||||
child: new AnimatedBuilder(
|
||||
animation: _opacity,
|
||||
builder: (BuildContext context, Widget child) {
|
||||
return new CustomPaint(
|
||||
foregroundPainter: new _Painter(
|
||||
scrollOffset: _scrollOffset,
|
||||
scrollDirection: _scrollDirection,
|
||||
containerExtent: _containerExtent,
|
||||
contentExtent: _contentExtent,
|
||||
color: Theme.of(context).highlightColor.withOpacity(_opacity.value)
|
||||
),
|
||||
child: child
|
||||
);
|
||||
},
|
||||
child: config.child
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ import '../rendering/mock_canvas.dart';
|
|||
|
||||
void main() {
|
||||
testWidgets('Viewport2 basic test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(new Scrollbar2(
|
||||
await tester.pumpWidget(new Scrollbar(
|
||||
child: new SingleChildScrollView(
|
||||
child: const SizedBox(width: 4000.0, height: 4000.0),
|
||||
),
|
||||
));
|
||||
expect(find.byType(Scrollbar2), isNot(paints..rect()));
|
||||
expect(find.byType(Scrollbar), isNot(paints..rect()));
|
||||
await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0);
|
||||
expect(find.byType(Scrollbar2), paints..rect());
|
||||
expect(find.byType(Scrollbar), paints..rect());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ void main() {
|
|||
),
|
||||
height: 200.0,
|
||||
width: 300.0,
|
||||
child: new Scrollbar2(
|
||||
child: new Scrollbar(
|
||||
child: new ListView(
|
||||
children: <Widget>[
|
||||
new Container(height: 40.0, child: new Text('0')),
|
||||
|
|
|
@ -74,7 +74,7 @@ void main() {
|
|||
await tester.pumpWidget(
|
||||
new ScrollConfiguration2(
|
||||
behavior: new TestBehavior(),
|
||||
child: new Scrollbar2(
|
||||
child: new Scrollbar(
|
||||
child: new Scrollable2(
|
||||
axisDirection: AxisDirection.down,
|
||||
physics: const TestScrollPhysics(),
|
||||
|
|
Loading…
Reference in a new issue