Skip to content

Commit 4d47600

Browse files
authored
[Improve base View][1/n] Add subview handling to View (#99)
Summary This PR begins a stack of PRs that improves the base `View` class implemented in #80. This PR adds subview management to `View`, as there was a lot of duplicated subview handling code present in almost all our `View` subclasses. This also brings us closer to UIKit's `UIView`, which also handles its own subviews. Implements #95. Test Plan * `yarn start`: nothing broken * `yarn lint` * `yarn flow`: no errors in affected code * `yarn test`
1 parent 882bdbc commit 4d47600

8 files changed

Lines changed: 118 additions & 81 deletions

File tree

src/canvas/views/FlamechartView.js

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class FlamechartStackLayerView extends View {
244244
onHover(null);
245245
}
246246

247-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
247+
handleInteraction(interaction: Interaction) {
248248
switch (interaction.type) {
249249
case 'hover':
250250
this.handleHover(interaction);
@@ -295,7 +295,7 @@ export class FlamechartView extends View {
295295
colorView,
296296
this.verticalStackView,
297297
]);
298-
this.layerStackView.superview = this;
298+
this.addSubview(this.layerStackView);
299299
}
300300

301301
desiredSize() {
@@ -316,11 +316,6 @@ export class FlamechartView extends View {
316316
this.flamechartRowViews.forEach(rowView => (rowView.onHover = onHover));
317317
}
318318

319-
setNeedsDisplay() {
320-
super.setNeedsDisplay();
321-
this.layerStackView.setNeedsDisplay();
322-
}
323-
324319
layoutSubviews() {
325320
if (this.flamechartRowViews.length !== this.flamechart.length) {
326321
// TODO: Remove existing row views from verticalStackView
@@ -344,10 +339,6 @@ export class FlamechartView extends View {
344339
layerStackView.setVisibleArea(this.visibleArea);
345340
}
346341

347-
draw(context: CanvasRenderingContext2D) {
348-
this.layerStackView.displayIfNeeded(context);
349-
}
350-
351342
/**
352343
* @private
353344
*/
@@ -364,12 +355,11 @@ export class FlamechartView extends View {
364355
}
365356
}
366357

367-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
358+
handleInteraction(interaction: Interaction) {
368359
switch (interaction.type) {
369360
case 'hover':
370361
this.handleHover(interaction);
371362
break;
372363
}
373-
this.layerStackView.handleInteractionAndPropagateToSubviews(interaction);
374364
}
375365
}

src/canvas/views/ReactEventsView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export class ReactEventsView extends View {
236236
onHover(null);
237237
}
238238

239-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
239+
handleInteraction(interaction: Interaction) {
240240
switch (interaction.type) {
241241
case 'hover':
242242
this.handleHover(interaction);

src/canvas/views/ReactMeasuresView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export class ReactMeasuresView extends View {
294294
onHover(null);
295295
}
296296

297-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
297+
handleInteraction(interaction: Interaction) {
298298
switch (interaction.type) {
299299
case 'hover':
300300
this.handleHover(interaction);

src/layout/HorizontalPanAndZoomView.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ function zoomLevelAndIntrinsicWidthToFrameWidth(
5353
}
5454

5555
export class HorizontalPanAndZoomView extends View {
56+
/**
57+
* Reference to the content view. This view is also the only view in
58+
* `this.subviews`.
59+
*/
5660
contentView: View;
5761
intrinsicContentWidth: number;
5862

@@ -79,17 +83,12 @@ export class HorizontalPanAndZoomView extends View {
7983
) {
8084
super(surface, frame);
8185
this.contentView = contentView;
82-
contentView.superview = this;
86+
this.addSubview(this.contentView);
8387
this.intrinsicContentWidth = intrinsicContentWidth;
8488
if (stateDeriver) this.stateDeriver = stateDeriver;
8589
if (onStateChange) this.onStateChange = onStateChange;
8690
}
8791

88-
setNeedsDisplay() {
89-
super.setNeedsDisplay();
90-
this.contentView.setNeedsDisplay();
91-
}
92-
9392
setFrame(newFrame: Rect) {
9493
super.setFrame(newFrame);
9594

@@ -116,10 +115,6 @@ export class HorizontalPanAndZoomView extends View {
116115
this.contentView.setVisibleArea(this.visibleArea);
117116
}
118117

119-
draw(context: CanvasRenderingContext2D) {
120-
this.contentView.displayIfNeeded(context);
121-
}
122-
123118
isPanning = false;
124119

125120
handleHorizontalPanStart(interaction: HorizontalPanStartInteraction) {
@@ -214,7 +209,7 @@ export class HorizontalPanAndZoomView extends View {
214209
this.updateState(offsetAdjustedState);
215210
}
216211

217-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
212+
handleInteraction(interaction: Interaction) {
218213
switch (interaction.type) {
219214
case 'horizontal-pan-start':
220215
this.handleHorizontalPanStart(interaction);
@@ -234,7 +229,6 @@ export class HorizontalPanAndZoomView extends View {
234229
this.handleWheelZoom(interaction);
235230
break;
236231
}
237-
this.contentView.handleInteractionAndPropagateToSubviews(interaction);
238232
}
239233

240234
/**

src/layout/StaticLayoutView.js

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// @flow
22

3-
import type {Interaction} from '../useCanvasInteraction';
43
import type {Rect} from './geometry';
54

65
import {Surface} from './Surface';
@@ -39,28 +38,17 @@ export const verticallyStackedLayout: Layouter = (views, frame) => {
3938
};
4039

4140
export class StaticLayoutView extends View {
42-
subviews: View[] = [];
4341
layouter: Layouter;
4442

4543
constructor(
4644
surface: Surface,
4745
frame: Rect,
4846
layouter: Layouter,
49-
subviews: View[],
47+
initialSubviews: View[],
5048
) {
5149
super(surface, frame);
5250
this.layouter = layouter;
53-
subviews.forEach(subview => this.addSubview(subview));
54-
}
55-
56-
setNeedsDisplay() {
57-
super.setNeedsDisplay();
58-
this.subviews.forEach(subview => subview.setNeedsDisplay());
59-
}
60-
61-
addSubview(view: View) {
62-
this.subviews.push(view);
63-
view.superview = this;
51+
initialSubviews.forEach(subview => this.addSubview(subview));
6452
}
6553

6654
layoutSubviews() {
@@ -76,19 +64,4 @@ export class StaticLayoutView extends View {
7664
}
7765
});
7866
}
79-
80-
draw(context: CanvasRenderingContext2D) {
81-
const {subviews, visibleArea} = this;
82-
subviews.forEach(subview => {
83-
if (rectIntersectsRect(visibleArea, subview.visibleArea)) {
84-
subview.displayIfNeeded(context);
85-
}
86-
});
87-
}
88-
89-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
90-
this.subviews.forEach(subview =>
91-
subview.handleInteractionAndPropagateToSubviews(interaction),
92-
);
93-
}
9467
}

src/layout/Surface.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ import {getCanvasContext} from '../canvas/canvasUtils';
88
import {View} from './View';
99
import {zeroPoint} from './geometry';
1010

11+
/**
12+
* Represents the canvas surface and a view heirarchy. A surface is also the
13+
* place where all interactions enter the view heirarchy.
14+
*/
1115
export class Surface {
1216
rootView: ?View;
1317
context: ?CanvasRenderingContext2D;

src/layout/VerticalScrollView.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ function clamp(min: number, max: number, value: number): number {
3636
}
3737

3838
export class VerticalScrollView extends View {
39+
/**
40+
* Reference to the content view. This view is also the only view in
41+
* `this.subviews`.
42+
*/
3943
contentView: View;
4044

4145
scrollState: VerticalScrollState = {
@@ -56,16 +60,11 @@ export class VerticalScrollView extends View {
5660
) {
5761
super(surface, frame);
5862
this.contentView = contentView;
59-
contentView.superview = this;
63+
this.addSubview(this.contentView);
6064
if (stateDeriver) this.stateDeriver = stateDeriver;
6165
if (onStateChange) this.onStateChange = onStateChange;
6266
}
6367

64-
setNeedsDisplay() {
65-
super.setNeedsDisplay();
66-
this.contentView.setNeedsDisplay();
67-
}
68-
6968
setFrame(newFrame: Rect) {
7069
super.setFrame(newFrame);
7170

@@ -96,10 +95,6 @@ export class VerticalScrollView extends View {
9695
this.contentView.setVisibleArea(this.visibleArea);
9796
}
9897

99-
draw(context: CanvasRenderingContext2D) {
100-
this.contentView.displayIfNeeded(context);
101-
}
102-
10398
isPanning = false;
10499

105100
handleVerticalPanStart(interaction: VerticalPanStartInteraction) {
@@ -151,7 +146,7 @@ export class VerticalScrollView extends View {
151146
});
152147
}
153148

154-
handleInteractionAndPropagateToSubviews(interaction: Interaction) {
149+
handleInteraction(interaction: Interaction) {
155150
switch (interaction.type) {
156151
case 'vertical-pan-start':
157152
this.handleVerticalPanStart(interaction);
@@ -166,7 +161,6 @@ export class VerticalScrollView extends View {
166161
this.handleWheelPlain(interaction);
167162
break;
168163
}
169-
this.contentView.handleInteractionAndPropagateToSubviews(interaction);
170164
}
171165

172166
/**

0 commit comments

Comments
 (0)