grid_list_demo.dart 5.96 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 31 32 33 34 35 36 37 38 39 40
// 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');
});

class GridDemoPhotoItem extends StatelessComponent {
  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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
      builder: (BuildContext context) {
        return new Scaffold(
          toolBar: new ToolBar(
            center: new Text(photo.title)
          ),
          body: new Material(
            child: new AssetImage(
              name: photo.assetName,
              fit: ImageFit.cover
            )
          )
        );
      }
    ));
  }

  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
72 73 74
        return new GridTile(
          header: new GridTileBar(
            backgroundColor: Colors.black.withAlpha(0x08),
75
            left: new Icon(icon: Icons.info, color: Colors.white70),
Hans Muller's avatar
Hans Muller committed
76 77 78
            title: new Text(photo.title)
          ),
          child: image
79 80 81
        );

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

class GridListDemoGridDelegate extends FixedColumnCountGridDelegate {
  GridListDemoGridDelegate({
    this.columnCount,
    double columnSpacing: 0.0,
    double rowSpacing: 0.0,
100
    EdgeInsets padding: EdgeInsets.zero,
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    this.tileHeightFactor: 2.75
  }) : super(columnSpacing: columnSpacing, rowSpacing: rowSpacing, padding: padding) {
    assert(columnCount != null && columnCount >= 0);
    assert(tileHeightFactor != null && tileHeightFactor > 0.0);
  }

  final int columnCount;
  final double tileHeightFactor;

  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
    );
  }

  bool shouldRelayout(GridListDemoGridDelegate oldDelegate) {
    return columnCount != oldDelegate.columnCount
        || tileHeightFactor != oldDelegate.tileHeightFactor
        || super.shouldRelayout(oldDelegate);
  }
}

class GridListDemo extends StatefulComponent {
Hans Muller's avatar
Hans Muller committed
132 133
  GridListDemo({ Key key }) : super(key: key);

134 135 136 137 138 139 140
  GridListDemoState createState() => new GridListDemoState();
}

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

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

156
    final EdgeInsets padding = MediaQuery.of(context).padding;
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    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.
  Widget build(BuildContext context) {
    final Orientation orientation = MediaQuery.of(context).orientation;
    return new Scaffold(
      toolBar: new ToolBar(
        center: new Text('Grid List'),
        right: <Widget>[
          new IconButton(
179
            icon: Icons.more_vert,
180 181 182 183 184 185 186 187 188 189
            onPressed: () { showTileStyleMenu(context); },
            tooltip: 'Show menu'
          )
        ]
      ),
      body: new ScrollableGrid(
        delegate: new GridListDemoGridDelegate(
          columnCount: (orientation == Orientation.portrait) ? 2 : 3,
          rowSpacing: 4.0,
          columnSpacing: 4.0,
190
          padding: const EdgeInsets.all(4.0),
191 192 193 194 195 196 197 198 199 200
          tileHeightFactor: (orientation == Orientation.portrait) ? 2.75 : 1.75
        ),
        children: photos.map((Photo photo) {
          return new GridDemoPhotoItem(photo: photo, tileStyle: tileStyle);
        })
        .toList()
      )
    );
  }
}