Skip to content

[Slider] Custom track, ticker, and overlay shape painters - #25008

Merged
clocksmith merged 15 commits into
flutter:masterfrom
clocksmith:slider-track-painter
Feb 1, 2019
Merged

clocksmith merged 15 commits into
flutter:masterfrom
clocksmith:slider-track-painter

Conversation

@clocksmith

@clocksmith clocksmith commented Dec 5, 2018 •

Copy link
Copy Markdown
Contributor

Create a slider shape for custom track, tick mark, and overlay painting. Originally, this work was part of the larger range slider effort, but can and should work independently of having more than 1 thumb.

Without this change

Part             | Custom Painter? | Custom Options?
__________________________________
Track            | ** NO **        | color
Ticks            | ** NO **        | periodicity, color
Thumbs           | YES             | color
Overlay          | ** NO **        | color
Value Indicators | YES             | color, text style

With this change

Part             | Custom Painter? | Custom Options?
__________________________________
Track            | ** YES **       | color, ** height **
Ticks            | ** YES **       | periodicity, color
Thumbs           | YES             | color
Overlay          | ** YES **       | color
Value Indicators | YES             | color, text style

CHANGES:

  • SliderTrackShape is added as slider theme param, with a default of RectangularSliderTrackShape, and slider RenderBox paint() is updated to use it.
    • The default track shape uses the slider theme colors to maintain compatibility with the activeTrackColor and inactiveTrackColor params in Slider.
    • The default track shape uses a newly created slider theme param: trackHeight, but is overridden if custom track shape is used.
    • Dependency between overlay, track length, and value mapping is removed from the slider class, and made an artifact of the default track shape.
  • SliderComponentShape for ticks is added as a slider theme param, with a default of RoundSliderTickShape, and slider RenderBox paint() is updated to use it.
  • All tick marks are now painted, instead of excluding the one with the same center as the thumb. This does not affect the default state, but is important if custom tick marks extend the bounds of a thumb
    • Default tick mark radius is a function of track height.
  • SliderComponentShape for overlay is added as a slider theme param, with a default of RoundSliderOverlayShape, and slider RenderBox paint() is updated to use it.
  • The new shape API and slider paint() works for a single thumb, but also allows for easy adaptation to multiple thumbs, in preparation for the RangeSlider, without having to change the new public API.

NEXT UP:

  • Update rendering to material spec.
    • Tick marks should be aligned with the center of the value, not adjusted to be contained within the track.
    • Thumb shape default radius should be larger.
  • More decoupling and customization.
    • Default overlay shape painting should be a function of thumbShape.
    • Default overlay shape should paint after thumb and be painted as an annulus.
    • Default overlay color should use new color theme.
    • Paint color tweens can be initialized once, rather than on every paint.
    • RangeSlider

closes #22325

@clocksmith clocksmith changed the title Slider track painter [WIP] [Slider] Custom track shape painter Dec 5, 2018
@zoechi zoechi added framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages labels Dec 6, 2018
@clocksmith clocksmith changed the title [WIP] [Slider] Custom track shape painter [WIP] [Slider] Custom track, ticker, and overlay shape painters Dec 11, 2018
@clocksmith clocksmith changed the title [WIP] [Slider] Custom track, ticker, and overlay shape painters [Slider] Custom track, ticker, and overlay shape painters Dec 12, 2018
@clocksmith
clocksmith requested a review from johnsonmh December 12, 2018 20:54

@johnsonmh johnsonmh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, I just had a bunch of nits but it's really just the same 2/3 things.

Comment thread packages/flutter/lib/src/material/slider.dart Outdated
Comment thread packages/flutter/lib/src/material/slider.dart Outdated
Comment thread packages/flutter/lib/src/material/slider.dart Outdated
Comment thread packages/flutter/lib/src/material/slider.dart Outdated
Comment thread packages/flutter/lib/src/material/slider.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/test/material/slider_test.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/test/material/slider_theme_test.dart Outdated
@clocksmith

Copy link
Copy Markdown
Contributor Author

Updated, PTAL

@gspencergoog

Copy link
Copy Markdown
Contributor

You will need to add tests before you commit, but it looks OK to me. Also, it would be nice to add to the "custom slider" demo in the Flutter gallery app to show a simple customization of the track, etc.

