xingwei.zhu
4 年前
当前提交
d114e119
共有 12 个文件被更改,包括 1616 次插入 和 28 次删除
-
45Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/demos.cs
-
22com.unity.uiwidgets/Runtime/material/button_bar_theme.cs
-
2com.unity.uiwidgets/Runtime/material/grid_tile_bar.cs
-
2com.unity.uiwidgets/Runtime/material/navigation_rail_theme.cs
-
15com.unity.uiwidgets/Runtime/material/popup_menu.cs
-
2com.unity.uiwidgets/Runtime/material/popup_menu_theme.cs
-
82com.unity.uiwidgets/Runtime/material/theme_data.cs
-
456Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/grid_list_demo.cs
-
159Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/icons_demo.cs
-
374Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/leave_behind_demo.cs
-
251Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/list_demo.cs
-
234Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/menu_demo.cs
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using uiwidgets; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using Image = Unity.UIWidgets.widgets.Image; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal enum GridDemoTileStyle |
|||
{ |
|||
imageOnly, |
|||
oneLine, |
|||
twoLine |
|||
} |
|||
|
|||
internal delegate void BannerTapCallback(Photo photo); |
|||
|
|||
internal static class GridListDemoUtils |
|||
{ |
|||
public const float _kMinFlingVelocity = 800.0f; |
|||
public static readonly string _kGalleryAssetsPackage = "gallery/"; |
|||
} |
|||
|
|||
internal class Photo |
|||
{ |
|||
public Photo( |
|||
string assetName = null, |
|||
string assetPackage = null, |
|||
string title = null, |
|||
string caption = null, |
|||
bool isFavorite = false |
|||
) |
|||
{ |
|||
this.assetName = assetName; |
|||
this.assetPackage = assetPackage; |
|||
this.title = title; |
|||
this.caption = caption; |
|||
this.isFavorite = isFavorite; |
|||
} |
|||
|
|||
public readonly string assetName; |
|||
public readonly string assetPackage; |
|||
public readonly string title; |
|||
public readonly string caption; |
|||
|
|||
internal bool isFavorite; |
|||
internal string tag => assetName; // Assuming that all asset names are unique.
|
|||
|
|||
internal bool isValid => assetName != null && title != null && caption != null && isFavorite != null; |
|||
} |
|||
|
|||
internal class GridPhotoViewer : StatefulWidget |
|||
{ |
|||
public GridPhotoViewer( |
|||
Key key = null, |
|||
Photo photo = null) : base(key: key) |
|||
{ |
|||
this.photo = photo; |
|||
} |
|||
|
|||
public readonly Photo photo; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _GridPhotoViewerState(); |
|||
} |
|||
} |
|||
|
|||
internal class _GridTitleText : StatelessWidget |
|||
{ |
|||
public _GridTitleText(string text) |
|||
{ |
|||
this.text = text; |
|||
} |
|||
|
|||
public readonly string text; |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new FittedBox( |
|||
fit: BoxFit.scaleDown, |
|||
alignment: Alignment.centerLeft, |
|||
child: new Text(text) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _GridPhotoViewerState : SingleTickerProviderStateMixin<GridPhotoViewer> |
|||
{ |
|||
private AnimationController _controller; |
|||
private Animation<Offset> _flingAnimation; |
|||
private Offset _offset = Offset.zero; |
|||
private float _scale = 1.0f; |
|||
private Offset _normalizedOffset; |
|||
private float _previousScale; |
|||
|
|||
|
|||
public override void initState() |
|||
{ |
|||
base.initState(); |
|||
_controller = new AnimationController(vsync: this); |
|||
_controller.addListener(_handleFlingAnimation); |
|||
} |
|||
|
|||
|
|||
public override void dispose() |
|||
{ |
|||
_controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
private Offset _clampOffset(Offset offset) |
|||
{ |
|||
Size size = context.size; |
|||
Offset minOffset = new Offset(size.width, size.height) * (1.0f - _scale); |
|||
return new Offset( |
|||
offset.dx.clamp(minOffset.dx, 0.0f), |
|||
offset.dy.clamp(minOffset.dy, 0.0f) |
|||
); |
|||
} |
|||
|
|||
private void _handleFlingAnimation() |
|||
{ |
|||
setState(() => { _offset = _flingAnimation.value; }); |
|||
} |
|||
|
|||
private void _handleOnScaleStart(ScaleStartDetails details) |
|||
{ |
|||
setState(() => |
|||
{ |
|||
_previousScale = _scale; |
|||
_normalizedOffset = (details.focalPoint - _offset) / _scale; |
|||
_controller.stop(); |
|||
}); |
|||
} |
|||
|
|||
private void _handleOnScaleUpdate(ScaleUpdateDetails details) |
|||
{ |
|||
setState(() => |
|||
{ |
|||
_scale = (_previousScale * details.scale).clamp(1.0f, 4.0f); |
|||
_offset = _clampOffset(details.focalPoint - _normalizedOffset * _scale); |
|||
}); |
|||
} |
|||
|
|||
private void _handleOnScaleEnd(ScaleEndDetails details) |
|||
{ |
|||
float magnitude = details.velocity.pixelsPerSecond.distance; |
|||
if (magnitude < GridListDemoUtils._kMinFlingVelocity) |
|||
return; |
|||
Offset direction = details.velocity.pixelsPerSecond / magnitude; |
|||
float distance = (Offset.zero & context.size).shortestSide; |
|||
_flingAnimation = _controller.drive(new OffsetTween( |
|||
begin: _offset, |
|||
end: _clampOffset(_offset + direction * distance) |
|||
)); |
|||
_controller.setValue(0.0f); |
|||
_controller.fling(velocity: magnitude / 1000.0f); |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
var transform = Matrix4.identity(); |
|||
transform.translate(_offset.dx, _offset.dy); |
|||
transform.scale(_scale); |
|||
return new GestureDetector( |
|||
onScaleStart: _handleOnScaleStart, |
|||
onScaleUpdate: _handleOnScaleUpdate, |
|||
onScaleEnd: _handleOnScaleEnd, |
|||
child: new ClipRect( |
|||
child: new Transform( |
|||
transform: transform, |
|||
child: Image.file( |
|||
widget.photo.assetPackage + widget.photo.assetName, |
|||
fit: BoxFit.cover |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class GridDemoPhotoItem : StatelessWidget |
|||
{ |
|||
public GridDemoPhotoItem( |
|||
Key key = null, |
|||
Photo photo = null, |
|||
GridDemoTileStyle? tileStyle = null, |
|||
BannerTapCallback onBannerTap = null |
|||
) : base(key: key) |
|||
{ |
|||
D.assert(photo != null && photo.isValid); |
|||
D.assert(tileStyle != null); |
|||
D.assert(onBannerTap != null); |
|||
|
|||
this.photo = photo; |
|||
this.tileStyle = tileStyle.Value; |
|||
this.onBannerTap = onBannerTap; |
|||
} |
|||
|
|||
public readonly Photo photo; |
|||
public readonly GridDemoTileStyle tileStyle; |
|||
public readonly BannerTapCallback onBannerTap; // User taps on the photo's header or footer.
|
|||
|
|||
private void showPhoto(BuildContext context) |
|||
{ |
|||
Navigator.push<object>(context, new MaterialPageRoute( |
|||
builder: (BuildContext subContext) => |
|||
{ |
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text(photo.title) |
|||
), |
|||
body: SizedBox.expand( |
|||
child: new Hero( |
|||
tag: photo.tag, |
|||
child: new GridPhotoViewer(photo: photo) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
)); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
Widget image = new GestureDetector( |
|||
onTap: () => { showPhoto(context); }, |
|||
child: new Hero( |
|||
key: Key.key(photo.assetName), |
|||
tag: photo.tag, |
|||
child: Image.file( |
|||
photo.assetPackage + photo.assetName, |
|||
fit: BoxFit.cover |
|||
) |
|||
) |
|||
); |
|||
|
|||
IconData icon = photo.isFavorite ? Icons.star : Icons.star_border; |
|||
|
|||
switch (tileStyle) |
|||
{ |
|||
case GridDemoTileStyle.imageOnly: |
|||
return image; |
|||
|
|||
case GridDemoTileStyle.oneLine: |
|||
return new GridTile( |
|||
header: new GestureDetector( |
|||
onTap: () => { onBannerTap(photo); }, |
|||
child: new GridTileBar( |
|||
title: new _GridTitleText(photo.title), |
|||
backgroundColor: Colors.black45, |
|||
leading: new Icon( |
|||
icon, |
|||
color: Colors.white |
|||
) |
|||
) |
|||
), |
|||
child: image |
|||
); |
|||
|
|||
case GridDemoTileStyle.twoLine: |
|||
return new GridTile( |
|||
footer: new GestureDetector( |
|||
onTap: () => { onBannerTap(photo); }, |
|||
child: new GridTileBar( |
|||
backgroundColor: Colors.black45, |
|||
title: new _GridTitleText(photo.title), |
|||
subtitle: new _GridTitleText(photo.caption), |
|||
trailing: new Icon( |
|||
icon, |
|||
color: Colors.white |
|||
) |
|||
) |
|||
), |
|||
child: image |
|||
); |
|||
} |
|||
|
|||
D.assert(tileStyle != null); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
internal class GridListDemo : StatefulWidget |
|||
{ |
|||
public GridListDemo(Key key = null) : base(key: key) |
|||
{ |
|||
} |
|||
|
|||
public static readonly string routeName = "/material/grid-list"; |
|||
|
|||
|
|||
public override State createState() |
|||
{ |
|||
return new GridListDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class GridListDemoState : State<GridListDemo> |
|||
{ |
|||
private GridDemoTileStyle _tileStyle = GridDemoTileStyle.twoLine; |
|||
|
|||
private List<Photo> photos = new List<Photo> |
|||
{ |
|||
new Photo( |
|||
assetName: "places/india_chennai_flower_market.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Chennai", |
|||
caption: "Flower Market" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_tanjore_bronze_works.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Tanjore", |
|||
caption: "Bronze Works" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_tanjore_market_merchant.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Tanjore", |
|||
caption: "Market" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_tanjore_thanjavur_temple.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Tanjore", |
|||
caption: "Thanjavur Temple" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_tanjore_thanjavur_temple_carvings.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Tanjore", |
|||
caption: "Thanjavur Temple" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_pondicherry_salt_farm.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Pondicherry", |
|||
caption: "Salt Farm" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_chennai_highway.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Chennai", |
|||
caption: "Scooters" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_chettinad_silk_maker.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Chettinad", |
|||
caption: "Silk Maker" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_chettinad_produce.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Chettinad", |
|||
caption: "Lunch Prep" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_tanjore_market_technology.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Tanjore", |
|||
caption: "Market" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_pondicherry_beach.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Pondicherry", |
|||
caption: "Beach" |
|||
), |
|||
new Photo( |
|||
assetName: "places/india_pondicherry_fisherman.png", |
|||
assetPackage: GridListDemoUtils._kGalleryAssetsPackage, |
|||
title: "Pondicherry", |
|||
caption: "Fisherman" |
|||
) |
|||
}; |
|||
|
|||
private void changeTileStyle(GridDemoTileStyle value) |
|||
{ |
|||
setState(() => { _tileStyle = value; }); |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
Orientation? orientation = MediaQuery.of(context).orientation; |
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Grid list"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(GridListDemo.routeName), |
|||
new PopupMenuButton<GridDemoTileStyle>( |
|||
onSelected: changeTileStyle, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<GridDemoTileStyle>> |
|||
{ |
|||
new PopupMenuItem<GridDemoTileStyle>( |
|||
value: GridDemoTileStyle.imageOnly, |
|||
child: new Text("Image only") |
|||
), |
|||
new PopupMenuItem<GridDemoTileStyle>( |
|||
value: GridDemoTileStyle.oneLine, |
|||
child: new Text("One line") |
|||
), |
|||
new PopupMenuItem<GridDemoTileStyle>( |
|||
value: GridDemoTileStyle.twoLine, |
|||
child: new Text("Two line") |
|||
) |
|||
} |
|||
) |
|||
} |
|||
), |
|||
body: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
new Expanded( |
|||
child: new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: GridView.count( |
|||
crossAxisCount: (orientation == Orientation.portrait) ? 2 : 3, |
|||
mainAxisSpacing: 4.0f, |
|||
crossAxisSpacing: 4.0f, |
|||
padding: EdgeInsets.all(4.0f), |
|||
childAspectRatio: (orientation == Orientation.portrait) ? 1.0f : 1.3f, |
|||
children: photos.Select<Photo, Widget>((Photo photo) => |
|||
{ |
|||
return new GridDemoPhotoItem( |
|||
photo: photo, |
|||
tileStyle: _tileStyle, |
|||
onBannerTap: (Photo curPhoto) => |
|||
{ |
|||
setState(() => { curPhoto.isFavorite = !curPhoto.isFavorite; }); |
|||
} |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using uiwidgets; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal class IconsDemo : StatefulWidget |
|||
{ |
|||
public static readonly string routeName = "/material/icons"; |
|||
|
|||
|
|||
public override State createState() |
|||
{ |
|||
return new IconsDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class IconsDemoState : State<IconsDemo> |
|||
{ |
|||
public static readonly List<MaterialColor> iconColors = new List<MaterialColor> |
|||
{ |
|||
Colors.red, |
|||
Colors.pink, |
|||
Colors.purple, |
|||
Colors.deepPurple, |
|||
Colors.indigo, |
|||
Colors.blue, |
|||
Colors.lightBlue, |
|||
Colors.cyan, |
|||
Colors.teal, |
|||
Colors.green, |
|||
Colors.lightGreen, |
|||
Colors.lime, |
|||
Colors.yellow, |
|||
Colors.amber, |
|||
Colors.orange, |
|||
Colors.deepOrange, |
|||
Colors.brown, |
|||
Colors.grey, |
|||
Colors.blueGrey |
|||
}; |
|||
|
|||
private int iconColorIndex = 8; // teal
|
|||
|
|||
private Color iconColor => iconColors[iconColorIndex]; |
|||
|
|||
private void handleIconButtonPress() |
|||
{ |
|||
setState(() => { iconColorIndex = (iconColorIndex + 1) % iconColors.Count; }); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Icons"), |
|||
actions: new List<Widget> {new MaterialDemoDocumentationButton(IconsDemo.routeName)} |
|||
), |
|||
body: new IconTheme( |
|||
data: new IconThemeData(color: iconColor), |
|||
child: new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Scrollbar( |
|||
child: new ListView( |
|||
padding: EdgeInsets.all(24.0f), |
|||
children: new List<Widget> |
|||
{ |
|||
new _IconsDemoCard(handleIconButtonPress, Icons.face), // direction-agnostic icon
|
|||
new SizedBox(height: 24.0f), |
|||
new _IconsDemoCard(handleIconButtonPress, |
|||
Icons.battery_unknown) // direction-aware icon
|
|||
} |
|||
) |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _IconsDemoCard : StatelessWidget |
|||
{ |
|||
public _IconsDemoCard(VoidCallback handleIconButtonPress, IconData icon) |
|||
{ |
|||
this.handleIconButtonPress = handleIconButtonPress; |
|||
this.icon = icon; |
|||
} |
|||
|
|||
public readonly VoidCallback handleIconButtonPress; |
|||
public readonly IconData icon; |
|||
|
|||
private Widget _buildIconButton(float iconSize, IconData icon, bool enabled) |
|||
{ |
|||
var prefix = enabled ? "Enabled" : "Disabled"; |
|||
return new IconButton( |
|||
icon: new Icon(icon), |
|||
iconSize: iconSize, |
|||
tooltip: $"{prefix} icon button", |
|||
onPressed: enabled ? handleIconButtonPress : null |
|||
); |
|||
} |
|||
|
|||
private Widget _centeredText(string label) |
|||
{ |
|||
return new Padding( |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Text(label, textAlign: TextAlign.center) |
|||
); |
|||
} |
|||
|
|||
private TableRow _buildIconRow(float size) |
|||
{ |
|||
return new TableRow( |
|||
children: new List<Widget> |
|||
{ |
|||
_centeredText(size.floor().ToString()), |
|||
_buildIconButton(size, icon, true), |
|||
_buildIconButton(size, icon, false) |
|||
} |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
TextStyle textStyle = theme.textTheme.subtitle1.copyWith(color: theme.textTheme.caption.color); |
|||
return new Card( |
|||
child: new DefaultTextStyle( |
|||
style: textStyle, |
|||
child: new Table( |
|||
defaultVerticalAlignment: TableCellVerticalAlignment.middle, |
|||
children: new List<TableRow> |
|||
{ |
|||
new TableRow( |
|||
children: new List<Widget> |
|||
{ |
|||
_centeredText("Size"), |
|||
_centeredText("Enabled"), |
|||
_centeredText("Disabled") |
|||
} |
|||
), |
|||
_buildIconRow(18.0f), |
|||
_buildIconRow(24.0f), |
|||
_buildIconRow(36.0f), |
|||
_buildIconRow(48.0f) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using uiwidgets; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.async2; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal enum LeaveBehindDemoAction |
|||
{ |
|||
reset, |
|||
horizontalSwipe, |
|||
leftSwipe, |
|||
rightSwipe, |
|||
confirmDismiss, |
|||
} |
|||
|
|||
internal class LeaveBehindItem : IComparable<LeaveBehindItem> |
|||
{ |
|||
public LeaveBehindItem( |
|||
int index = 0, |
|||
string name = null, |
|||
string subject = null, |
|||
string body = null) |
|||
{ |
|||
this.index = index; |
|||
this.name = name; |
|||
this.subject = subject; |
|||
this.body = body; |
|||
} |
|||
|
|||
public static LeaveBehindItem from(LeaveBehindItem item) |
|||
{ |
|||
return new LeaveBehindItem( |
|||
index: item.index, |
|||
name: item.name, |
|||
subject: item.subject, |
|||
body: item.body |
|||
); |
|||
} |
|||
|
|||
public readonly int index; |
|||
public readonly string name; |
|||
public readonly string subject; |
|||
public readonly string body; |
|||
|
|||
public int CompareTo(LeaveBehindItem other) |
|||
{ |
|||
return index.CompareTo(other.index); |
|||
} |
|||
} |
|||
|
|||
internal class LeaveBehindDemo : StatefulWidget |
|||
{ |
|||
public LeaveBehindDemo(Key key = null) : base(key: key) |
|||
{ |
|||
} |
|||
|
|||
public static readonly string routeName = "/material/leave-behind"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new LeaveBehindDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class LeaveBehindDemoState : State<LeaveBehindDemo> |
|||
{ |
|||
private static readonly GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key(); |
|||
private DismissDirection _dismissDirection = DismissDirection.horizontal; |
|||
private bool _confirmDismiss = true; |
|||
private List<LeaveBehindItem> leaveBehindItems; |
|||
|
|||
private void initListItems() |
|||
{ |
|||
leaveBehindItems = new List<LeaveBehindItem>(); |
|||
|
|||
for (int i = 0; i < 16; i++) |
|||
{ |
|||
var index = i; |
|||
leaveBehindItems.Add(new LeaveBehindItem( |
|||
index: index, |
|||
name: $"Item {index} Sender", |
|||
subject: $"Subject: {index}", |
|||
body: $"[{index}] first line of the message's body..." |
|||
)); |
|||
} |
|||
} |
|||
|
|||
|
|||
public override void initState() |
|||
{ |
|||
base.initState(); |
|||
initListItems(); |
|||
} |
|||
|
|||
private void handleDemoAction(LeaveBehindDemoAction action) |
|||
{ |
|||
setState(() => |
|||
{ |
|||
switch (action) |
|||
{ |
|||
case LeaveBehindDemoAction.reset: |
|||
initListItems(); |
|||
break; |
|||
case LeaveBehindDemoAction.horizontalSwipe: |
|||
_dismissDirection = DismissDirection.horizontal; |
|||
break; |
|||
case LeaveBehindDemoAction.leftSwipe: |
|||
_dismissDirection = DismissDirection.endToStart; |
|||
break; |
|||
case LeaveBehindDemoAction.rightSwipe: |
|||
_dismissDirection = DismissDirection.startToEnd; |
|||
break; |
|||
case LeaveBehindDemoAction.confirmDismiss: |
|||
_confirmDismiss = !_confirmDismiss; |
|||
break; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private int lowerBound(List<LeaveBehindItem> items, LeaveBehindItem item) |
|||
{ |
|||
items.Sort(); |
|||
for (int i = 0; i < items.Count; i++) |
|||
if (item.CompareTo(items[i]) >= 0) |
|||
return i; |
|||
return items.Count - 1; |
|||
} |
|||
|
|||
private void handleUndo(LeaveBehindItem item) |
|||
{ |
|||
int insertionIndex = lowerBound(leaveBehindItems, item); |
|||
setState(() => { leaveBehindItems.Insert(insertionIndex, item); }); |
|||
} |
|||
|
|||
private void _handleArchive(LeaveBehindItem item) |
|||
{ |
|||
setState(() => { leaveBehindItems.Remove(item); }); |
|||
_scaffoldKey.currentState.showSnackBar(new SnackBar( |
|||
content: new Text($"You archived item {item.index}"), |
|||
action: new SnackBarAction( |
|||
label: "UNDO", |
|||
onPressed: () => { handleUndo(item); } |
|||
) |
|||
)); |
|||
} |
|||
|
|||
private void _handleDelete(LeaveBehindItem item) |
|||
{ |
|||
setState(() => { leaveBehindItems.Remove(item); }); |
|||
_scaffoldKey.currentState.showSnackBar(new SnackBar( |
|||
content: new Text($"You deleted item {item.index}"), |
|||
action: new SnackBarAction( |
|||
label: "UNDO", |
|||
onPressed: () => { handleUndo(item); } |
|||
) |
|||
)); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
Widget body = null; |
|||
if (leaveBehindItems.isEmpty()) |
|||
body = new Center( |
|||
child: new RaisedButton( |
|||
onPressed: () => handleDemoAction(LeaveBehindDemoAction.reset), |
|||
child: new Text("Reset the list") |
|||
) |
|||
); |
|||
else |
|||
body = new Scrollbar( |
|||
child: new ListView( |
|||
children: leaveBehindItems.Select<LeaveBehindItem, Widget>((LeaveBehindItem item) => |
|||
{ |
|||
return new _LeaveBehindListItem( |
|||
confirmDismiss: _confirmDismiss, |
|||
item: item, |
|||
onArchive: _handleArchive, |
|||
onDelete: _handleDelete, |
|||
dismissDirection: _dismissDirection |
|||
); |
|||
}).ToList() |
|||
) |
|||
); |
|||
|
|||
return new Scaffold( |
|||
key: _scaffoldKey, |
|||
appBar: new AppBar( |
|||
title: new Text("Swipe to dismiss"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(LeaveBehindDemo.routeName), |
|||
new PopupMenuButton<LeaveBehindDemoAction>( |
|||
onSelected: handleDemoAction, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<LeaveBehindDemoAction>> |
|||
{ |
|||
new PopupMenuItem<LeaveBehindDemoAction>( |
|||
value: LeaveBehindDemoAction.reset, |
|||
child: new Text("Reset the list") |
|||
), |
|||
new PopupMenuDivider<LeaveBehindDemoAction>(), |
|||
new CheckedPopupMenuItem<LeaveBehindDemoAction>( |
|||
value: LeaveBehindDemoAction.horizontalSwipe, |
|||
isChecked: _dismissDirection == DismissDirection.horizontal, |
|||
child: new Text("Horizontal swipe") |
|||
), |
|||
new CheckedPopupMenuItem<LeaveBehindDemoAction>( |
|||
value: LeaveBehindDemoAction.leftSwipe, |
|||
isChecked: _dismissDirection == DismissDirection.endToStart, |
|||
child: new Text("Only swipe left") |
|||
), |
|||
new CheckedPopupMenuItem<LeaveBehindDemoAction>( |
|||
value: LeaveBehindDemoAction.rightSwipe, |
|||
isChecked: _dismissDirection == DismissDirection.startToEnd, |
|||
child: new Text("Only swipe right") |
|||
), |
|||
new CheckedPopupMenuItem<LeaveBehindDemoAction>( |
|||
value: LeaveBehindDemoAction.confirmDismiss, |
|||
isChecked: _confirmDismiss, |
|||
child: new Text("Confirm dismiss") |
|||
) |
|||
} |
|||
) |
|||
} |
|||
), |
|||
body: body |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal delegate void onArchiveFunc(LeaveBehindItem item); |
|||
|
|||
internal delegate void onDeleteFunc(LeaveBehindItem item); |
|||
|
|||
internal class _LeaveBehindListItem : StatelessWidget |
|||
{ |
|||
public _LeaveBehindListItem( |
|||
Key key = null, |
|||
LeaveBehindItem item = null, |
|||
onArchiveFunc onArchive = null, |
|||
onDeleteFunc onDelete = null, |
|||
DismissDirection? dismissDirection = null, |
|||
bool? confirmDismiss = null |
|||
) : base(key: key) |
|||
{ |
|||
this.item = item; |
|||
this.onArchive = onArchive; |
|||
this.onDelete = onDelete; |
|||
this.dismissDirection = dismissDirection; |
|||
this.confirmDismiss = confirmDismiss; |
|||
} |
|||
|
|||
public readonly LeaveBehindItem item; |
|||
public readonly DismissDirection? dismissDirection; |
|||
public readonly onArchiveFunc onArchive; |
|||
public readonly onDeleteFunc onDelete; |
|||
public readonly bool? confirmDismiss; |
|||
|
|||
private void _handleArchive() |
|||
{ |
|||
Debug.Log("handle archived >>>>"); |
|||
onArchive(item); |
|||
} |
|||
|
|||
private void _handleDelete() |
|||
{ |
|||
Debug.Log("handle deleted >>>>"); |
|||
onDelete(item); |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
|
|||
Future<bool> dismissDirectionFunc(DismissDirection? dismissDirection) |
|||
{ |
|||
switch (dismissDirection) |
|||
{ |
|||
case DismissDirection.endToStart: |
|||
return _showConfirmationDialog(context, "archive"); |
|||
case DismissDirection.startToEnd: |
|||
return _showConfirmationDialog(context, "delete"); |
|||
case DismissDirection.horizontal: |
|||
case DismissDirection.vertical: |
|||
case DismissDirection.up: |
|||
case DismissDirection.down: |
|||
D.assert(false); |
|||
break; |
|||
} |
|||
|
|||
return Future.value(false).to<bool>(); |
|||
} |
|||
|
|||
return new Dismissible( |
|||
key: new ObjectKey(item), |
|||
direction: dismissDirection.Value, |
|||
onDismissed: (DismissDirection? direction) => |
|||
{ |
|||
if (direction == DismissDirection.endToStart) |
|||
_handleArchive(); |
|||
else |
|||
_handleDelete(); |
|||
}, |
|||
confirmDismiss: !confirmDismiss.Value ? (ConfirmDismissCallback) null : dismissDirectionFunc, |
|||
background: new Container( |
|||
color: theme.primaryColor, |
|||
child: new Center( |
|||
child: new ListTile( |
|||
leading: new Icon(Icons.delete, color: Colors.white, size: 36.0f) |
|||
) |
|||
) |
|||
), |
|||
secondaryBackground: new Container( |
|||
color: theme.primaryColor, |
|||
child: new Center( |
|||
child: new ListTile( |
|||
trailing: new Icon(Icons.archive, color: Colors.white, size: 36.0f) |
|||
) |
|||
) |
|||
), |
|||
child: new Container( |
|||
decoration: new BoxDecoration( |
|||
color: theme.canvasColor, |
|||
border: new Border(bottom: new BorderSide(color: theme.dividerColor)) |
|||
), |
|||
child: new ListTile( |
|||
title: new Text(item.name), |
|||
subtitle: new Text($"{item.subject}\n{item.body}"), |
|||
isThreeLine: true |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
private Future<bool> _showConfirmationDialog(BuildContext context, string action) |
|||
{ |
|||
return material_.showDialog<bool>( |
|||
context: context, |
|||
barrierDismissible: true, |
|||
builder: (BuildContext subContext) => |
|||
{ |
|||
return new AlertDialog( |
|||
title: new Text($"Do you want to {action} this item?"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new FlatButton( |
|||
child: new Text("Yes"), |
|||
onPressed: () => |
|||
{ |
|||
Navigator.pop(context, true); // showDialog() returns true
|
|||
} |
|||
), |
|||
new FlatButton( |
|||
child: new Text("No"), |
|||
onPressed: () => |
|||
{ |
|||
Navigator.pop(context, false); // showDialog() returns false
|
|||
} |
|||
) |
|||
} |
|||
); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using uiwidgets; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal enum _MaterialListType |
|||
{ |
|||
/// A list tile that contains a single line of text.
|
|||
oneLine, |
|||
|
|||
/// A list tile that contains a [CircleAvatar] followed by a single line of text.
|
|||
oneLineWithAvatar, |
|||
|
|||
/// A list tile that contains two lines of text.
|
|||
twoLine, |
|||
|
|||
/// A list tile that contains three lines of text.
|
|||
threeLine, |
|||
} |
|||
|
|||
internal class ListDemo : StatefulWidget |
|||
{ |
|||
public ListDemo(Key key = null) : base(key: key) |
|||
{ |
|||
} |
|||
|
|||
public static readonly string routeName = "/material/list"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _ListDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _ListDemoState : State<ListDemo> |
|||
{ |
|||
private static readonly GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>.key(); |
|||
|
|||
private PersistentBottomSheetController<object> _bottomSheet; |
|||
private _MaterialListType _itemType = _MaterialListType.threeLine; |
|||
private bool _dense = false; |
|||
private bool _showAvatars = true; |
|||
private bool _showIcons = false; |
|||
private bool _showDividers = false; |
|||
private bool _reverseSort = false; |
|||
|
|||
private List<string> items = new List<string> |
|||
{ |
|||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", |
|||
}; |
|||
|
|||
private void changeItemType(_MaterialListType type) |
|||
{ |
|||
setState(() => { _itemType = type; }); |
|||
_bottomSheet?.setState(() => { }); |
|||
} |
|||
|
|||
private void _showConfigurationSheet() |
|||
{ |
|||
PersistentBottomSheetController<object> bottomSheet = scaffoldKey.currentState.showBottomSheet( |
|||
(BuildContext bottomSheetContext) => |
|||
{ |
|||
return new Container( |
|||
decoration: new BoxDecoration( |
|||
border: new Border(top: new BorderSide(color: Colors.black26)) |
|||
), |
|||
child: new ListView( |
|||
shrinkWrap: true, |
|||
primary: false, |
|||
children: new List<Widget> |
|||
{ |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("One-line"), |
|||
trailing: new Radio<_MaterialListType>( |
|||
value: _showAvatars |
|||
? _MaterialListType.oneLineWithAvatar |
|||
: _MaterialListType.oneLine, |
|||
groupValue: _itemType, |
|||
onChanged: changeItemType |
|||
) |
|||
), |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("Two-line"), |
|||
trailing: new Radio<_MaterialListType>( |
|||
value: _MaterialListType.twoLine, |
|||
groupValue: _itemType, |
|||
onChanged: changeItemType |
|||
) |
|||
), |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("Three-line"), |
|||
trailing: new Radio<_MaterialListType>( |
|||
value: _MaterialListType.threeLine, |
|||
groupValue: _itemType, |
|||
onChanged: changeItemType |
|||
) |
|||
), |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("Show avatar"), |
|||
trailing: new Checkbox( |
|||
value: _showAvatars, |
|||
onChanged: (bool? value) => |
|||
{ |
|||
setState(() => { _showAvatars = value.Value; }); |
|||
_bottomSheet?.setState(() => { }); |
|||
} |
|||
) |
|||
), |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("Show icon"), |
|||
trailing: new Checkbox( |
|||
value: _showIcons, |
|||
onChanged: (bool? value) => |
|||
{ |
|||
setState(() => { _showIcons = value.Value; }); |
|||
_bottomSheet?.setState(() => { }); |
|||
} |
|||
) |
|||
), |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("Show dividers"), |
|||
trailing: new Checkbox( |
|||
value: _showDividers, |
|||
onChanged: (bool? value) => |
|||
{ |
|||
setState(() => { _showDividers = value.Value; }); |
|||
_bottomSheet?.setState(() => { }); |
|||
} |
|||
) |
|||
), |
|||
new ListTile( |
|||
dense: true, |
|||
title: new Text("Dense layout"), |
|||
trailing: new Checkbox( |
|||
value: _dense, |
|||
onChanged: (bool? value) => |
|||
{ |
|||
setState(() => { _dense = value.Value; }); |
|||
_bottomSheet?.setState(() => { }); |
|||
} |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
}); |
|||
|
|||
setState(() => { _bottomSheet = bottomSheet; }); |
|||
|
|||
_bottomSheet.closed.whenComplete(() => |
|||
{ |
|||
if (mounted) |
|||
setState(() => { _bottomSheet = null; }); |
|||
}); |
|||
} |
|||
|
|||
private Widget buildListTile(BuildContext context, string item) |
|||
{ |
|||
Widget secondary = null; |
|||
if (_itemType == _MaterialListType.twoLine) |
|||
secondary = new Text("Additional item information."); |
|||
else if (_itemType == _MaterialListType.threeLine) |
|||
secondary = new Text( |
|||
"Even more additional list item information appears on line three." |
|||
); |
|||
return new ListTile( |
|||
isThreeLine: _itemType == _MaterialListType.threeLine, |
|||
dense: _dense, |
|||
leading: _showAvatars ? new CircleAvatar(child: new Text(item)) : null, |
|||
title: new Text($"This item represents {item}."), |
|||
subtitle: secondary, |
|||
trailing: _showIcons ? new Icon(Icons.info, color: Theme.of(context).disabledColor) : null |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
string layoutText = _dense ? " \u2013 Dense" : ""; |
|||
string itemTypeText = ""; |
|||
switch (_itemType) |
|||
{ |
|||
case _MaterialListType.oneLine: |
|||
case _MaterialListType.oneLineWithAvatar: |
|||
itemTypeText = "Single-line"; |
|||
break; |
|||
case _MaterialListType.twoLine: |
|||
itemTypeText = "Two-line"; |
|||
break; |
|||
case _MaterialListType.threeLine: |
|||
itemTypeText = "Three-line"; |
|||
break; |
|||
} |
|||
|
|||
IEnumerable<Widget> listTiles = items.Select<string, Widget>((string item) => buildListTile(context, item)); |
|||
if (_showDividers) |
|||
listTiles = ListTile.divideTiles(context: context, tiles: listTiles); |
|||
|
|||
return new Scaffold( |
|||
key: scaffoldKey, |
|||
appBar: new AppBar( |
|||
title: new Text($"Scrolling list\n{itemTypeText}{layoutText}"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(ListDemo.routeName), |
|||
new IconButton( |
|||
icon: new Icon(Icons.sort_by_alpha), |
|||
tooltip: "Sort", |
|||
onPressed: () => |
|||
{ |
|||
setState(() => |
|||
{ |
|||
_reverseSort = !_reverseSort; |
|||
items.Sort((string a, string b) => _reverseSort ? b.CompareTo(a) : a.CompareTo(b)); |
|||
}); |
|||
} |
|||
), |
|||
new IconButton( |
|||
icon: new Icon( |
|||
Theme.of(context).platform == RuntimePlatform.IPhonePlayer |
|||
? Icons.more_horiz |
|||
: Icons.more_vert |
|||
), |
|||
tooltip: "Show menu", |
|||
onPressed: _bottomSheet == null ? _showConfigurationSheet : (VoidCallback) null |
|||
) |
|||
} |
|||
), |
|||
body: new Scrollbar( |
|||
child: new ListView( |
|||
padding: EdgeInsets.symmetric(vertical: _dense ? 4.0f : 8.0f), |
|||
children: listTiles.ToList() |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using uiwidgets; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
class MenuDemo : StatefulWidget { |
|||
public MenuDemo(Key key = null) : base(key: key) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public static readonly string routeName = "/material/menu"; |
|||
|
|||
public override State createState() => new MenuDemoState(); |
|||
} |
|||
|
|||
class MenuDemoState : State<MenuDemo> { |
|||
readonly GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key(); |
|||
|
|||
static readonly string _simpleValue1 = "Menu item value one"; |
|||
static readonly string _simpleValue2 = "Menu item value two"; |
|||
static readonly string _simpleValue3 = "Menu item value three"; |
|||
string _simpleValue; |
|||
|
|||
readonly string _checkedValue1 = "One"; |
|||
readonly string _checkedValue2 = "Two"; |
|||
readonly string _checkedValue3 = "Free"; |
|||
readonly string _checkedValue4 = "Four"; |
|||
List<string> _checkedValues; |
|||
|
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
_simpleValue = _simpleValue2; |
|||
_checkedValues = new List<string>{_checkedValue3}; |
|||
} |
|||
|
|||
void showInSnackBar(string value) { |
|||
_scaffoldKey.currentState.showSnackBar(new SnackBar( |
|||
content: new Text(value) |
|||
)); |
|||
} |
|||
|
|||
List<string> _showSelection = new List<string> { _simpleValue1, _simpleValue2, _simpleValue3 }; |
|||
|
|||
void showMenuSelection(string value) { |
|||
|
|||
if (_showSelection.Contains(value)) |
|||
_simpleValue = value; |
|||
showInSnackBar($"You selected: {value}"); |
|||
} |
|||
|
|||
void showCheckedMenuSelections(String value) { |
|||
if (_checkedValues.Contains(value)) |
|||
_checkedValues.Remove(value); |
|||
else |
|||
_checkedValues.Add(value); |
|||
|
|||
showInSnackBar($"Checked {_checkedValues.Count} items"); |
|||
} |
|||
|
|||
bool isChecked(string value) => _checkedValues.Contains(value); |
|||
|
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new Scaffold( |
|||
key: _scaffoldKey, |
|||
appBar: new AppBar( |
|||
title: new Text("Menus"), |
|||
actions: new List<Widget>{ |
|||
new MaterialDemoDocumentationButton(MenuDemo.routeName), |
|||
new PopupMenuButton<string>( |
|||
onSelected: showMenuSelection, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<string>>{ |
|||
new PopupMenuItem<string>( |
|||
value: "Toolbar menu", |
|||
child: new Text("Toolbar menu") |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: "Right here", |
|||
child: new Text("Right here") |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: "Hooray!", |
|||
child: new Text("Hooray!") |
|||
) |
|||
} |
|||
) |
|||
} |
|||
), |
|||
body: new ListTileTheme( |
|||
iconColor: Theme.of(context).brightness == Brightness.light |
|||
? Colors.grey[600] |
|||
: Colors.grey[500], |
|||
child: new ListView( |
|||
padding: material_.kMaterialListPadding, |
|||
children: new List<Widget>{ |
|||
// Pressing the PopupMenuButton on the right of this item shows
|
|||
// a simple menu with one disabled item. Typically the contents
|
|||
// of this "contextual menu" would reflect the app's state.
|
|||
new ListTile( |
|||
title: new Text("An item with a context menu button"), |
|||
trailing: new PopupMenuButton<string>( |
|||
padding: EdgeInsets.zero, |
|||
onSelected: showMenuSelection, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<string>>{ |
|||
new PopupMenuItem<string>( |
|||
value: _simpleValue1, |
|||
child: new Text("Context menu item one") |
|||
), |
|||
new PopupMenuItem<string>( |
|||
enabled: false, |
|||
child: new Text("A disabled menu item") |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: _simpleValue3, |
|||
child: new Text("Context menu item three") |
|||
) |
|||
} |
|||
) |
|||
), |
|||
// Pressing the PopupMenuButton on the right of this item shows
|
|||
// a menu whose items have text labels and icons and a divider
|
|||
// That separates the first three items from the last one.
|
|||
new ListTile( |
|||
title: new Text("An item with a sectioned menu"), |
|||
trailing: new PopupMenuButton<string>( |
|||
padding: EdgeInsets.zero, |
|||
onSelected: showMenuSelection, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<string>>{ |
|||
new PopupMenuItem<string>( |
|||
value: "Preview", |
|||
child: new ListTile( |
|||
leading: new Icon(Icons.visibility), |
|||
title: new Text("Preview") |
|||
) |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: "Share", |
|||
child: new ListTile( |
|||
leading: new Icon(Icons.person_add), |
|||
title: new Text("Share") |
|||
) |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: "Get Link", |
|||
child: new ListTile( |
|||
leading: new Icon(Icons.link), |
|||
title: new Text("Get link") |
|||
) |
|||
), |
|||
new PopupMenuDivider<string>(), |
|||
new PopupMenuItem<string>( |
|||
value: "Remove", |
|||
child: new ListTile( |
|||
leading: new Icon(Icons.delete), |
|||
title: new Text("Remove") |
|||
) |
|||
) |
|||
} |
|||
) |
|||
), |
|||
// This entire list item is a PopupMenuButton. Tapping anywhere shows
|
|||
// a menu whose current value is highlighted and aligned over the
|
|||
// list item's center line.
|
|||
new PopupMenuButton<string>( |
|||
padding: EdgeInsets.zero, |
|||
initialValue: _simpleValue, |
|||
onSelected: showMenuSelection, |
|||
child: new ListTile( |
|||
title: new Text("An item with a simple menu"), |
|||
subtitle: new Text(_simpleValue) |
|||
), |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<string>>{ |
|||
new PopupMenuItem<string>( |
|||
value: _simpleValue1, |
|||
child: new Text(_simpleValue1) |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: _simpleValue2, |
|||
child: new Text(_simpleValue2) |
|||
), |
|||
new PopupMenuItem<string>( |
|||
value: _simpleValue3, |
|||
child: new Text(_simpleValue3) |
|||
) |
|||
} |
|||
), |
|||
// Pressing the PopupMenuButton on the right of this item shows a menu
|
|||
// whose items have checked icons that reflect this app's state.
|
|||
new ListTile( |
|||
title: new Text("An item with a checklist menu"), |
|||
trailing: new PopupMenuButton<string>( |
|||
padding: EdgeInsets.zero, |
|||
onSelected: showCheckedMenuSelections, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<string>>{ |
|||
new CheckedPopupMenuItem<string>( |
|||
value: _checkedValue1, |
|||
isChecked: isChecked(_checkedValue1), |
|||
child: new Text(_checkedValue1) |
|||
), |
|||
new CheckedPopupMenuItem<string>( |
|||
value: _checkedValue2, |
|||
enabled: false, |
|||
isChecked: isChecked(_checkedValue2), |
|||
child: new Text(_checkedValue2) |
|||
), |
|||
new CheckedPopupMenuItem<string>( |
|||
value: _checkedValue3, |
|||
isChecked: isChecked(_checkedValue3), |
|||
child: new Text(_checkedValue3) |
|||
), |
|||
new CheckedPopupMenuItem<string>( |
|||
value: _checkedValue4, |
|||
isChecked: isChecked(_checkedValue4), |
|||
child: new Text(_checkedValue4) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue