fix issue 30526: rounding error (#30979)
This commit is contained in:
parent
4230e9674c
commit
caebdaf1e8
@ -65,7 +65,15 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
||||
/// order, without gaps, starting from layout offset zero.
|
||||
@protected
|
||||
int getMinChildIndexForScrollOffset(double scrollOffset, double itemExtent) {
|
||||
return itemExtent > 0.0 ? math.max(0, scrollOffset ~/ itemExtent) : 0;
|
||||
if (itemExtent > 0.0) {
|
||||
final double actual = scrollOffset / itemExtent;
|
||||
final int round = actual.round();
|
||||
if ((actual - round).abs() < precisionErrorTolerance) {
|
||||
return round;
|
||||
}
|
||||
return actual.floor();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// The maximum child index that is visible at the given scroll offset.
|
||||
@ -224,7 +232,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
|
||||
final double leadingScrollOffset = indexToLayoutOffset(itemExtent, firstIndex);
|
||||
final double trailingScrollOffset = indexToLayoutOffset(itemExtent, lastIndex + 1);
|
||||
|
||||
assert(firstIndex == 0 || childScrollOffset(firstChild) <= scrollOffset);
|
||||
assert(firstIndex == 0 || childScrollOffset(firstChild) - scrollOffset <= precisionErrorTolerance);
|
||||
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
||||
assert(indexOf(firstChild) == firstIndex);
|
||||
assert(targetLastIndex == null || lastIndex <= targetLastIndex);
|
||||
|
@ -0,0 +1,106 @@
|
||||
// Copyright 2019 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/foundation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import '../flutter_test_alternative.dart';
|
||||
|
||||
import 'rendering_tester.dart';
|
||||
|
||||
void main() {
|
||||
test('RenderSliverFixedExtentList layout test - rounding error', () {
|
||||
final List<RenderBox> children = <RenderBox>[
|
||||
RenderSizedBox(const Size(400.0, 100.0)),
|
||||
RenderSizedBox(const Size(400.0, 100.0)),
|
||||
RenderSizedBox(const Size(400.0, 100.0))
|
||||
];
|
||||
final TestRenderSliverBoxChildManager childManager = TestRenderSliverBoxChildManager(
|
||||
children: children,
|
||||
);
|
||||
final RenderViewport root = RenderViewport(
|
||||
axisDirection: AxisDirection.down,
|
||||
crossAxisDirection: AxisDirection.right,
|
||||
offset: ViewportOffset.zero(),
|
||||
cacheExtent: 0,
|
||||
children: <RenderSliver>[
|
||||
childManager.createRenderSliverFillViewport(),
|
||||
],
|
||||
);
|
||||
layout(root);
|
||||
expect(children[0].attached, true);
|
||||
expect(children[1].attached, false);
|
||||
|
||||
root.offset = ViewportOffset.fixed(600);
|
||||
pumpFrame();
|
||||
expect(children[0].attached, false);
|
||||
expect(children[1].attached, true);
|
||||
|
||||
// Simulate double precision error.
|
||||
root.offset = ViewportOffset.fixed(1199.999999999998);
|
||||
pumpFrame();
|
||||
expect(children[1].attached, false);
|
||||
expect(children[2].attached, true);
|
||||
});
|
||||
}
|
||||
|
||||
class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
|
||||
TestRenderSliverBoxChildManager({
|
||||
this.children,
|
||||
});
|
||||
|
||||
RenderSliverMultiBoxAdaptor _renderObject;
|
||||
List<RenderBox> children;
|
||||
|
||||
RenderSliverFillViewport createRenderSliverFillViewport() {
|
||||
assert(_renderObject == null);
|
||||
_renderObject = RenderSliverFillViewport(
|
||||
childManager: this,
|
||||
);
|
||||
return _renderObject;
|
||||
}
|
||||
|
||||
int _currentlyUpdatingChildIndex;
|
||||
|
||||
@override
|
||||
void createChild(int index, { @required RenderBox after }) {
|
||||
if (index < 0 || index >= children.length)
|
||||
return;
|
||||
try {
|
||||
_currentlyUpdatingChildIndex = index;
|
||||
_renderObject.insert(children[index], after: after);
|
||||
} finally {
|
||||
_currentlyUpdatingChildIndex = null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void removeChild(RenderBox child) {
|
||||
_renderObject.remove(child);
|
||||
}
|
||||
|
||||
@override
|
||||
double estimateMaxScrollOffset(
|
||||
SliverConstraints constraints, {
|
||||
int firstIndex,
|
||||
int lastIndex,
|
||||
double leadingScrollOffset,
|
||||
double trailingScrollOffset,
|
||||
}) {
|
||||
assert(lastIndex >= firstIndex);
|
||||
return children.length * (trailingScrollOffset - leadingScrollOffset) / (lastIndex - firstIndex + 1);
|
||||
}
|
||||
|
||||
@override
|
||||
int get childCount => children.length;
|
||||
|
||||
@override
|
||||
void didAdoptChild(RenderBox child) {
|
||||
assert(_currentlyUpdatingChildIndex != null);
|
||||
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
|
||||
childParentData.index = _currentlyUpdatingChildIndex;
|
||||
}
|
||||
|
||||
@override
|
||||
void setDidUnderflow(bool value) { }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user