grid_list_demo.dart 6.03 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// 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 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

enum GridDemoTileStyle {
  imageOnly,
  oneLine,
  twoLine
}

class Photo {
  const Photo({ this.assetName });

  final String assetName;

  String get title => 'Safari';
  String get caption => 'March 2015';

  bool get isValid => assetName != null;
}

final List<Photo> photos = new List<Photo>.generate(16, (int index) {
  return const Photo(assetName: 'packages/flutter_gallery_assets/kangaroo_valley_safari.png');
});

31
class GridDemoPhotoItem extends StatelessWidget {
32 33 34 35 36 37 38 39 40
  GridDemoPhotoItem({ Key key, this.photo, this.tileStyle }) : super(key: key) {
    assert(photo != null && photo.isValid);
    assert(tileStyle != null);
  }

  final Photo photo;
  final GridDemoTileStyle tileStyle;

  void showPhoto(BuildContext context) {
41
    Navigator.push(context, new MaterialPageRoute<Null>(
42 43
      builder: (BuildContext context) {
        return new Scaffold(
44 45
          appBar: new AppBar(
            title: new Text(photo.title)
46 47 48 49 50 51 52 53 54 55 56 57
          ),
          body: new Material(
            child: new AssetImage(
              name: photo.assetName,
              fit: ImageFit.cover
            )
          )
        );
      }
    ));
  }

58
  @override
59 60 61 62 63 64 65 66 67 68 69 70 71 72
  Widget build(BuildContext context) {
    final Widget image = new GestureDetector(
      onTap: () { showPhoto(context); },
      child: new AssetImage(
        name: photo.assetName,
        fit: ImageFit.cover
      )
    );

    switch(tileStyle) {
      case GridDemoTileStyle.imageOnly:
        return image;

      case GridDemoTileStyle.oneLine:
Hans Muller's avatar
Hans Muller committed
73 74 75
        return new GridTile(
          header: new GridTileBar(
            backgroundColor: Colors.black.withAlpha(0x08),
76
            leading: new Icon(icon: Icons.info, color: Colors.white70),
Hans Muller's avatar
Hans Muller committed
77 78 79
            title: new Text(photo.title)
          ),
          child: image
80 81 82
        );

      case GridDemoTileStyle.twoLine:
Hans Muller's avatar
Hans Muller committed
83 84 85 86
        return new GridTile(
          footer: new GridTileBar(
            backgroundColor: Colors.black.withAlpha(0x08),
            title: new Text(photo.title),
87 88
            subtitle: new Text(photo.caption),
            trailing: new Icon(icon: Icons.info, color: Colors.white70)
Hans Muller's avatar
Hans Muller committed
89 90
          ),
          child: image
91
        );
Hans Muller's avatar
Hans Muller committed
92
    }
93 94 95 96 97 98 99 100
  }
}

class GridListDemoGridDelegate extends FixedColumnCountGridDelegate {
  GridListDemoGridDelegate({
    this.columnCount,
    double columnSpacing: 0.0,
    double rowSpacing: 0.0,
101
    EdgeInsets padding: EdgeInsets.zero,
102 103 104 105 106 107
    this.tileHeightFactor: 2.75
  }) : super(columnSpacing: columnSpacing, rowSpacing: rowSpacing, padding: padding) {
    assert(columnCount != null && columnCount >= 0);
    assert(tileHeightFactor != null && tileHeightFactor > 0.0);
  }

108
  @override
109
  final int columnCount;
110

111 112
  final double tileHeightFactor;

113
  @override
114 115 116 117 118 119 120 121 122 123 124 125 126 127
  GridSpecification getGridSpecification(BoxConstraints constraints, int childCount) {
    assert(constraints.maxWidth < double.INFINITY);
    assert(constraints.maxHeight < double.INFINITY);
    return new GridSpecification.fromRegularTiles(
      tileWidth: math.max(0.0, constraints.maxWidth - padding.horizontal + columnSpacing) / columnCount,
      tileHeight: constraints.maxHeight / tileHeightFactor,
      columnCount: columnCount,
      rowCount: (childCount / columnCount).ceil(),
      columnSpacing: columnSpacing,
      rowSpacing: rowSpacing,
      padding: padding
    );
  }

128
  @override
129 130 131 132 133 134 135
  bool shouldRelayout(GridListDemoGridDelegate oldDelegate) {
    return columnCount != oldDelegate.columnCount
        || tileHeightFactor != oldDelegate.tileHeightFactor
        || super.shouldRelayout(oldDelegate);
  }
}

136
class GridListDemo extends StatefulWidget {
Hans Muller's avatar
Hans Muller committed
137 138
  GridListDemo({ Key key }) : super(key: key);

139
  @override
140 141 142 143 144 145 146
  GridListDemoState createState() => new GridListDemoState();
}

class GridListDemoState extends State<GridListDemo> {
  GridDemoTileStyle tileStyle = GridDemoTileStyle.twoLine;

  void showTileStyleMenu(BuildContext context) {
147
    final List<PopupMenuItem<GridDemoTileStyle>> items = <PopupMenuItem<GridDemoTileStyle>>[
Hans Muller's avatar
Hans Muller committed
148
      new PopupMenuItem<GridDemoTileStyle>(
149 150 151
        value: GridDemoTileStyle.imageOnly,
        child: new Text('Image only')
      ),
Hans Muller's avatar
Hans Muller committed
152
      new PopupMenuItem<GridDemoTileStyle>(
153 154 155
        value: GridDemoTileStyle.oneLine,
        child: new Text('One line')
      ),
Hans Muller's avatar
Hans Muller committed
156
      new PopupMenuItem<GridDemoTileStyle>(
157 158 159 160 161
        value: GridDemoTileStyle.twoLine,
        child: new Text('Two line')
      )
    ];

162
    final EdgeInsets padding = MediaQuery.of(context).padding;
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    final ModalPosition position = new ModalPosition(
      right: padding.right + 16.0,
      top: padding.top + 16.0
    );

    showMenu(context: context, position: position, items: items).then((GridDemoTileStyle value) {
      setState(() {
        tileStyle = value;
      });
    });
  }

  // When the ScrollableGrid first appears we want the last row to only be
  // partially visible, to help the user recognize that the grid is scrollable.
  // The GridListDemoGridDelegate's tileHeightFactor is used for this.
178
  @override
179 180 181
  Widget build(BuildContext context) {
    final Orientation orientation = MediaQuery.of(context).orientation;
    return new Scaffold(
182 183 184
      appBar: new AppBar(
        title: new Text('Grid List'),
        actions: <Widget>[
185
          new IconButton(
186
            icon: Icons.more_vert,
187 188 189 190 191 192 193 194 195 196
            onPressed: () { showTileStyleMenu(context); },
            tooltip: 'Show menu'
          )
        ]
      ),
      body: new ScrollableGrid(
        delegate: new GridListDemoGridDelegate(
          columnCount: (orientation == Orientation.portrait) ? 2 : 3,
          rowSpacing: 4.0,
          columnSpacing: 4.0,
197
          padding: const EdgeInsets.all(4.0),
198 199 200 201 202 203 204 205 206 207
          tileHeightFactor: (orientation == Orientation.portrait) ? 2.75 : 1.75
        ),
        children: photos.map((Photo photo) {
          return new GridDemoPhotoItem(photo: photo, tileStyle: tileStyle);
        })
        .toList()
      )
    );
  }
}