mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Changes the offset computation to first item for RenderSliverMainAxisGroup (#154688)
Fixes https://github.com/flutter/flutter/issues/154615 When scrolling back to the top, the position of the first visible item should have its scrollExtent subtracted. Otherwise, the accumulated position may be retained, which may result in the first visible item being hidden in some cases.
This commit is contained in:
parent
19296abf85
commit
8cc862c727
@ -6,6 +6,7 @@
|
||||
library;
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'object.dart';
|
||||
@ -213,7 +214,14 @@ class RenderSliverMainAxisGroup extends RenderSliver with ContainerRenderObjectM
|
||||
double childScrollOffset = 0.0;
|
||||
RenderSliver? current = childBefore(child as RenderSliver);
|
||||
while (current != null) {
|
||||
childScrollOffset += current.geometry!.scrollExtent;
|
||||
// If the current child is not the first child, then we need to
|
||||
// add the scroll extent of the previous child to the current child's
|
||||
// scroll offset.
|
||||
if (childBefore(current) != null) {
|
||||
childScrollOffset += childAfter(current)!.geometry!.scrollExtent + child.geometry!.scrollExtent;
|
||||
} else if (!(childAfter(child) != null && current.geometry!.hasVisualOverflow)) {
|
||||
childScrollOffset += current.geometry!.scrollExtent;
|
||||
}
|
||||
current = childBefore(current);
|
||||
}
|
||||
return childScrollOffset;
|
||||
|
||||
@ -797,6 +797,64 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getTopLeft(find.byKey(key)), Offset.zero);
|
||||
});
|
||||
|
||||
testWidgets('SliverMainAxisGroup scrolls to the correct position when focusing on a text field within a header', (WidgetTester tester) async {
|
||||
final ScrollController controller = ScrollController();
|
||||
addTearDown(controller.dispose);
|
||||
final FocusNode textFieldFocus = FocusNode();
|
||||
addTearDown(textFieldFocus.dispose);
|
||||
final FocusNode textFieldFocus2 = FocusNode();
|
||||
addTearDown(textFieldFocus2.dispose);
|
||||
const ValueKey<int> firstTextFieldKey = ValueKey<int>(1);
|
||||
|
||||
await tester.pumpWidget(
|
||||
_buildSliverMainAxisGroup(
|
||||
controller: controller,
|
||||
slivers: <Widget>[
|
||||
SliverPersistentHeader(
|
||||
pinned: true,
|
||||
delegate: _SliverTitleDelegate(
|
||||
child: Container(
|
||||
color: Colors.red,
|
||||
height: 60.0,
|
||||
),
|
||||
height: 60.0,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Material(
|
||||
child: TextField(
|
||||
key: firstTextFieldKey,
|
||||
focusNode: textFieldFocus,
|
||||
),
|
||||
)),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
color: Colors.green,
|
||||
height: 500,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Material(
|
||||
child: TextField(
|
||||
focusNode: textFieldFocus2,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
textFieldFocus2.requestFocus();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
textFieldFocus.requestFocus();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(tester.getTopLeft(find.byKey(firstTextFieldKey)), const Offset(0, 60));
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildSliverList({
|
||||
@ -875,3 +933,26 @@ class TestDelegate extends SliverPersistentHeaderDelegate {
|
||||
@override
|
||||
bool shouldRebuild(TestDelegate oldDelegate) => true;
|
||||
}
|
||||
|
||||
class _SliverTitleDelegate extends SliverPersistentHeaderDelegate {
|
||||
_SliverTitleDelegate({
|
||||
required this.height,
|
||||
required this.child,
|
||||
});
|
||||
final double height;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
double get minExtent => height;
|
||||
@override
|
||||
double get maxExtent => height;
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||
return child;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRebuild(_SliverTitleDelegate oldDelegate) => true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user