Skip to content

Conversation

@LongCatIsLooong
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong commented Jul 10, 2019

Description

  • Introduce SliverLayoutBuilder.

Related Issues

Closes #35927

Tests

I added the following tests:

SliverLayoutBuilder versions of most LayoutBuilder tests

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Does your PR require Flutter developers to manually update their apps to accommodate your change?

  • No, this is not a breaking change.

@LongCatIsLooong LongCatIsLooong added f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. labels Jul 10, 2019
@chunhtai
Copy link
Contributor

chunhtai commented Jul 15, 2019

A thought I have after look at the pr, instead of doing the inherit structure, you can try to wrap Layoutbuilder by using SliverConstraints.asBoxConstraints to convert the constraints that passed down to builder and RenderSliverToBoxAdapter to convert the renderbox back to rendersliver. This should make it a SliverLayoutbuilder.

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, I leave some minor comment.
I do not have enough background on this. Can you explain more how this can help we solve #23873? What are the obstacle we facing if we don't have SliverLayoutBuilder?

void applyPaintTransform(RenderObject child, Matrix4 transform) {
assert(child != null);
assert(child == this.child);
// No-op because child's offset is always (0, 0),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use the word 'no-op' in our documentation. maybe 'It does not require transformation because..."

final RenderBox renderChild1 = tester.renderObject(find.byKey(childKey1));
final RenderBox renderChild2 = tester.renderObject(find.byKey(childKey2));

// scrollController.scrollOffset = 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end with dot

typedef SliverLayoutWidgetBuilder = Widget Function(BuildContext context, SliverConstraints constraints);

// A widget that defers its building until layout.
abstract class _GenericLayoutBuilder<ConstraintType extends Constraints> extends RenderObjectWidget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after talked with @dnfield offline, it feels strange that we have public class inherit from private class, let's make this class public. In that class, the build property can documented here instead of duplicated in two subclass.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this could be called ConstrainedLayoutBuilder

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also exposed RenderConstrainedLayoutBuilder for subclassing. _LayoutBuilderElement should be generic enough to stay private.

Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parts I looked at LGTM, I'll defer to @chunhtai to finish the rest of his review

if (child != null)
context.paintChild(child, offset);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe outsource the sliver stuff in a separate sliver_layout_builder.dart file?

mixin RenderConstrainedLayoutBuilder<ConstraintType extends Constraints, ChildType extends RenderObject> on RenderObjectWithChildMixin<ChildType> {
LayoutCallback<ConstraintType> _callback;
/// Change the layout callback.
set callback(LayoutCallback<ConstraintType> value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a setter without a getter is strange...

}) : super(key: key, builder: builder);

@override
LayoutWidgetBuilder get builder;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I am missing something, but how does this override work? It doesn't have a body and the class is not marked abstract?

Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Jul 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah I didn't realize that and it passed the tests. Turns out this is expected, according to the language spec:

section: 16.19:

Let m be an identifier, o an object, L a library, and C a class which is the
class of o or a superclass thereof.
...
The result of a getter lookup for m in o with respect to L starting in class
C is the result of a getter lookup for m in C with respect to L. The result of a
getter lookup for m in C with respect to L is: If C declares a concrete instance
getter named m that is accessible to L, then that getter declaration is the result
of the getter lookup, and we say that the getter was looked up in C. Otherwise,
if C has a superclass S, the result of the getter lookup is the result of a getter
lookup for m in S with respect to L. Otherwise, we say that the getter lookup
has failed.

section 10.4:

The purpose of an abstract method is to provide a declaration for purposes
such as type checking and reflection. In mixins, it is often useful to introduce
such declarations for methods that the mixin expects will be provided by the
superclass the mixin is applied to.
We wish to detect if one declares a concrete class with abstract members.
However, code like the following should work:

class Base {
  int get one => 1;
}
abstract class Mix {
  int get one;
  int get two => one + one;
}
class C extends Base with Mix { }

At run time, the concrete method one declared in Base will be executed, and
no problem should arise. Therefore no error should be raised if a corresponding
concrete member exists in the hierarchy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added implementation.

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

import 'debug.dart';
import 'framework.dart';

export 'sliver_layout_builder.dart';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This export should probably be in flutter/lib/widgets.dart instead.


@override
_RenderLayoutBuilder createRenderObject(BuildContext context) => _RenderLayoutBuilder();
/// Called at layout time to construct the widget tree. The builder must not
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the first paragraph of a doc comment should be a one-sentence summary.

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

expect(parentSliver.geometry.scrollExtent, childHeight);
expect(parentSliver.geometry.paintExtent, childHeight);

// When child is over-sized.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

half sentence

@LongCatIsLooong LongCatIsLooong merged commit 9c8badd into flutter:master Jul 26, 2019
@LongCatIsLooong LongCatIsLooong deleted the sliver-layoutbuilder branch July 26, 2019 17:39
johnsonmh pushed a commit to johnsonmh/flutter that referenced this pull request Jul 30, 2019
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add SliverLayoutBuilder

5 participants