Merge pull request #587 from abarth/sliders

Add a basic material slider
This commit is contained in:
Adam Barth 2015-11-25 12:34:09 -08:00
commit abce0533b4
4 changed files with 204 additions and 0 deletions

View file

@ -8,11 +8,13 @@ import 'chip_demo.dart';
import 'date_picker_demo.dart';
import 'drop_down_demo.dart';
import 'gallery_page.dart';
import 'slider_demo.dart';
import 'time_picker_demo.dart';
import 'widget_demo.dart';
final List<WidgetDemo> _kDemos = <WidgetDemo>[
kChipDemo,
kSliderDemo,
kDatePickerDemo,
kTimePickerDemo,
kDropDownDemo,

View file

@ -0,0 +1,45 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'widget_demo.dart';
class SliderDemo extends StatefulComponent {
_SliderDemoState createState() => new _SliderDemoState();
}
class _SliderDemoState extends State<SliderDemo> {
double _value = 0.25;
Widget build(BuildContext context) {
return new Block([
new Container(
height: 100.0,
child: new Center(
child: new Row([
new Slider(
value: _value,
onChanged: (double value) {
setState(() {
_value = value;
});
}
),
new Container(
padding: const EdgeDims.symmetric(horizontal: 16.0),
child: new Text(_value.toStringAsFixed(2))
),
], justifyContent: FlexJustifyContent.collapse)
)
)
]);
}
}
final WidgetDemo kSliderDemo = new WidgetDemo(
title: 'Sliders',
routeName: '/sliders',
builder: (_) => new SliderDemo()
);

View file

@ -45,6 +45,7 @@ export 'src/material/raised_button.dart';
export 'src/material/scaffold.dart';
export 'src/material/scrollbar_painter.dart';
export 'src/material/shadows.dart';
export 'src/material/slider.dart';
export 'src/material/snack_bar.dart';
export 'src/material/switch.dart';
export 'src/material/tabs.dart';

View file

@ -0,0 +1,156 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
import 'theme.dart';
const double _kThumbRadius = 6.0;
const double _kReactionRadius = 16.0;
const double _kTrackWidth = 144.0;
const int _kReactionAlpha = 0x33;
class Slider extends StatelessComponent {
Slider({ Key key, this.value, this.onChanged })
: super(key: key);
final double value;
final ValueChanged<double> onChanged;
Widget build(BuildContext context) {
return new _SliderRenderObjectWidget(
value: value,
primaryColor: Theme.of(context).accentColor,
onChanged: onChanged
);
}
}
class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
_SliderRenderObjectWidget({ Key key, this.value, this.primaryColor, this.onChanged })
: super(key: key);
final double value;
final Color primaryColor;
final ValueChanged<double> onChanged;
_RenderSlider createRenderObject() => new _RenderSlider(
value: value,
primaryColor: primaryColor,
onChanged: onChanged
);
void updateRenderObject(_RenderSlider renderObject, _SliderRenderObjectWidget oldWidget) {
renderObject.value = value;
renderObject.primaryColor = primaryColor;
renderObject.onChanged = onChanged;
}
}
final Color _kInactiveTrackColor = Colors.grey[400];
final Color _kActiveTrackColor = Colors.grey[500];
class _RenderSlider extends RenderConstrainedBox {
_RenderSlider({
double value,
Color primaryColor,
this.onChanged
}) : _value = value,
_primaryColor = primaryColor,
super(additionalConstraints: const BoxConstraints.tightFor(width: _kTrackWidth + 2 * _kReactionRadius, height: 2 * _kReactionRadius)) {
assert(value != null && value >= 0.0 && value <= 1.0);
_drag = new HorizontalDragGestureRecognizer(router: FlutterBinding.instance.pointerRouter)
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd;
}
double get value => _value;
double _value;
void set value(double newValue) {
assert(newValue != null && newValue >= 0.0 && newValue <= 1.0);
if (newValue == _value)
return;
_value = newValue;
markNeedsPaint();
}
Color get primaryColor => _primaryColor;
Color _primaryColor;
void set primaryColor(Color value) {
if (value == _primaryColor)
return;
_primaryColor = value;
markNeedsPaint();
}
ValueChanged<double> onChanged;
double get _trackLength => size.width - 2.0 * _kReactionRadius;
HorizontalDragGestureRecognizer _drag;
bool _active = false;
double _currentDragValue = 0.0;
void _handleDragStart(Point globalPosition) {
if (onChanged != null) {
_active = true;
_currentDragValue = globalToLocal(globalPosition).x / _trackLength;
onChanged(_currentDragValue.clamp(0.0, 1.0));
markNeedsPaint();
}
}
void _handleDragUpdate(double delta) {
if (onChanged != null) {
_currentDragValue += delta / _trackLength;
onChanged(_currentDragValue.clamp(0.0, 1.0));
}
}
void _handleDragEnd(Offset velocity) {
if (_active) {
_active = false;
_currentDragValue = 0.0;
markNeedsPaint();
}
}
bool hitTestSelf(Point position) => true;
void handleEvent(InputEvent event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown' && onChanged != null)
_drag.addPointer(event);
}
void paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas;
final double trackLength = _trackLength;
double trackCenter = offset.dy + size.height / 2.0;
double trackLeft = offset.dx + _kReactionRadius;
double trackTop = trackCenter - 1.0;
double trackBottom = trackCenter + 1.0;
double trackRight = trackLeft + trackLength;
double trackActive = trackLeft + trackLength * value;
Paint primaryPaint = new Paint()..color = _primaryColor;
Paint trackPaint = new Paint()..color = _active ? _kActiveTrackColor : _kInactiveTrackColor;
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackRight, trackBottom), trackPaint);
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackActive, trackBottom), primaryPaint);
Point activeLocation = new Point(trackActive, trackCenter);
if (_active) {
Paint reactionPaint = new Paint()..color = _primaryColor.withAlpha(_kReactionAlpha);
canvas.drawCircle(activeLocation, _kReactionRadius, reactionPaint);
}
canvas.drawCircle(activeLocation, _kThumbRadius, trackPaint);
}
}