OLD | NEW |
| (Empty) |
1 part of widgets; | |
2 | |
3 abstract class FixedHeightScrollable extends Component { | |
4 | |
5 // TODO(rafaelw): This component really shouldn't have an opinion | |
6 // about how it is sized. The owning component should decide whether | |
7 // it's explicitly sized or flexible or whatever... | |
8 static Style _style = new Style(''' | |
9 overflow: hidden; | |
10 position: relative; | |
11 flex: 1; | |
12 will-change: transform;''' | |
13 ); | |
14 | |
15 static Style _scrollAreaStyle = new Style(''' | |
16 position:relative; | |
17 will-change: transform;''' | |
18 ); | |
19 | |
20 double minOffset; | |
21 double maxOffset; | |
22 | |
23 double _scrollOffset = 0.0; | |
24 FlingCurve _flingCurve; | |
25 int _flingAnimationId; | |
26 double _height = 0.0; | |
27 double _itemHeight; | |
28 | |
29 FixedHeightScrollable({ | |
30 Object key, | |
31 this.minOffset, | |
32 this.maxOffset | |
33 }) : super(key: key) {} | |
34 | |
35 List<Node> buildItems(int start, int count); | |
36 | |
37 void didMount() { | |
38 var root = getRoot(); | |
39 var item = root.firstChild.firstChild; | |
40 sky.ClientRect scrollRect = root.getBoundingClientRect(); | |
41 sky.ClientRect itemRect = item.getBoundingClientRect(); | |
42 assert(scrollRect.height > 0); | |
43 assert(itemRect.height > 0); | |
44 | |
45 setState(() { | |
46 _height = scrollRect.height; | |
47 _itemHeight = itemRect.height; | |
48 }); | |
49 } | |
50 | |
51 Node build() { | |
52 var itemNumber = 0; | |
53 var drawCount = 1; | |
54 var transformStyle = ''; | |
55 | |
56 if (_height > 0.0) { | |
57 drawCount = (_height / _itemHeight).round() + 1; | |
58 double alignmentDelta = -_scrollOffset % _itemHeight; | |
59 if (alignmentDelta != 0.0) { | |
60 alignmentDelta -= _itemHeight; | |
61 } | |
62 | |
63 double drawStart = _scrollOffset + alignmentDelta; | |
64 itemNumber = (drawStart / _itemHeight).floor(); | |
65 | |
66 transformStyle = | |
67 'transform: translateY(${(alignmentDelta).toStringAsFixed(2)}px)'; | |
68 } | |
69 | |
70 return new Container( | |
71 style: _style, | |
72 children: [ | |
73 new Container( | |
74 style: _scrollAreaStyle, | |
75 inlineStyle: transformStyle, | |
76 children: buildItems(itemNumber, drawCount) | |
77 ) | |
78 ] | |
79 ) | |
80 ..events.listen('gestureflingstart', _handleFlingStart) | |
81 ..events.listen('gestureflingcancel', _handleFlingCancel) | |
82 ..events.listen('gesturescrollupdate', _handleScrollUpdate) | |
83 ..events.listen('wheel', _handleWheel); | |
84 } | |
85 | |
86 void didUnmount() { | |
87 _stopFling(); | |
88 } | |
89 | |
90 bool _scrollBy(double scrollDelta) { | |
91 var newScrollOffset = _scrollOffset + scrollDelta; | |
92 if (minOffset != null && newScrollOffset < minOffset) { | |
93 newScrollOffset = minOffset; | |
94 } else if (maxOffset != null && newScrollOffset > maxOffset) { | |
95 newScrollOffset = maxOffset; | |
96 } | |
97 if (newScrollOffset == _scrollOffset) { | |
98 return false; | |
99 } | |
100 | |
101 setState(() { | |
102 _scrollOffset = newScrollOffset; | |
103 }); | |
104 return true; | |
105 } | |
106 | |
107 void _scheduleFlingUpdate() { | |
108 _flingAnimationId = sky.window.requestAnimationFrame(_updateFling); | |
109 } | |
110 | |
111 void _stopFling() { | |
112 if (_flingAnimationId == null) { | |
113 return; | |
114 } | |
115 | |
116 sky.window.cancelAnimationFrame(_flingAnimationId); | |
117 _flingCurve = null; | |
118 _flingAnimationId = null; | |
119 } | |
120 | |
121 void _updateFling(double timeStamp) { | |
122 double scrollDelta = _flingCurve.update(timeStamp); | |
123 if (!_scrollBy(scrollDelta)) | |
124 return _stopFling(); | |
125 _scheduleFlingUpdate(); | |
126 } | |
127 | |
128 void _handleScrollUpdate(sky.GestureEvent event) { | |
129 _scrollBy(-event.dy); | |
130 } | |
131 | |
132 void _handleFlingStart(sky.GestureEvent event) { | |
133 setState(() { | |
134 _flingCurve = new FlingCurve(-event.velocityY, event.timeStamp); | |
135 _scheduleFlingUpdate(); | |
136 }); | |
137 } | |
138 | |
139 void _handleFlingCancel(sky.GestureEvent event) { | |
140 _stopFling(); | |
141 } | |
142 | |
143 void _handleWheel(sky.WheelEvent event) { | |
144 _scrollBy(-event.offsetY); | |
145 } | |
146 } | |
OLD | NEW |