1
1
using System ;
2
- using System . Collections . Generic ;
3
2
using Unity . UIWidgets . animation ;
4
3
using Unity . UIWidgets . async ;
5
4
using Unity . UIWidgets . foundation ;
10
9
using Unity . UIWidgets . ui ;
11
10
using Unity . UIWidgets . widgets ;
12
11
using UnityEngine ;
12
+ using Canvas = Unity . UIWidgets . ui . Canvas ;
13
13
using Color = Unity . UIWidgets . ui . Color ;
14
14
using Rect = Unity . UIWidgets . ui . Rect ;
15
15
@@ -253,14 +253,6 @@ public override void updateRenderObject(BuildContext context, RenderObject rende
253
253
}
254
254
255
255
class _RenderSlider : RenderBox {
256
- //static TimeSpan _positionAnimationDuration = new TimeSpan(0, 0, 0, 0, 75);
257
- //static TimeSpan _minimumInteractionTime = new TimeSpan(0, 0, 0, 0, 500);
258
-
259
- static float _positionAnimationDurationMilliSeconds = 75 ;
260
- static float _minimumInteractionTimeMilliSeconds = 500 ;
261
-
262
- const float _minPreferredTrackWidth = 144.0f ;
263
-
264
256
public _RenderSlider (
265
257
float ? value = null ,
266
258
int ? divisions = null ,
@@ -287,7 +279,7 @@ public _RenderSlider(
287
279
this . _mediaQueryData = mediaQueryData ;
288
280
this . _onChanged = onChanged ;
289
281
this . _state = state ;
290
-
282
+
291
283
this . _updateLabelPainter ( ) ;
292
284
GestureArenaTeam team = new GestureArenaTeam ( ) ;
293
285
this . _drag = new HorizontalDragGestureRecognizer {
@@ -304,64 +296,28 @@ public _RenderSlider(
304
296
onTapUp = this . _handleTapUp ,
305
297
onTapCancel = this . _endInteraction
306
298
} ;
307
-
299
+
308
300
this . _overlayAnimation = new CurvedAnimation (
309
301
parent : this . _state . overlayController ,
310
302
curve : Curves . fastOutSlowIn ) ;
311
-
303
+
312
304
this . _valueIndicatorAnimation = new CurvedAnimation (
313
305
parent : this . _state . valueIndicatorController ,
314
306
curve : Curves . fastOutSlowIn ) ;
315
-
307
+
316
308
this . _enableAnimation = new CurvedAnimation (
317
309
parent : this . _state . enableController ,
318
310
curve : Curves . easeInOut ) ;
319
311
}
320
312
321
- float _maxSliderPartWidth {
322
- get {
323
- float maxValue = 0 ;
324
- foreach ( Size size in this . _sliderPartSizes ) {
325
- if ( size . width > maxValue ) {
326
- maxValue = size . width ;
327
- }
328
- }
329
- return maxValue ;
330
- }
331
- }
332
-
333
- float _maxSliderPartHeight {
334
- get {
335
- float maxValue = 0 ;
336
- foreach ( Size size in this . _sliderPartSizes ) {
337
- if ( size . width > maxValue ) {
338
- maxValue = size . width ;
339
- }
340
- }
341
- return maxValue ; }
342
- }
343
-
344
- List < Size > __sliderPartSizes ;
345
- List < Size > _sliderPartSizes {
346
- get {
347
- if ( this . __sliderPartSizes != null ) {
348
- return this . __sliderPartSizes ;
349
- }
350
-
351
- this . __sliderPartSizes = new List < Size > {
352
- this . _sliderTheme . overlayShape . getPreferredSize ( this . isInteractive , this . isDiscrete ) ,
353
- this . _sliderTheme . thumbShape . getPreferredSize ( this . isInteractive , this . isDiscrete ) ,
354
- this . _sliderTheme . tickMarkShape . getPreferredSize ( isEnabled : this . isInteractive ,
355
- sliderTheme : this . sliderTheme )
356
- } ;
357
-
358
- return this . __sliderPartSizes ;
359
- }
360
- }
361
-
362
- float _minPreferredTrackHeight {
363
- get { return this . _sliderTheme . trackHeight ; }
364
- }
313
+ const float _positionAnimationDurationMilliSeconds = 75 ;
314
+ const float _overlayRadius = 16.0f ;
315
+ const float _overlayDiameter = _overlayRadius * 2.0f ;
316
+ const float _trackHeight = 2.0f ;
317
+ const float _preferredTrackWidth = 144.0f ;
318
+ const float _preferredTotalWidth = _preferredTrackWidth + _overlayDiameter ;
319
+ const float _minimumInteractionTimeMilliSeconds = 500 ;
320
+ static readonly Animatable < float > _overlayRadiusTween = new FloatTween ( begin : 0.0f , end : _overlayRadius ) ;
365
321
366
322
_SliderState _state ;
367
323
Animation < float > _overlayAnimation ;
@@ -373,15 +329,8 @@ float _minPreferredTrackHeight {
373
329
bool _active = false ;
374
330
float _currentDragValue = 0.0f ;
375
331
376
- Rect _trackRect {
377
- get {
378
- return this . _sliderTheme . trackShape . getPreferredRect (
379
- parentBox : this ,
380
- offset : Offset . zero ,
381
- sliderTheme : this . _sliderTheme ,
382
- isDiscrete : false
383
- ) ;
384
- }
332
+ float _trackLength {
333
+ get { return this . size . width - _overlayDiameter ; }
385
334
}
386
335
387
336
bool isInteractive {
@@ -405,7 +354,7 @@ public float value {
405
354
if ( this . isDiscrete ) {
406
355
float distance = ( this . _value - this . _state . positionController . value ) . abs ( ) ;
407
356
this . _state . positionController . duration = distance != 0.0f
408
- ? new TimeSpan ( 0 , 0 , 0 , 0 , ( int ) ( _positionAnimationDurationMilliSeconds * ( 1.0f / distance ) ) )
357
+ ? new TimeSpan ( 0 , 0 , 0 , 0 , ( int ) ( _positionAnimationDurationMilliSeconds * ( 1.0f / distance ) ) )
409
358
: TimeSpan . Zero ;
410
359
this . _state . positionController . animateTo ( convertedValue , curve : Curves . easeInOut ) ;
411
360
}
@@ -438,6 +387,7 @@ public int? divisions {
438
387
}
439
388
440
389
this . _divisions = value ;
390
+ this . markNeedsPaint ( ) ;
441
391
}
442
392
}
443
393
@@ -598,7 +548,7 @@ float _getValueFromVisualPosition(float visualPosition) {
598
548
599
549
float _getValueFromGlobalPosition ( Offset globalPosition ) {
600
550
float visualPosition =
601
- ( this . globalToLocal ( globalPosition ) . dx - this . _trackRect . left ) / this . _trackRect . width ;
551
+ ( this . globalToLocal ( globalPosition ) . dx - _overlayRadius ) / this . _trackLength ;
602
552
return this . _getValueFromVisualPosition ( visualPosition ) ;
603
553
}
604
554
@@ -625,13 +575,16 @@ void _startInteraction(Offset globalPosition) {
625
575
if ( this . showValueIndicator ) {
626
576
this . _state . valueIndicatorController . forward ( ) ;
627
577
this . _state . interactionTimer ? . cancel ( ) ;
628
- this . _state . interactionTimer = Window . instance . run ( new TimeSpan ( 0 , 0 , 0 , 0 , ( int ) ( _minimumInteractionTimeMilliSeconds * SchedulerBinding . instance . timeDilation ) ) , ( ) => {
629
- this . _state . interactionTimer = null ;
630
- if ( ! this . _active &&
631
- this . _state . valueIndicatorController . status == AnimationStatus . completed ) {
632
- this . _state . valueIndicatorController . reverse ( ) ;
633
- }
634
- } ) ;
578
+ this . _state . interactionTimer = Window . instance . run (
579
+ new TimeSpan ( 0 , 0 , 0 , 0 ,
580
+ ( int ) ( _minimumInteractionTimeMilliSeconds * SchedulerBinding . instance . timeDilation ) ) ,
581
+ ( ) => {
582
+ this . _state . interactionTimer = null ;
583
+ if ( ! this . _active &&
584
+ this . _state . valueIndicatorController . status == AnimationStatus . completed ) {
585
+ this . _state . valueIndicatorController . reverse ( ) ;
586
+ }
587
+ } ) ;
635
588
}
636
589
}
637
590
}
@@ -657,7 +610,7 @@ void _handleDragStart(DragStartDetails details) {
657
610
658
611
void _handleDragUpdate ( DragUpdateDetails details ) {
659
612
if ( this . isInteractive ) {
660
- float valueDelta = details . primaryDelta . Value / this . _trackRect . width ;
613
+ float valueDelta = details . primaryDelta . Value / this . _trackLength ;
661
614
this . _currentDragValue += valueDelta ;
662
615
this . onChanged ( this . _discretize ( this . _currentDragValue ) ) ;
663
616
}
@@ -689,19 +642,20 @@ public override void handleEvent(PointerEvent evt, HitTestEntry entry) {
689
642
690
643
691
644
protected override float computeMinIntrinsicWidth ( float height ) {
692
- return _minPreferredTrackWidth + this . _maxSliderPartWidth ;
645
+ return Mathf . Max ( _overlayDiameter ,
646
+ this . _sliderTheme . thumbShape . getPreferredSize ( this . isInteractive , this . isDiscrete ) . width ) ;
693
647
}
694
648
695
649
protected override float computeMaxIntrinsicWidth ( float height ) {
696
- return _minPreferredTrackWidth + this . _maxSliderPartWidth ;
650
+ return _preferredTotalWidth ;
697
651
}
698
652
699
653
protected override float computeMinIntrinsicHeight ( float width ) {
700
- return Mathf . Max ( this . _minPreferredTrackHeight , this . _maxSliderPartHeight ) ;
654
+ return _overlayDiameter ;
701
655
}
702
656
703
657
protected override float computeMaxIntrinsicHeight ( float width ) {
704
- return Mathf . Max ( this . _minPreferredTrackHeight , this . _maxSliderPartHeight ) ;
658
+ return _overlayDiameter ;
705
659
}
706
660
707
661
protected override bool sizedByParent {
@@ -712,78 +666,114 @@ protected override void performResize() {
712
666
this . size = new Size (
713
667
this . constraints . hasBoundedWidth
714
668
? this . constraints . maxWidth
715
- : _minPreferredTrackWidth + this . _maxSliderPartWidth ,
669
+ : _preferredTotalWidth ,
716
670
this . constraints . hasBoundedHeight
717
671
? this . constraints . maxHeight
718
- : Mathf . Max ( this . _minPreferredTrackHeight , this . _maxSliderPartHeight )
672
+ : _overlayDiameter
719
673
) ;
720
674
}
721
675
722
- public override void paint ( PaintingContext context , Offset offset ) {
723
- float value = this . _state . positionController . value ;
724
- float visualPosition = value ;
676
+ void _paintTickMarks (
677
+ Canvas canvas ,
678
+ Rect trackLeft ,
679
+ Rect trackRight ,
680
+ Paint leftPaint ,
681
+ Paint rightPaint ) {
682
+ if ( this . isDiscrete ) {
683
+ const float tickRadius = _trackHeight / 2.0f ;
684
+ float trackWidth = trackRight . right - trackLeft . left ;
685
+ float dx = ( trackWidth - _trackHeight ) / this . divisions . Value ;
686
+
687
+ if ( dx >= 3.0 * _trackHeight ) {
688
+ for ( int i = 0 ; i <= this . divisions . Value ; i += 1 ) {
689
+ float left = trackLeft . left + i * dx ;
690
+ Offset center = new Offset ( left + tickRadius , trackLeft . top + tickRadius ) ;
691
+ if ( trackLeft . contains ( center ) ) {
692
+ canvas . drawCircle ( center , tickRadius , leftPaint ) ;
693
+ }
694
+ else if ( trackRight . contains ( center ) ) {
695
+ canvas . drawCircle ( center , tickRadius , rightPaint ) ;
696
+ }
697
+ }
698
+ }
699
+ }
700
+ }
725
701
726
- Rect trackRect = this . _sliderTheme . trackShape . getPreferredRect (
727
- parentBox : this ,
728
- offset : offset ,
729
- sliderTheme : this . _sliderTheme ,
730
- isDiscrete : this . isDiscrete
731
- ) ;
702
+ void _paintOverlay (
703
+ Canvas canvas ,
704
+ Offset center ) {
705
+ Paint overlayPaint = new Paint { color = this . _sliderTheme . overlayColor } ;
706
+ float radius = _overlayRadiusTween . evaluate ( this . _overlayAnimation ) ;
707
+ canvas . drawCircle ( center , radius , overlayPaint ) ;
708
+ }
732
709
733
- Offset thumbCenter = new Offset ( trackRect . left + visualPosition * trackRect . width , trackRect . center . dy ) ;
710
+ public override void paint ( PaintingContext context , Offset offset ) {
711
+ Canvas canvas = context . canvas ;
734
712
735
- this . _sliderTheme . trackShape . paint (
736
- context ,
737
- offset ,
738
- parentBox : this ,
739
- sliderTheme : this . _sliderTheme ,
740
- enableAnimation : this . _enableAnimation ,
741
- thumbCenter : thumbCenter ,
742
- isDiscrete : this . isDiscrete ,
743
- isEnabled : this . isInteractive
744
- ) ;
713
+ float trackLength = this . size . width - 2 * _overlayRadius ;
714
+ float value = this . _state . positionController . value ;
715
+ ColorTween activeTrackEnableColor = new ColorTween ( begin : this . _sliderTheme . disabledActiveTrackColor ,
716
+ end : this . _sliderTheme . activeTrackColor ) ;
717
+ ColorTween inactiveTrackEnableColor = new ColorTween ( begin : this . _sliderTheme . disabledInactiveTrackColor ,
718
+ end : this . _sliderTheme . inactiveTrackColor ) ;
719
+ ColorTween activeTickMarkEnableColor = new ColorTween ( begin : this . _sliderTheme . disabledActiveTickMarkColor ,
720
+ end : this . _sliderTheme . activeTickMarkColor ) ;
721
+ ColorTween inactiveTickMarkEnableColor =
722
+ new ColorTween ( begin : this . _sliderTheme . disabledInactiveTickMarkColor ,
723
+ end : this . _sliderTheme . inactiveTickMarkColor ) ;
724
+
725
+ Paint activeTrackPaint = new Paint { color = activeTrackEnableColor . evaluate ( this . _enableAnimation ) } ;
726
+ Paint inactiveTrackPaint = new Paint { color = inactiveTrackEnableColor . evaluate ( this . _enableAnimation ) } ;
727
+ Paint activeTickMarkPaint = new Paint { color = activeTickMarkEnableColor . evaluate ( this . _enableAnimation ) } ;
728
+ Paint inactiveTickMarkPaint = new Paint
729
+ { color = inactiveTickMarkEnableColor . evaluate ( this . _enableAnimation ) } ;
745
730
746
- if ( ! this . _overlayAnimation . isDismissed ) {
747
- this . _sliderTheme . overlayShape . paint (
748
- context ,
749
- thumbCenter ,
750
- activationAnimation : this . _overlayAnimation ,
751
- enableAnimation : this . _enableAnimation ,
752
- isDiscrete : this . isDiscrete ,
753
- labelPainter : this . _labelPainter ,
754
- parentBox : this ,
755
- sliderTheme : this . _sliderTheme ,
756
- value : this . _value
757
- ) ;
731
+ float visualPosition = value ;
732
+ Paint leftTrackPaint = activeTrackPaint ;
733
+ Paint rightTrackPaint = inactiveTrackPaint ;
734
+ Paint leftTickMarkPaint = activeTickMarkPaint ;
735
+ Paint rightTickMarkPaint = inactiveTickMarkPaint ;
736
+
737
+ float trackRadius = _trackHeight / 2.0f ;
738
+ float thumbGap = 2.0f ;
739
+
740
+ float trackVerticalCenter = offset . dy + ( this . size . height ) / 2.0f ;
741
+ float trackLeft = offset . dx + _overlayRadius ;
742
+ float trackTop = trackVerticalCenter - trackRadius ;
743
+ float trackBottom = trackVerticalCenter + trackRadius ;
744
+ float trackRight = trackLeft + trackLength ;
745
+ float trackActive = trackLeft + trackLength * visualPosition ;
746
+ float thumbRadius =
747
+ this . _sliderTheme . thumbShape . getPreferredSize ( this . isInteractive , this . isDiscrete ) . width / 2.0f ;
748
+ float trackActiveLeft = Mathf . Max ( 0.0f ,
749
+ trackActive - thumbRadius - thumbGap * ( 1.0f - this . _enableAnimation . value ) ) ;
750
+ float trackActiveRight =
751
+ Mathf . Min ( trackActive + thumbRadius + thumbGap * ( 1.0f - this . _enableAnimation . value ) , trackRight ) ;
752
+ Rect trackLeftRect = Rect . fromLTRB ( trackLeft , trackTop , trackActiveLeft , trackBottom ) ;
753
+ Rect trackRightRect = Rect . fromLTRB ( trackActiveRight , trackTop , trackRight , trackBottom ) ;
754
+
755
+ Offset thumbCenter = new Offset ( trackActive , trackVerticalCenter ) ;
756
+
757
+ if ( visualPosition > 0.0 ) {
758
+ canvas . drawRect ( trackLeftRect , leftTrackPaint ) ;
758
759
}
759
760
760
- if ( this . isDiscrete ) {
761
- float tickMarkWidth = this . _sliderTheme . tickMarkShape . getPreferredSize (
762
- isEnabled : this . isInteractive ,
763
- sliderTheme : this . _sliderTheme
764
- ) . width ;
765
-
766
- if ( ( trackRect . width - tickMarkWidth ) / this . divisions . Value >= 3.0f * tickMarkWidth ) {
767
- for ( int i = 0 ; i <= this . divisions ; i ++ ) {
768
- float tickValue = i / this . divisions . Value ;
769
- float tickX = trackRect . left +
770
- tickValue * ( trackRect . width - tickMarkWidth ) + tickMarkWidth / 2 ;
771
- float tickY = trackRect . center . dy ;
772
- Offset tickMarkOffset = new Offset ( tickX , tickY ) ;
773
- this . _sliderTheme . tickMarkShape . paint (
774
- context ,
775
- tickMarkOffset ,
776
- parentBox : this ,
777
- sliderTheme : this . _sliderTheme ,
778
- enableAnimation : this . _enableAnimation ,
779
- thumbCenter : thumbCenter ,
780
- isEnabled : this . isInteractive
781
- ) ;
782
- }
783
- }
761
+ if ( visualPosition < 1.0 ) {
762
+ canvas . drawRect ( trackRightRect , rightTrackPaint ) ;
784
763
}
785
764
786
- if ( this . isInteractive && this . label != null && ! this . _valueIndicatorAnimation . isDismissed ) {
765
+ this . _paintOverlay ( canvas , thumbCenter ) ;
766
+
767
+ this . _paintTickMarks (
768
+ canvas ,
769
+ trackLeftRect ,
770
+ trackRightRect ,
771
+ leftTickMarkPaint ,
772
+ rightTickMarkPaint
773
+ ) ;
774
+
775
+ if ( this . isInteractive && this . label != null &&
776
+ this . _valueIndicatorAnimation . status != AnimationStatus . dismissed ) {
787
777
if ( this . showValueIndicator ) {
788
778
this . _sliderTheme . valueIndicatorShape . paint (
789
779
context ,
0 commit comments