blob: d0487a58f91dca5edea05b1ad19636db1a541fb5 [file] [log] [blame]
// Copyright 2016 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/rendering.dart';
import 'package:meta/meta.dart';
import 'framework.dart';
import 'basic.dart';
import 'scroll_physics.dart';
import 'scroll_position.dart';
import 'scrollable.dart';
import 'sliver.dart';
import 'viewport.dart';
abstract class ScrollView extends StatelessWidget {
ScrollView({
Key key,
this.scrollDirection: Axis.vertical,
this.reverse: false,
this.physics,
this.shrinkWrap: false,
}) : super(key: key) {
assert(reverse != null);
assert(shrinkWrap != null);
}
final Axis scrollDirection;
final bool reverse;
final ScrollPhysics physics;
final bool shrinkWrap;
@protected
AxisDirection getDirection(BuildContext context) {
// TODO(abarth): Consider reading direction.
switch (scrollDirection) {
case Axis.horizontal:
return reverse ? AxisDirection.left : AxisDirection.right;
case Axis.vertical:
return reverse ? AxisDirection.up : AxisDirection.down;
}
return null;
}
@protected
List<Widget> buildSlivers(BuildContext context);
@override
Widget build(BuildContext context) {
List<Widget> slivers = buildSlivers(context);
AxisDirection axisDirection = getDirection(context);
return new Scrollable2(
axisDirection: axisDirection,
physics: physics,
viewportBuilder: (BuildContext context, ViewportOffset offset) {
if (shrinkWrap) {
return new ShrinkWrappingViewport(
axisDirection: axisDirection,
offset: offset,
slivers: slivers,
);
} else {
return new Viewport2(
axisDirection: axisDirection,
offset: offset,
slivers: slivers,
);
}
}
);
}
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('$scrollDirection');
if (shrinkWrap)
description.add('shrink-wrapping');
}
}
abstract class BoxScrollView extends ScrollView {
BoxScrollView({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
this.padding,
}) : super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
);
final EdgeInsets padding;
@override
List<Widget> buildSlivers(BuildContext context) {
Widget sliver = buildChildLayout(context);
if (padding != null)
sliver = new SliverPadding(padding: padding, child: sliver);
return <Widget>[ sliver ];
}
@protected
Widget buildChildLayout(BuildContext context);
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (padding != null)
description.add('padding: $padding');
}
}
/// A scrollable list of boxes.
// TODO(ianh): More documentation here.
///
/// See also:
///
/// * [SingleChildScrollView], when you need to make a single child scrollable.
/// * [GridView], for a scrollable grid of boxes.
/// * [PageView], for a scrollable that works page by page.
class ListView extends BoxScrollView {
ListView({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsets padding,
this.itemExtent,
List<Widget> children: const <Widget>[],
}) : childrenDelegate = new SliverChildListDelegate(children), super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
);
ListView.custom({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsets padding,
this.itemExtent,
@required this.childrenDelegate,
}) : super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
) {
assert(childrenDelegate != null);
}
final double itemExtent;
final SliverChildListDelegate childrenDelegate;
@override
Widget buildChildLayout(BuildContext context) {
if (itemExtent != null) {
return new SliverList(
delegate: childrenDelegate,
itemExtent: itemExtent,
);
}
return new SliverBlock(delegate: childrenDelegate);
}
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (itemExtent != null)
description.add('itemExtent: $itemExtent');
}
}
/// A scrollable grid of boxes.
// TODO(ianh): More documentation here.
///
/// See also:
///
/// * [SingleChildScrollView], when you need to make a single child scrollable.
/// * [ListView], for a scrollable list of boxes.
/// * [PageView], for a scrollable that works page by page.
class GridView extends BoxScrollView {
GridView({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsets padding,
@required this.gridDelegate,
List<Widget> children: const <Widget>[],
}) : childrenDelegate = new SliverChildListDelegate(children), super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
) {
assert(gridDelegate != null);
}
GridView.custom({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsets padding,
@required this.gridDelegate,
@required this.childrenDelegate,
}) : super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
) {
assert(gridDelegate != null);
assert(childrenDelegate != null);
}
GridView.count({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsets padding,
@required int crossAxisCount,
double mainAxisSpacing: 0.0,
double crossAxisSpacing: 0.0,
double childAspectRatio: 1.0,
List<Widget> children: const <Widget>[],
}) : gridDelegate = new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio,
),
childrenDelegate = new SliverChildListDelegate(children), super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
);
GridView.extent({
Key key,
Axis scrollDirection: Axis.vertical,
bool reverse: false,
ScrollPhysics physics,
bool shrinkWrap: false,
EdgeInsets padding,
@required double maxCrossAxisExtent,
double mainAxisSpacing: 0.0,
double crossAxisSpacing: 0.0,
double childAspectRatio: 1.0,
List<Widget> children: const <Widget>[],
}) : gridDelegate = new SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio,
),
childrenDelegate = new SliverChildListDelegate(children), super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
);
final SliverGridDelegate gridDelegate;
final SliverChildListDelegate childrenDelegate;
@override
Widget buildChildLayout(BuildContext context) {
return new SliverGrid(
delegate: childrenDelegate,
gridDelegate: gridDelegate,
);
}
}
/// A scrollable list that works page by page.
// TODO(ianh): More documentation here.
///
/// See also:
///
/// * [SingleChildScrollView], when you need to make a single child scrollable.
/// * [ListView], for a scrollable list of boxes.
/// * [GridView], for a scrollable grid of boxes.
class PageView extends BoxScrollView {
PageView({
Key key,
Axis scrollDirection: Axis.horizontal,
bool reverse: false,
ScrollPhysics physics: const PageScrollPhysics(),
bool shrinkWrap: false,
EdgeInsets padding,
List<Widget> children: const <Widget>[],
}) : childrenDelegate = new SliverChildListDelegate(children), super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
);
PageView.custom({
Key key,
Axis scrollDirection: Axis.horizontal,
bool reverse: false,
ScrollPhysics physics: const PageScrollPhysics(),
bool shrinkWrap: false,
EdgeInsets padding,
@required this.childrenDelegate,
}) : super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
) {
assert(childrenDelegate != null);
}
final SliverChildListDelegate childrenDelegate;
@override
Widget buildChildLayout(BuildContext context) {
return new SliverFill(delegate: childrenDelegate);
}
}