Unverified Commit 313b5f30 authored by xubaolin's avatar xubaolin Committed by GitHub

update the scrollbar that support always show the track even not on hover (#90178)

parent d0e00529
...@@ -77,6 +77,7 @@ class Scrollbar extends StatelessWidget { ...@@ -77,6 +77,7 @@ class Scrollbar extends StatelessWidget {
required this.child, required this.child,
this.controller, this.controller,
this.isAlwaysShown, this.isAlwaysShown,
this.trackVisibility,
this.showTrackOnHover, this.showTrackOnHover,
this.hoverThickness, this.hoverThickness,
this.thickness, this.thickness,
...@@ -95,11 +96,26 @@ class Scrollbar extends StatelessWidget { ...@@ -95,11 +96,26 @@ class Scrollbar extends StatelessWidget {
/// {@macro flutter.widgets.Scrollbar.isAlwaysShown} /// {@macro flutter.widgets.Scrollbar.isAlwaysShown}
final bool? isAlwaysShown; final bool? isAlwaysShown;
/// Controls the track visibility.
///
/// If this property is null, then [ScrollbarThemeData.trackVisibility] of
/// [ThemeData.scrollbarTheme] is used. If that is also null, the default value
/// is false.
///
/// If the track visibility is related to the scrollbar's material state,
/// use the global [ScrollbarThemeData.trackVisibility] or override the
/// sub-tree's theme data.
///
/// [showTrackOnHover] can be replaced by this and will be deprecated.
final bool? trackVisibility;
/// Controls if the track will show on hover and remain, including during drag. /// Controls if the track will show on hover and remain, including during drag.
/// ///
/// If this property is null, then [ScrollbarThemeData.showTrackOnHover] of /// If this property is null, then [ScrollbarThemeData.showTrackOnHover] of
/// [ThemeData.scrollbarTheme] is used. If that is also null, the default value /// [ThemeData.scrollbarTheme] is used. If that is also null, the default value
/// is false. /// is false.
///
/// This will be deprecated, and [trackVisibility] is recommended.
final bool? showTrackOnHover; final bool? showTrackOnHover;
/// The thickness of the scrollbar when a hover state is active and /// The thickness of the scrollbar when a hover state is active and
...@@ -153,6 +169,7 @@ class Scrollbar extends StatelessWidget { ...@@ -153,6 +169,7 @@ class Scrollbar extends StatelessWidget {
return _MaterialScrollbar( return _MaterialScrollbar(
controller: controller, controller: controller,
isAlwaysShown: isAlwaysShown, isAlwaysShown: isAlwaysShown,
trackVisibility: trackVisibility,
showTrackOnHover: showTrackOnHover, showTrackOnHover: showTrackOnHover,
hoverThickness: hoverThickness, hoverThickness: hoverThickness,
thickness: thickness, thickness: thickness,
...@@ -171,6 +188,7 @@ class _MaterialScrollbar extends RawScrollbar { ...@@ -171,6 +188,7 @@ class _MaterialScrollbar extends RawScrollbar {
required Widget child, required Widget child,
ScrollController? controller, ScrollController? controller,
bool? isAlwaysShown, bool? isAlwaysShown,
this.trackVisibility,
this.showTrackOnHover, this.showTrackOnHover,
this.hoverThickness, this.hoverThickness,
double? thickness, double? thickness,
...@@ -193,6 +211,7 @@ class _MaterialScrollbar extends RawScrollbar { ...@@ -193,6 +211,7 @@ class _MaterialScrollbar extends RawScrollbar {
scrollbarOrientation: scrollbarOrientation, scrollbarOrientation: scrollbarOrientation,
); );
final bool? trackVisibility;
final bool? showTrackOnHover; final bool? showTrackOnHover;
final double? hoverThickness; final double? hoverThickness;
...@@ -217,6 +236,13 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -217,6 +236,13 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
bool get _showTrackOnHover => widget.showTrackOnHover ?? _scrollbarTheme.showTrackOnHover ?? false; bool get _showTrackOnHover => widget.showTrackOnHover ?? _scrollbarTheme.showTrackOnHover ?? false;
MaterialStateProperty<bool> get _trackVisibility => MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered) && _showTrackOnHover) {
return true;
}
return widget.trackVisibility ?? _scrollbarTheme.trackVisibility?.resolve(states) ?? false;
});
Set<MaterialState> get _states => <MaterialState>{ Set<MaterialState> get _states => <MaterialState>{
if (_dragIsActive) MaterialState.dragged, if (_dragIsActive) MaterialState.dragged,
if (_hoverIsActive) MaterialState.hovered, if (_hoverIsActive) MaterialState.hovered,
...@@ -251,7 +277,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -251,7 +277,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
// If the track is visible, the thumb color hover animation is ignored and // If the track is visible, the thumb color hover animation is ignored and
// changes immediately. // changes immediately.
if (states.contains(MaterialState.hovered) && _showTrackOnHover) if (_trackVisibility.resolve(states))
return _scrollbarTheme.thumbColor?.resolve(states) ?? hoverColor; return _scrollbarTheme.thumbColor?.resolve(states) ?? hoverColor;
return Color.lerp( return Color.lerp(
...@@ -266,7 +292,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -266,7 +292,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
final Color onSurface = _colorScheme.onSurface; final Color onSurface = _colorScheme.onSurface;
final Brightness brightness = _colorScheme.brightness; final Brightness brightness = _colorScheme.brightness;
return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered) && _showTrackOnHover) { if (_trackVisibility.resolve(states)) {
return _scrollbarTheme.trackColor?.resolve(states) return _scrollbarTheme.trackColor?.resolve(states)
?? (brightness == Brightness.light ?? (brightness == Brightness.light
? onSurface.withOpacity(0.03) ? onSurface.withOpacity(0.03)
...@@ -280,7 +306,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -280,7 +306,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
final Color onSurface = _colorScheme.onSurface; final Color onSurface = _colorScheme.onSurface;
final Brightness brightness = _colorScheme.brightness; final Brightness brightness = _colorScheme.brightness;
return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered) && _showTrackOnHover) { if (_trackVisibility.resolve(states)) {
return _scrollbarTheme.trackBorderColor?.resolve(states) return _scrollbarTheme.trackBorderColor?.resolve(states)
?? (brightness == Brightness.light ?? (brightness == Brightness.light
? onSurface.withOpacity(0.1) ? onSurface.withOpacity(0.1)
...@@ -292,7 +318,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { ...@@ -292,7 +318,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> {
MaterialStateProperty<double> get _thickness { MaterialStateProperty<double> get _thickness {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered) && _showTrackOnHover) if (states.contains(MaterialState.hovered) && _trackVisibility.resolve(states))
return widget.hoverThickness return widget.hoverThickness
?? _scrollbarTheme.thickness?.resolve(states) ?? _scrollbarTheme.thickness?.resolve(states)
?? _kScrollbarThicknessWithTrack; ?? _kScrollbarThicknessWithTrack;
......
...@@ -32,6 +32,7 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -32,6 +32,7 @@ class ScrollbarThemeData with Diagnosticable {
/// Creates a theme that can be used for [ThemeData.scrollbarTheme]. /// Creates a theme that can be used for [ThemeData.scrollbarTheme].
const ScrollbarThemeData({ const ScrollbarThemeData({
this.thickness, this.thickness,
this.trackVisibility,
this.showTrackOnHover, this.showTrackOnHover,
this.isAlwaysShown, this.isAlwaysShown,
this.radius, this.radius,
...@@ -51,6 +52,10 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -51,6 +52,10 @@ class ScrollbarThemeData with Diagnosticable {
/// * [MaterialState.hovered] on web and desktop platforms. /// * [MaterialState.hovered] on web and desktop platforms.
final MaterialStateProperty<double?>? thickness; final MaterialStateProperty<double?>? thickness;
/// Overrides the default value of [Scrollbar.trackVisibility] in all
/// descendant [Scrollbar] widgets.
final MaterialStateProperty<bool?>? trackVisibility;
/// Overrides the default value of [Scrollbar.showTrackOnHover] in all /// Overrides the default value of [Scrollbar.showTrackOnHover] in all
/// descendant [Scrollbar] widgets. /// descendant [Scrollbar] widgets.
final bool? showTrackOnHover; final bool? showTrackOnHover;
...@@ -122,6 +127,7 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -122,6 +127,7 @@ class ScrollbarThemeData with Diagnosticable {
/// new values. /// new values.
ScrollbarThemeData copyWith({ ScrollbarThemeData copyWith({
MaterialStateProperty<double?>? thickness, MaterialStateProperty<double?>? thickness,
MaterialStateProperty<bool?>? trackVisibility,
bool? showTrackOnHover, bool? showTrackOnHover,
bool? isAlwaysShown, bool? isAlwaysShown,
bool? interactive, bool? interactive,
...@@ -135,6 +141,7 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -135,6 +141,7 @@ class ScrollbarThemeData with Diagnosticable {
}) { }) {
return ScrollbarThemeData( return ScrollbarThemeData(
thickness: thickness ?? this.thickness, thickness: thickness ?? this.thickness,
trackVisibility: trackVisibility ?? this.trackVisibility,
showTrackOnHover: showTrackOnHover ?? this.showTrackOnHover, showTrackOnHover: showTrackOnHover ?? this.showTrackOnHover,
isAlwaysShown: isAlwaysShown ?? this.isAlwaysShown, isAlwaysShown: isAlwaysShown ?? this.isAlwaysShown,
interactive: interactive ?? this.interactive, interactive: interactive ?? this.interactive,
...@@ -157,9 +164,10 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -157,9 +164,10 @@ class ScrollbarThemeData with Diagnosticable {
assert(t != null); assert(t != null);
return ScrollbarThemeData( return ScrollbarThemeData(
thickness: _lerpProperties<double?>(a?.thickness, b?.thickness, t, lerpDouble), thickness: _lerpProperties<double?>(a?.thickness, b?.thickness, t, lerpDouble),
showTrackOnHover: t < 0.5 ? a?.showTrackOnHover : b?.showTrackOnHover, trackVisibility: _lerpProperties<bool?>(a?.trackVisibility, b?.trackVisibility, t, _lerpBool),
isAlwaysShown: t < 0.5 ? a?.isAlwaysShown : b?.isAlwaysShown, showTrackOnHover: _lerpBool(a?.showTrackOnHover, b?.showTrackOnHover, t),
interactive: t < 0.5 ? a?.interactive : b?.interactive, isAlwaysShown: _lerpBool(a?.isAlwaysShown, b?.isAlwaysShown, t),
interactive: _lerpBool(a?.interactive, b?.interactive, t),
radius: Radius.lerp(a?.radius, b?.radius, t), radius: Radius.lerp(a?.radius, b?.radius, t),
thumbColor: _lerpProperties<Color?>(a?.thumbColor, b?.thumbColor, t, Color.lerp), thumbColor: _lerpProperties<Color?>(a?.thumbColor, b?.thumbColor, t, Color.lerp),
trackColor: _lerpProperties<Color?>(a?.trackColor, b?.trackColor, t, Color.lerp), trackColor: _lerpProperties<Color?>(a?.trackColor, b?.trackColor, t, Color.lerp),
...@@ -174,6 +182,7 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -174,6 +182,7 @@ class ScrollbarThemeData with Diagnosticable {
int get hashCode { int get hashCode {
return hashValues( return hashValues(
thickness, thickness,
trackVisibility,
showTrackOnHover, showTrackOnHover,
isAlwaysShown, isAlwaysShown,
interactive, interactive,
...@@ -195,6 +204,7 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -195,6 +204,7 @@ class ScrollbarThemeData with Diagnosticable {
return false; return false;
return other is ScrollbarThemeData return other is ScrollbarThemeData
&& other.thickness == thickness && other.thickness == thickness
&& other.trackVisibility == trackVisibility
&& other.showTrackOnHover == showTrackOnHover && other.showTrackOnHover == showTrackOnHover
&& other.isAlwaysShown == isAlwaysShown && other.isAlwaysShown == isAlwaysShown
&& other.interactive == interactive && other.interactive == interactive
...@@ -211,6 +221,7 @@ class ScrollbarThemeData with Diagnosticable { ...@@ -211,6 +221,7 @@ class ScrollbarThemeData with Diagnosticable {
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<MaterialStateProperty<double?>>('thickness', thickness, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<double?>>('thickness', thickness, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<bool?>>('trackVisibility', trackVisibility, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('showTrackOnHover', showTrackOnHover, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('showTrackOnHover', showTrackOnHover, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('isAlwaysShown', isAlwaysShown, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('isAlwaysShown', isAlwaysShown, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('interactive', interactive, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('interactive', interactive, defaultValue: null));
...@@ -252,6 +263,8 @@ class _LerpProperties<T> implements MaterialStateProperty<T> { ...@@ -252,6 +263,8 @@ class _LerpProperties<T> implements MaterialStateProperty<T> {
} }
} }
bool? _lerpBool(bool? a, bool? b, double t) => t < 0.5 ? a : b;
/// Applies a scrollbar theme to descendant [Scrollbar] widgets. /// Applies a scrollbar theme to descendant [Scrollbar] widgets.
/// ///
/// Descendant widgets obtain the current theme's [ScrollbarThemeData] using /// Descendant widgets obtain the current theme's [ScrollbarThemeData] using
......
...@@ -574,6 +574,52 @@ void main() { ...@@ -574,6 +574,52 @@ void main() {
}), }),
); );
testWidgets('ScrollbarThemeData.trackVisibility test', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController();
bool? _getTrackVisibility(Set<MaterialState> states) {
return true;
}
await tester.pumpWidget(
MaterialApp(
theme: ThemeData().copyWith(
scrollbarTheme: _scrollbarTheme(
trackVisibility: MaterialStateProperty.resolveWith(_getTrackVisibility),
),
),
home: ScrollConfiguration(
behavior: const NoScrollbarBehavior(),
child: Scrollbar(
isAlwaysShown: true,
showTrackOnHover: true,
controller: scrollController,
child: SingleChildScrollView(
controller: scrollController,
child: const SizedBox(width: 4000.0, height: 4000.0),
),
),
),
),
);
await tester.pumpAndSettle();
expect(
find.byType(Scrollbar),
paints
..rect(color: const Color(0x08000000))
..line(
strokeWidth: 1.0,
color: const Color(0x1a000000),
)
..rrect(color: const Color(0xff4caf50)),
);
}, variant: const TargetPlatformVariant(<TargetPlatform>{
TargetPlatform.linux,
TargetPlatform.macOS,
TargetPlatform.windows,
TargetPlatform.fuchsia,
}),
);
testWidgets('Default ScrollbarTheme debugFillProperties', (WidgetTester tester) async { testWidgets('Default ScrollbarTheme debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
const ScrollbarThemeData().debugFillProperties(builder); const ScrollbarThemeData().debugFillProperties(builder);
...@@ -636,6 +682,7 @@ class NoScrollbarBehavior extends ScrollBehavior { ...@@ -636,6 +682,7 @@ class NoScrollbarBehavior extends ScrollBehavior {
ScrollbarThemeData _scrollbarTheme({ ScrollbarThemeData _scrollbarTheme({
MaterialStateProperty<double?>? thickness, MaterialStateProperty<double?>? thickness,
MaterialStateProperty<bool?>? trackVisibility,
bool showTrackOnHover = true, bool showTrackOnHover = true,
bool isAlwaysShown = true, bool isAlwaysShown = true,
Radius radius = const Radius.circular(6.0), Radius radius = const Radius.circular(6.0),
...@@ -648,6 +695,7 @@ ScrollbarThemeData _scrollbarTheme({ ...@@ -648,6 +695,7 @@ ScrollbarThemeData _scrollbarTheme({
}) { }) {
return ScrollbarThemeData( return ScrollbarThemeData(
thickness: thickness ?? MaterialStateProperty.resolveWith(_getThickness), thickness: thickness ?? MaterialStateProperty.resolveWith(_getThickness),
trackVisibility: trackVisibility,
showTrackOnHover: showTrackOnHover, showTrackOnHover: showTrackOnHover,
isAlwaysShown: isAlwaysShown, isAlwaysShown: isAlwaysShown,
radius: radius, radius: radius,
......
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