Commit d4e52ccb authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add RTL support to Scrollbar (#11843)

When scrolling vertically, the scrollbar is on the left in RTL.
parent 268ec4b3
...@@ -49,7 +49,9 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin { ...@@ -49,7 +49,9 @@ class _ScrollbarState extends State<Scrollbar> with TickerProviderStateMixin {
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_painter ??= new _ScrollbarPainter(this); _painter ??= new _ScrollbarPainter(this);
_painter.color = Theme.of(context).highlightColor; _painter
..color = Theme.of(context).highlightColor
..textDirection = Directionality.of(context);
} }
bool _handleScrollNotification(ScrollNotification notification) { bool _handleScrollNotification(ScrollNotification notification) {
...@@ -102,12 +104,22 @@ class _ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -102,12 +104,22 @@ class _ScrollbarPainter extends ChangeNotifier implements CustomPainter {
Color _color; Color _color;
set color(Color value) { set color(Color value) {
assert(value != null); assert(value != null);
if (color == value) if (_color == value)
return; return;
_color = value; _color = value;
notifyListeners(); notifyListeners();
} }
TextDirection get textDirection => _textDirection;
TextDirection _textDirection;
set textDirection(TextDirection value) {
assert(value != null);
if (_textDirection == value)
return;
_textDirection = value;
notifyListeners();
}
@override @override
void dispose() { void dispose() {
_fadeOut?.cancel(); _fadeOut?.cancel();
...@@ -142,8 +154,19 @@ class _ScrollbarPainter extends ChangeNotifier implements CustomPainter { ...@@ -142,8 +154,19 @@ class _ScrollbarPainter extends ChangeNotifier implements CustomPainter {
Paint get _paint => new Paint()..color = color.withOpacity(_opacity.value); Paint get _paint => new Paint()..color = color.withOpacity(_opacity.value);
double _getThumbX(Size size) {
assert(textDirection != null);
switch (textDirection) {
case TextDirection.rtl:
return 0.0;
case TextDirection.ltr:
return size.width - _kThumbGirth;
}
return null;
}
void _paintVerticalThumb(Canvas canvas, Size size, double thumbOffset, double thumbExtent) { void _paintVerticalThumb(Canvas canvas, Size size, double thumbOffset, double thumbExtent) {
final Offset thumbOrigin = new Offset(size.width - _kThumbGirth, thumbOffset); final Offset thumbOrigin = new Offset(_getThumbX(size), thumbOffset);
final Size thumbSize = new Size(_kThumbGirth, thumbExtent); final Size thumbSize = new Size(_kThumbGirth, thumbExtent);
canvas.drawRect(thumbOrigin & thumbSize, _paint); canvas.drawRect(thumbOrigin & thumbSize, _paint);
} }
......
...@@ -8,14 +8,31 @@ import 'package:flutter/material.dart'; ...@@ -8,14 +8,31 @@ import 'package:flutter/material.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
void main() { void main() {
testWidgets('Viewport basic test', (WidgetTester tester) async { testWidgets('Viewport basic test (LTR)', (WidgetTester tester) async {
await tester.pumpWidget(new Scrollbar( await tester.pumpWidget(new Directionality(
child: new SingleChildScrollView( textDirection: TextDirection.ltr,
child: const SizedBox(width: 4000.0, height: 4000.0), child: new Scrollbar(
child: new SingleChildScrollView(
child: const SizedBox(width: 4000.0, height: 4000.0),
),
), ),
)); ));
expect(find.byType(Scrollbar), isNot(paints..rect())); expect(find.byType(Scrollbar), isNot(paints..rect()));
await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0); await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0);
expect(find.byType(Scrollbar), paints..rect()); expect(find.byType(Scrollbar), paints..rect(rect: new Rect.fromLTRB(800.0 - 6.0, 1.5, 800.0, 91.5)));
});
testWidgets('Viewport basic test (RTL)', (WidgetTester tester) async {
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.rtl,
child: new Scrollbar(
child: new SingleChildScrollView(
child: const SizedBox(width: 4000.0, height: 4000.0),
),
),
));
expect(find.byType(Scrollbar), isNot(paints..rect()));
await tester.fling(find.byType(SingleChildScrollView), const Offset(0.0, -10.0), 10.0);
expect(find.byType(Scrollbar), paints..rect(rect: new Rect.fromLTRB(0.0, 1.5, 6.0, 91.5)));
}); });
} }
...@@ -19,8 +19,9 @@ class TestCanvas implements Canvas { ...@@ -19,8 +19,9 @@ class TestCanvas implements Canvas {
void main() { void main() {
testWidgets('Scrollbar doesn\'t show when tapping list', (WidgetTester tester) async { testWidgets('Scrollbar doesn\'t show when tapping list', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new Center( textDirection: TextDirection.ltr,
child: new Center(
child: new Container( child: new Container(
decoration: new BoxDecoration( decoration: new BoxDecoration(
border: new Border.all(color: const Color(0xFFFFFF00)) border: new Border.all(color: const Color(0xFFFFFF00))
...@@ -38,12 +39,12 @@ void main() { ...@@ -38,12 +39,12 @@ void main() {
new Container(height: 40.0, child: const Text('5')), new Container(height: 40.0, child: const Text('5')),
new Container(height: 40.0, child: const Text('6')), new Container(height: 40.0, child: const Text('6')),
new Container(height: 40.0, child: const Text('7')), new Container(height: 40.0, child: const Text('7')),
] ],
) ),
) ),
) ),
) ),
); ));
SchedulerBinding.instance.debugAssertNoTransientCallbacks('Building a list with a scrollbar triggered an animation.'); SchedulerBinding.instance.debugAssertNoTransientCallbacks('Building a list with a scrollbar triggered an animation.');
await tester.tap(find.byType(ListView)); await tester.tap(find.byType(ListView));
...@@ -61,19 +62,20 @@ void main() { ...@@ -61,19 +62,20 @@ void main() {
}); });
testWidgets('ScrollbarPainter does not divide by zero', (WidgetTester tester) async { testWidgets('ScrollbarPainter does not divide by zero', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new Container( textDirection: TextDirection.ltr,
child: new Container(
height: 200.0, height: 200.0,
width: 300.0, width: 300.0,
child: new Scrollbar( child: new Scrollbar(
child: new ListView( child: new ListView(
children: <Widget>[ children: <Widget>[
new Container(height: 40.0, child: const Text('0')), new Container(height: 40.0, child: const Text('0')),
] ],
) ),
) ),
) ),
); ));
final CustomPaint custom = tester.widget(find.descendant(of: find.byType(Scrollbar), matching: find.byType(CustomPaint)).first); final CustomPaint custom = tester.widget(find.descendant(of: find.byType(Scrollbar), matching: find.byType(CustomPaint)).first);
final dynamic scrollPainter = custom.foregroundPainter; final dynamic scrollPainter = custom.foregroundPainter;
......
...@@ -73,8 +73,9 @@ class TestViewportScrollPosition extends ScrollPositionWithSingleContext { ...@@ -73,8 +73,9 @@ class TestViewportScrollPosition extends ScrollPositionWithSingleContext {
void main() { void main() {
testWidgets('Evil test of sliver features - 1', (WidgetTester tester) async { testWidgets('Evil test of sliver features - 1', (WidgetTester tester) async {
final GlobalKey centerKey = new GlobalKey(); final GlobalKey centerKey = new GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(new Directionality(
new ScrollConfiguration( textDirection: TextDirection.ltr,
child: new ScrollConfiguration(
behavior: new TestBehavior(), behavior: new TestBehavior(),
child: new Scrollbar( child: new Scrollbar(
child: new Scrollable( child: new Scrollable(
...@@ -159,7 +160,7 @@ void main() { ...@@ -159,7 +160,7 @@ void main() {
), ),
), ),
), ),
); ));
final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position; final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
position.animateTo(10000.0, curve: Curves.linear, duration: const Duration(minutes: 1)); position.animateTo(10000.0, curve: Curves.linear, duration: const Duration(minutes: 1));
......
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