@clocksmith

Copy link
Copy Markdown
Contributor Author

I added tests, and am going to update the gallery with examples next (sep PR)

@HansMuller HansMuller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still working on this. Progress report :-)

Comment thread packages/flutter/lib/src/material/slider.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's sufficient to say that it's the default [Slider] track shape.

Is it the default value of SliderThemeData.trackShape?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically it is the default shape of the SliderThemeData.fromPrimaryColors ctor which is the default for the Theme. I copied the description directly from the 2 existing default shapes (RoundThumb and PaddleValueIndicator). Can cover this in #25672 as well

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated

@HansMuller HansMuller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More feedback that's mostly about the docs. Adding this much new API requires adding a commensurate amount of helpful documentation.

Comment thread packages/flutter/lib/src/material/slider.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really helpful (if it is helpful then the reader is out of their depth).

It might be worth pointing out how he trackShape's preferred size contribute's to the slider's overall preferred size.

It would be worth pointing out that the default value of trackShape is RectangularSliderTrackShape.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following the pattern of the other existing components here. If I remove "This can be customized by implementing a subclass of Foo" from the 3 new components, should I also take it away from the existing 2?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth pointing out how he trackShape's preferred size contribute's to the slider's overall preferred size.

It doesn't actually do that in this change.

The default track size paints relative to the size of the parent box, but it subtracts out the size largest overlapping piece: the overlay. The intrinsic sizes are dependent on the overlay, thumb, and value indicators. The track shape's preferredRect is used inside the Slider class for:

  1. Tap gesture points to thumb position range, where 0.0 is track.left and 1.0 is track.right.
  2. The thumb center and discrete tick centers for their shape painters.

I added these as doc comments, but will go in more detail once I get to the actual SliderTrackShape doc comments.

It would be worth pointing out that the default value of trackShape is RectangularSliderTrackShape.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't define behavior.

The size and shape of the each [Slider] tick.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will resolve from above question:

I was following the pattern of the other existing components here. If I remove "This can be customized by implementing a subclass of Foo" from the 3 new components, should I also take it away from the existing 2?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to fix them up in this PR. Filing an issue, so that the work happens eventually, would be helpful.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I ended up keeping some comments consistent by updating the, and some constsent by leaving tham as is, but I have filed #25672 to further improve the docs, and create a diagram

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/test/material/slider_theme_test.dart Outdated
Comment thread packages/flutter/test/material/slider_theme_test.dart Outdated
@clocksmith

clocksmith commented Dec 21, 2018 •

Copy link
Copy Markdown
Contributor Author

Added 2 issues for follow up PRs

#25672 - Documentation diagram and consistency
#25671 - DiagnostiProperties tests

@clocksmith

Copy link
Copy Markdown
Contributor Author

Ready for next review, PTAL

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still hard to understand. This "overlay" is the temporary highlight that appears around the slider's thumb when the thumb is pressed and dragged?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah overlay was an existing term used within this class. The spec does not call it anything specifically, but it is visible when the thumb is pressed, focused, or hovered.

I added a little more description.

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this method have an isEnabled parameter?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case a developer wants the track size for enabled/disabled to be different

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conventional boilerplate for see also references like this is:

[RectangularSliderTrackShape], which default track shape.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed through out

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is just the value of Slider.isInteractive, why isn't the parameter called isInteractive?

@clocksmith clocksmith Jan 8, 2019 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct terminology is "enabled" and "disabled", but isInteractive already exists within slider.dart. It is already correctly referred to as isEnabled in other places slider_theme.dart, so I am continuing with that. Ideally, it would be refactored to isEnabled, enabled, disabled, etc in slider.dart as well.

https://material.io/design/components/sliders.html#continuous-slider
see "States" ^

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
@HansMuller

Copy link
Copy Markdown
Contributor

One other thing: the SliderTheme "see also" doc should mention the new shape values.

@clocksmith
clocksmith force-pushed the slider-track-painter branch 3 times, most recently from 8f575f9 to 5d08a96 Compare January 9, 2019 19:47

@HansMuller HansMuller left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there are still comments from the last review that need to be addressed. Before submitting for another review, please read everything carefully:

  • Watch out for obvious typos and indentos.
  • Don't document methods or properties by reiterating the name.
  • Make sure all feedback has been addressed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to assume that the centers of the 3 shapes will be aligned. That doesn't seem correct?

Comment thread packages/flutter/lib/src/material/slider.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes more sense then the original; not clear why _overlayRadius was used. On the other hand the code was known to work ... any idea why we used to subtract _overlayRadius?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the track was always padded from the slider edges by the overlay radius, but now that is encapsulated in the _trackRect

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the original comment obsolete now?

It looks like the underlying assumption here is that the thumb/overlay/tick could extend horizontally past both ends of the track by 50%. If that's correct, it would be helpful to say as much.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

computeMaxIntrinsicWidth isn't supposed to be called directly (see https://docs.flutter.io/flutter/rendering/RenderBox/computeMaxIntrinsicWidth.html), call getMaxIntrinsicWith().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra indent space

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in macro

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[isEnabled] has the same value as [Slider.isInteractive]. If true the slider will respond to input.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in macro

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't just reiterate the name of a property as its definition.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This param no longer exists, removed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved a lot of these things to macros too

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The [center] offset is relative to the origin of the canvas.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment may have to be adjusted with the macros that are now being used

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
@clocksmith
clocksmith force-pushed the slider-track-painter branch from 3a8caa7 to 57c3b79 Compare January 14, 2019 23:22
@clocksmith

Copy link
Copy Markdown
Contributor Author

One other thing: the SliderTheme "see also" doc should mention the new shape values.

It mentions the abstract shapes. Should it also mention the defaults?

@HansMuller HansMuller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really close. Just some simple cleanups.

Comment thread packages/flutter/lib/src/material/slider.dart Outdated
// need to padding to the track relative to the slider box itself. It is
// assumed that these shapes are vertically centered on the track.
double get _maxHorizontalTrackPadding => _sizesThatCanPadTrack.map((Size size) => size.width).reduce(math.max);
double get _maxVerticalTrackPadding => _sizesThatCanPadTrack.map((Size size) => size.width).reduce(math.max);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are width and height values not really padding values. It would be clearer if they were called: maxSliderPartHeight and maxSliderPartWidth; the list below would be sliderPartSizes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


@override
double computeMinIntrinsicHeight(double width) => _verticalPaddingFromShapes;
double computeMinIntrinsicHeight(double width) => _maxVerticalTrackPadding;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be math.max(minPreferredTrackHeight, maxSliderPartHeight)

Same change in performResize

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that is right. I changed it. Now the slider will size correctly if the track height is larger than the max height of the other parts.

Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
Comment thread packages/flutter/lib/src/material/slider_theme.dart Outdated
});

testWidgets('SliderThemeData assigns the correct default shapes', (WidgetTester tester) async {
final SliderThemeData sliderTheme = _createDefaultSliderTheme();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value should be ThemeData().sliderTheme.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

);
final SliderThemeData sliderTheme = theme.sliderTheme.copyWith(thumbColor: Colors.red.shade500);
double value = 0.25;
Widget buildApp({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One line:

Widget buildApp({ bool enabled = true }) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

bool enabled = true,
}) {
final ValueChanged<double> onChanged = enabled ? (double d) => value = d : null;
return Directionality(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK to must build a MaterialApp/Scaffold for tests like this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made to be consistent with other tests (using the "Directionality -> MediaQuery -> Material -> Center -> SLiderTheme -> Slider" tree structure.) Is this one different?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, just a suggestion since pasting things together by hand is tedious and doesn't actually test the common case (MaterialApp/Scaffold is the common case).

Comment thread packages/flutter/test/material/slider_theme_test.dart Outdated
Comment thread packages/flutter/test/material/slider_theme_test.dart Outdated

@HansMuller HansMuller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Hooray!

@johnsonmh johnsonmh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@clocksmith
clocksmith merged commit cfe992d into flutter:master Feb 1, 2019
kangwang1988 pushed a commit to XianyuTech/flutter that referenced this pull request Feb 12, 2019
…ider (flutter#25008)

Create a slider shape for custom track, tick mark, and overlay painting, for the material slider.
@clocksmith
clocksmith deleted the slider-track-painter branch September 12, 2019 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide ability to make origin of active track color in Slider start at arbitrary value

6 participants