xingweizhu
4 年前
当前提交
49bd6bad
共有 25 个文件被更改,包括 3248 次插入 和 19 次删除
-
7Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/about.cs
-
7Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/updater.cs
-
2com.unity.uiwidgets/Runtime/material/banner.cs
-
2com.unity.uiwidgets/Runtime/material/bottom_sheet.cs
-
10com.unity.uiwidgets/Runtime/material/popup_menu.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material.meta
-
241Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/demo.cs.meta
-
472Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/backdrop_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/backdrop_demo.cs.meta
-
126Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/banner_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/banner_demo.cs.meta
-
600Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/bottom_app_bar_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/bottom_app_bar_demo.cs.meta
-
254Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/bottom_navigation_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/bottom_navigation_demo.cs.meta
-
390Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/buttons_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/buttons_demo.cs.meta
-
477Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/cards_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/cards_demo.cs.meta
-
365Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/chip_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/chip_demo.cs.meta
-
284Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/data_table_demo.cs
-
3Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/data_table_demo.cs.meta
|
|||
fileFormatVersion: 2 |
|||
guid: 27e2b642479d4616ad980ef32f76e152 |
|||
timeCreated: 1612406310 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.async2; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.gallery |
|||
{ |
|||
public static class BrowserUtils |
|||
{ |
|||
internal static void launch(string url) |
|||
{ |
|||
Process.Start(url); |
|||
} |
|||
|
|||
internal static bool canLaunch(string url) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
internal class ComponentDemoTabData : IEquatable<ComponentDemoTabData> |
|||
{ |
|||
public ComponentDemoTabData( |
|||
Widget demoWidget = null, |
|||
string exampleCodeTag = null, |
|||
string description = null, |
|||
string tabName = null, |
|||
string documentationUrl = null |
|||
) |
|||
{ |
|||
this.demoWidget = demoWidget; |
|||
this.exampleCodeTag = exampleCodeTag; |
|||
this.description = description; |
|||
this.tabName = tabName; |
|||
this.documentationUrl = documentationUrl; |
|||
} |
|||
|
|||
public readonly Widget demoWidget; |
|||
public readonly string exampleCodeTag; |
|||
public readonly string description; |
|||
public readonly string tabName; |
|||
public readonly string documentationUrl; |
|||
|
|||
public bool Equals(ComponentDemoTabData other) |
|||
{ |
|||
if (ReferenceEquals(null, other)) return false; |
|||
|
|||
if (ReferenceEquals(this, other)) return true; |
|||
|
|||
return this.tabName.Equals(other.tabName) |
|||
&& this.description.Equals(other.description) |
|||
&& this.documentationUrl.Equals(other.documentationUrl); |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (ReferenceEquals(null, obj)) return false; |
|||
|
|||
if (ReferenceEquals(this, obj)) return true; |
|||
|
|||
if (obj.GetType() != this.GetType()) return false; |
|||
|
|||
return this.Equals((ComponentDemoTabData) obj); |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
var hashCode = (this.tabName.GetHashCode() * 397); |
|||
hashCode = (hashCode * 397) ^ this.description.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.documentationUrl.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
public static bool operator ==(ComponentDemoTabData left, ComponentDemoTabData right) |
|||
{ |
|||
return Equals(left, right); |
|||
} |
|||
|
|||
public static bool operator !=(ComponentDemoTabData left, ComponentDemoTabData right) |
|||
{ |
|||
return !Equals(left, right); |
|||
} |
|||
} |
|||
|
|||
|
|||
internal class TabbedComponentDemoScaffold : StatelessWidget |
|||
{ |
|||
public TabbedComponentDemoScaffold( |
|||
List<ComponentDemoTabData> demos, |
|||
string title, |
|||
List<Widget> actions, |
|||
bool isScrollable = true, |
|||
bool showExampleCodeAction = true |
|||
) |
|||
{ |
|||
this.title = title; |
|||
this.demos = demos; |
|||
this.actions = actions; |
|||
this.isScrollable = isScrollable; |
|||
this.showExampleCodeAction = showExampleCodeAction; |
|||
} |
|||
|
|||
public readonly List<ComponentDemoTabData> demos; |
|||
public readonly string title; |
|||
public readonly List<Widget> actions; |
|||
public readonly bool isScrollable; |
|||
public readonly bool showExampleCodeAction; |
|||
|
|||
private void _showExampleCode(BuildContext context) |
|||
{ |
|||
string tag = this.demos[DefaultTabController.of(context).index].exampleCodeTag; |
|||
if (tag != null) D.assert(false, () => "TO DO >>>"); |
|||
/*Navigator.push(context, MaterialPageRoute<FullScreenCodeDialog>( |
|||
builder: (BuildContext context) => FullScreenCodeDialog(exampleCodeTag: tag) |
|||
));*/ |
|||
} |
|||
|
|||
private Future _showApiDocumentation(BuildContext context) |
|||
{ |
|||
string url = this.demos[DefaultTabController.of(context).index].documentationUrl; |
|||
if (url == null) |
|||
return null; |
|||
|
|||
if (BrowserUtils.canLaunch(url)) |
|||
BrowserUtils.launch(url); |
|||
else |
|||
material_.showDialog<object>( |
|||
context: context, |
|||
builder: (BuildContext subContext) => |
|||
{ |
|||
return new SimpleDialog( |
|||
title: new Text("Couldn't display URL:"), |
|||
children: new List<Widget> |
|||
{ |
|||
new Padding( |
|||
padding: EdgeInsets.symmetric(horizontal: 16.0f), |
|||
child: new Text(url) |
|||
) |
|||
} |
|||
); |
|||
} |
|||
); |
|||
|
|||
return Future.value(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
var children = new List<Widget>(this.actions); |
|||
children.Add(new Builder( |
|||
builder: (BuildContext subContext) => |
|||
{ |
|||
return new IconButton( |
|||
icon: new Icon(Icons.library_books), |
|||
onPressed: () => this._showApiDocumentation(context) |
|||
); |
|||
} |
|||
) |
|||
); |
|||
|
|||
if (this.showExampleCodeAction) |
|||
children.Add(new Builder( |
|||
builder: (BuildContext subContext) => |
|||
{ |
|||
return new IconButton( |
|||
icon: new Icon(Icons.code), |
|||
tooltip: "Show example code", |
|||
onPressed: () => this._showExampleCode(context) |
|||
); |
|||
} |
|||
)); |
|||
|
|||
return new DefaultTabController( |
|||
length: this.demos.Count, |
|||
child: new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text(this.title), |
|||
actions: children, |
|||
bottom: new TabBar( |
|||
isScrollable: this.isScrollable, |
|||
tabs: this.demos.Select<ComponentDemoTabData, Widget>((ComponentDemoTabData data) => |
|||
new Tab(text: data.tabName)).ToList() |
|||
) |
|||
), |
|||
body: new TabBarView( |
|||
children: this.demos.Select<ComponentDemoTabData, Widget>((ComponentDemoTabData demo) => |
|||
{ |
|||
return new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
new Padding( |
|||
padding: EdgeInsets.all(16.0f), |
|||
child: new Text(demo.description, |
|||
style: Theme.of(context).textTheme.subtitle1 |
|||
) |
|||
), |
|||
new Expanded(child: demo.demoWidget) |
|||
} |
|||
) |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class MaterialDemoDocumentationButton : StatelessWidget |
|||
{ |
|||
internal MaterialDemoDocumentationButton(string routeName, Key key = null) : base(key: key) |
|||
{ |
|||
D.assert( |
|||
GalleryDemo.kDemoDocumentationUrl[routeName] != null, |
|||
() => $"A documentation URL was not specified for demo route {routeName} in kAllGalleryDemos" |
|||
); |
|||
this.documentationUrl = GalleryDemo.kDemoDocumentationUrl[routeName]; |
|||
} |
|||
|
|||
public readonly string documentationUrl; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new IconButton( |
|||
icon: new Icon(Icons.library_books), |
|||
tooltip: "API documentation", |
|||
onPressed: () => BrowserUtils.launch(this.documentationUrl) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a66930d03e874eb0ba49812d9c1f952f |
|||
timeCreated: 1612409591 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using uiwidgets; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Image = Unity.UIWidgets.widgets.Image; |
|||
using Material = Unity.UIWidgets.material.Material; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
public class Category |
|||
{ |
|||
public Category(string title = null, List<string> assets = null) |
|||
{ |
|||
this.title = title; |
|||
this.assets = assets; |
|||
} |
|||
|
|||
public readonly string title; |
|||
public readonly List<string> assets; |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return $"{this.GetType()}({this.title})"; |
|||
} |
|||
|
|||
public static readonly List<Category> allCategories = new List<Category> |
|||
{ |
|||
new Category( |
|||
title: "Accessories", |
|||
assets: new List<string> |
|||
{ |
|||
"products/belt.png", |
|||
"products/earrings.png", |
|||
"products/backpack.png", |
|||
"products/hat.png", |
|||
"products/scarf.png", |
|||
"products/sunnies.png" |
|||
} |
|||
), |
|||
new Category( |
|||
title: "Blue", |
|||
assets: new List<string> |
|||
{ |
|||
"products/backpack.png", |
|||
"products/cup.png", |
|||
"products/napkins.png", |
|||
"products/top.png" |
|||
} |
|||
), |
|||
new Category( |
|||
title: "Cold Weather", |
|||
assets: new List<string> |
|||
{ |
|||
"products/jacket.png", |
|||
"products/jumper.png", |
|||
"products/scarf.png", |
|||
"products/sweater.png", |
|||
"products/sweats.png" |
|||
} |
|||
), |
|||
new Category( |
|||
title: "Home", |
|||
assets: new List<string> |
|||
{ |
|||
"products/cup.png", |
|||
"products/napkins.png", |
|||
"products/planters.png", |
|||
"products/table.png", |
|||
"products/teaset.png" |
|||
} |
|||
), |
|||
new Category( |
|||
title: "Tops", |
|||
assets: new List<string> |
|||
{ |
|||
"products/jumper.png", |
|||
"products/shirt.png", |
|||
"products/sweater.png", |
|||
"products/top.png" |
|||
} |
|||
), |
|||
new Category( |
|||
title: "Everything", |
|||
assets: new List<string> |
|||
{ |
|||
"products/backpack.png", |
|||
"products/belt.png", |
|||
"products/cup.png", |
|||
"products/dress.png", |
|||
"products/earrings.png", |
|||
"products/flatwear.png", |
|||
"products/hat.png", |
|||
"products/jacket.png", |
|||
"products/jumper.png", |
|||
"products/napkins.png", |
|||
"products/planters.png", |
|||
"products/scarf.png", |
|||
"products/shirt.png", |
|||
"products/sunnies.png", |
|||
"products/sweater.png", |
|||
"products/sweats.png", |
|||
"products/table.png", |
|||
"products/teaset.png", |
|||
"products/top.png" |
|||
} |
|||
) |
|||
}; |
|||
} |
|||
|
|||
|
|||
public class CategoryView : StatelessWidget |
|||
{ |
|||
public CategoryView(Key key = null, Category category = null) : base(key: key) |
|||
{ |
|||
this.category = category; |
|||
} |
|||
|
|||
public readonly Category category; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
return new Scrollbar( |
|||
child: new ListView( |
|||
key: new PageStorageKey<Category>(this.category), |
|||
padding: EdgeInsets.symmetric( |
|||
vertical: 16.0f, |
|||
horizontal: 64.0f |
|||
), |
|||
children: this.category.assets.Select<string, Widget>((string asset) => |
|||
{ |
|||
return new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: new List<Widget> |
|||
{ |
|||
new Card( |
|||
child: new Container( |
|||
width: 144.0f, |
|||
alignment: Alignment.center, |
|||
child: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
Image.asset( |
|||
asset, |
|||
package: "uiwidgets_gallery_assets", |
|||
fit: BoxFit.contain |
|||
), |
|||
new Container( |
|||
padding: EdgeInsets.only(bottom: 16.0f), |
|||
alignment: AlignmentDirectional.center, |
|||
child: new Text( |
|||
asset, |
|||
style: theme.textTheme.caption |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
), |
|||
new SizedBox(height: 24.0f) |
|||
} |
|||
); |
|||
}).ToList() |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class BackdropPanel : StatelessWidget |
|||
{ |
|||
public BackdropPanel( |
|||
Key key = null, |
|||
VoidCallback onTap = null, |
|||
GestureDragUpdateCallback onVerticalDragUpdate = null, |
|||
GestureDragEndCallback onVerticalDragEnd = null, |
|||
Widget title = null, |
|||
Widget child = null |
|||
) : base(key: key) |
|||
{ |
|||
this.onTap = onTap; |
|||
this.onVerticalDragUpdate = onVerticalDragUpdate; |
|||
this.onVerticalDragEnd = onVerticalDragEnd; |
|||
this.title = title; |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly VoidCallback onTap; |
|||
public readonly GestureDragUpdateCallback onVerticalDragUpdate; |
|||
public readonly GestureDragEndCallback onVerticalDragEnd; |
|||
public readonly Widget title; |
|||
public readonly Widget child; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
return new Material( |
|||
elevation: 2.0f, |
|||
borderRadius: BorderRadius.only( |
|||
topLeft: Radius.circular(16.0f), |
|||
topRight: Radius.circular(16.0f) |
|||
), |
|||
child: new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: new List<Widget> |
|||
{ |
|||
new GestureDetector( |
|||
behavior: HitTestBehavior.opaque, |
|||
onVerticalDragUpdate: this.onVerticalDragUpdate, |
|||
onVerticalDragEnd: this.onVerticalDragEnd, |
|||
onTap: () => { this.onTap?.Invoke(); }, |
|||
child: new Container( |
|||
height: 48.0f, |
|||
//TODO: uncomment this when fixes on EdgeInsetsDirectional lands
|
|||
//padding: EdgeInsetsDirectional.only(start: 16.0f),
|
|||
padding: EdgeInsets.only(left: 16.0f), |
|||
alignment: AlignmentDirectional.centerStart, |
|||
child: new DefaultTextStyle( |
|||
style: theme.textTheme.subtitle1, |
|||
child: new Tooltip( |
|||
message: "Tap to dismiss", |
|||
child: this.title |
|||
) |
|||
) |
|||
) |
|||
), |
|||
new Divider(height: 1.0f), |
|||
new Expanded(child: this.child) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class BackdropTitle : AnimatedWidget |
|||
{ |
|||
public BackdropTitle( |
|||
Key key = null, |
|||
Animation<float> listenable = null |
|||
) : base(key: key, listenable: listenable) |
|||
{ |
|||
} |
|||
|
|||
protected override Widget build(BuildContext context) |
|||
{ |
|||
Animation<float> animation = this.listenable as Animation<float>; |
|||
return new DefaultTextStyle( |
|||
style: Theme.of(context).primaryTextTheme.headline6, |
|||
softWrap: false, |
|||
overflow: TextOverflow.ellipsis, |
|||
child: new Stack( |
|||
children: new List<Widget> |
|||
{ |
|||
new Opacity( |
|||
opacity: new CurvedAnimation( |
|||
parent: new ReverseAnimation(animation), |
|||
curve: new Interval(0.5f, 1.0f) |
|||
).value, |
|||
child: new Text("Select a Category") |
|||
), |
|||
new Opacity( |
|||
opacity: new CurvedAnimation( |
|||
parent: animation, |
|||
curve: new Interval(0.5f, 1.0f) |
|||
).value, |
|||
child: new Text("Asset Viewer") |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class BackdropDemo : StatefulWidget |
|||
{ |
|||
public static readonly string routeName = "/material/backdrop"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _BackdropDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _BackdropDemoState : SingleTickerProviderStateMixin<BackdropDemo> |
|||
{ |
|||
private GlobalKey _backdropKey = GlobalKey.key(debugLabel: "Backdrop"); |
|||
private AnimationController _controller; |
|||
private Category _category = Category.allCategories[0]; |
|||
|
|||
|
|||
public override void initState() |
|||
{ |
|||
base.initState(); |
|||
this._controller = new AnimationController( |
|||
duration: new TimeSpan(0, 0, 0, 0, 300), |
|||
value: 1.0f, |
|||
vsync: this |
|||
); |
|||
} |
|||
|
|||
public override void dispose() |
|||
{ |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
private void _changeCategory(Category category) |
|||
{ |
|||
this.setState(() => |
|||
{ |
|||
this._category = category; |
|||
this._controller.fling(velocity: 2.0f); |
|||
}); |
|||
} |
|||
|
|||
private bool _backdropPanelVisible |
|||
{ |
|||
get |
|||
{ |
|||
AnimationStatus status = this._controller.status; |
|||
return status == AnimationStatus.completed || status == AnimationStatus.forward; |
|||
} |
|||
} |
|||
|
|||
private void _toggleBackdropPanelVisibility() |
|||
{ |
|||
this._controller.fling(velocity: this._backdropPanelVisible ? -2.0f : 2.0f); |
|||
} |
|||
|
|||
private float _backdropHeight |
|||
{ |
|||
get |
|||
{ |
|||
RenderBox renderBox = this._backdropKey.currentContext.findRenderObject() as RenderBox; |
|||
return renderBox.size.height; |
|||
} |
|||
} |
|||
|
|||
// By design: the panel can only be opened with a swipe. To close the panel
|
|||
// the user must either tap its heading or the backdrop's menu icon.
|
|||
|
|||
private void _handleDragUpdate(DragUpdateDetails details) |
|||
{ |
|||
if (this._controller.isAnimating || this._controller.status == AnimationStatus.completed) |
|||
return; |
|||
|
|||
this._controller.setValue(this._controller.value - details.primaryDelta.Value / (this._backdropHeight)); |
|||
} |
|||
|
|||
private void _handleDragEnd(DragEndDetails details) |
|||
{ |
|||
if (this._controller.isAnimating || this._controller.status == AnimationStatus.completed) |
|||
return; |
|||
|
|||
float flingVelocity = details.velocity.pixelsPerSecond.dy / this._backdropHeight; |
|||
if (flingVelocity < 0.0f) |
|||
this._controller.fling(velocity: Mathf.Max(2.0f, -flingVelocity)); |
|||
else if (flingVelocity > 0.0f) |
|||
this._controller.fling(velocity: Mathf.Min(-2.0f, -flingVelocity)); |
|||
else |
|||
this._controller.fling(velocity: this._controller.value < 0.5 ? -2.0f : 2.0f); |
|||
} |
|||
|
|||
// Stacks a BackdropPanel, which displays the selected category, on top
|
|||
// of the backdrop. The categories are displayed with ListTiles. Just one
|
|||
// can be selected at a time. This is a LayoutWidgetBuild function because
|
|||
// we need to know how big the BackdropPanel will be to set up its
|
|||
// animation.
|
|||
private Widget _buildStack(BuildContext context, BoxConstraints constraints) |
|||
{ |
|||
float panelTitleHeight = 48.0f; |
|||
Size panelSize = constraints.biggest; |
|||
float panelTop = panelSize.height - panelTitleHeight; |
|||
|
|||
Animation<RelativeRect> panelAnimation = this._controller.drive( |
|||
new RelativeRectTween( |
|||
begin: RelativeRect.fromLTRB( |
|||
0.0f, |
|||
panelTop - MediaQuery.of(context).padding.bottom, |
|||
0.0f, |
|||
panelTop - panelSize.height |
|||
), |
|||
end: RelativeRect.fromLTRB(0.0f, 0.0f, 0.0f, 0.0f) |
|||
) |
|||
); |
|||
|
|||
ThemeData theme = Theme.of(context); |
|||
List<Widget> backdropItems = Category.allCategories.Select<Category, Widget>((Category category) => |
|||
{ |
|||
bool selected = category == this._category; |
|||
return new Material( |
|||
shape: new RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.all(Radius.circular(4.0f)) |
|||
), |
|||
color: selected |
|||
? Colors.white.withOpacity(0.25f) |
|||
: Colors.transparent, |
|||
child: new ListTile( |
|||
title: new Text(category.title), |
|||
selected: selected, |
|||
onTap: () => { this._changeCategory(category); } |
|||
) |
|||
); |
|||
}).ToList(); |
|||
|
|||
return new Container( |
|||
key: this._backdropKey, |
|||
color: theme.primaryColor, |
|||
child: new Stack( |
|||
children: new List<Widget> |
|||
{ |
|||
new ListTileTheme( |
|||
iconColor: theme.primaryIconTheme.color, |
|||
textColor: theme.primaryTextTheme.headline6.color.withOpacity(0.6f), |
|||
selectedColor: theme.primaryTextTheme.headline6.color, |
|||
child: new Padding( |
|||
padding: EdgeInsets.symmetric(horizontal: 16.0f), |
|||
child: new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.stretch, |
|||
children: backdropItems |
|||
) |
|||
) |
|||
), |
|||
new PositionedTransition( |
|||
rect: panelAnimation, |
|||
child: new BackdropPanel( |
|||
onTap: this._toggleBackdropPanelVisibility, |
|||
onVerticalDragUpdate: this._handleDragUpdate, |
|||
onVerticalDragEnd: this._handleDragEnd, |
|||
title: new Text(this._category.title), |
|||
child: new CategoryView(category: this._category) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
elevation: 0.0f, |
|||
title: new BackdropTitle( |
|||
listenable: this._controller.view |
|||
), |
|||
actions: new List<Widget> |
|||
{ |
|||
new IconButton( |
|||
onPressed: this._toggleBackdropPanelVisibility, |
|||
icon: new AnimatedIcon( |
|||
icon: AnimatedIcons.close_menu, |
|||
progress: this._controller.view |
|||
) |
|||
) |
|||
} |
|||
), |
|||
body: new LayoutBuilder( |
|||
builder: this._buildStack |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0d229d2babb945ec933ff8ce2c53a9f4 |
|||
timeCreated: 1612406341 |
|
|||
using System.Collections.Generic; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal enum BannerDemoAction |
|||
{ |
|||
reset, |
|||
showMultipleActions, |
|||
showLeading, |
|||
} |
|||
|
|||
internal class BannerDemo : StatefulWidget |
|||
{ |
|||
public BannerDemo(Key key = null) : base(key: key) |
|||
{ |
|||
} |
|||
|
|||
public static readonly string routeName = "/material/banner"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _BannerDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _BannerDemoState : State<BannerDemo> |
|||
{ |
|||
private const int _numItems = 20; |
|||
private bool _displayBanner = true; |
|||
private bool _showMultipleActions = true; |
|||
private bool _showLeading = true; |
|||
|
|||
private void handleDemoAction(BannerDemoAction action) |
|||
{ |
|||
this.setState(() => |
|||
{ |
|||
switch (action) |
|||
{ |
|||
case BannerDemoAction.reset: |
|||
this._displayBanner = true; |
|||
this._showMultipleActions = true; |
|||
this._showLeading = true; |
|||
break; |
|||
case BannerDemoAction.showMultipleActions: |
|||
this._showMultipleActions = !this._showMultipleActions; |
|||
break; |
|||
case BannerDemoAction.showLeading: |
|||
this._showLeading = !this._showLeading; |
|||
break; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
var children = new List<Widget> |
|||
{ |
|||
new FlatButton( |
|||
child: new Text("SIGN IN"), |
|||
onPressed: () => { this.setState(() => { this._displayBanner = false; }); } |
|||
) |
|||
}; |
|||
|
|||
if (this._showMultipleActions) |
|||
children.Add(new FlatButton( |
|||
child: new Text("DISMISS"), |
|||
onPressed: () => { this.setState(() => { this._displayBanner = false; }); } |
|||
)); |
|||
|
|||
|
|||
Widget banner = new MaterialBanner( |
|||
content: new Text("Your password was updated on your other device. Please sign in again."), |
|||
leading: this._showLeading ? new CircleAvatar(child: new Icon(Icons.access_alarm)) : null, |
|||
actions: children |
|||
); |
|||
|
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Banner"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(BannerDemo.routeName), |
|||
new PopupMenuButton<BannerDemoAction>( |
|||
onSelected: this.handleDemoAction, |
|||
itemBuilder: (BuildContext subContext) => |
|||
{ |
|||
var menuEntries = new List<PopupMenuEntry<BannerDemoAction>>(); |
|||
menuEntries.Add(new PopupMenuItem<BannerDemoAction>( |
|||
value: BannerDemoAction.reset, |
|||
child: new Text("Reset the banner") |
|||
)); |
|||
|
|||
menuEntries.Add(new PopupMenuDivider<BannerDemoAction>()); |
|||
|
|||
menuEntries.Add(new CheckedPopupMenuItem<BannerDemoAction>( |
|||
value: BannerDemoAction.showMultipleActions, |
|||
isChecked: this._showMultipleActions, |
|||
child: new Text("Multiple actions") |
|||
)); |
|||
|
|||
menuEntries.Add(new CheckedPopupMenuItem<BannerDemoAction>( |
|||
value: BannerDemoAction.showLeading, |
|||
isChecked: this._showLeading, |
|||
child: new Text("Leading icon") |
|||
)); |
|||
|
|||
return menuEntries; |
|||
}) |
|||
} |
|||
), |
|||
body: ListView.builder(itemCount: this._displayBanner ? _numItems + 1 : _numItems, |
|||
itemBuilder: (BuildContext subContext, int index) => |
|||
{ |
|||
if (index == 0 && this._displayBanner) return banner; |
|||
|
|||
var itemIndex = this._displayBanner ? index : index + 1; |
|||
return new ListTile(title: new Text($"Item {itemIndex}")); |
|||
}) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e535b3a1ad7a44868e26cd44fecc9c31 |
|||
timeCreated: 1612408411 |
|
|||
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.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Canvas = Unity.UIWidgets.ui.Canvas; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
using Material = Unity.UIWidgets.material.Material; |
|||
using Rect = Unity.UIWidgets.ui.Rect; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal class BottomAppBarDemo : StatefulWidget |
|||
{ |
|||
public static readonly string routeName = "/material/bottom_app_bar"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _BottomAppBarDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _BottomAppBarDemoState : State<BottomAppBarDemo> |
|||
{ |
|||
private static GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key(); |
|||
|
|||
// FAB shape
|
|||
|
|||
private static readonly _ChoiceValue<Widget> kNoFab = new _ChoiceValue<Widget>( |
|||
title: "None", |
|||
label: "do not show a floating action button", |
|||
value: null |
|||
); |
|||
|
|||
private static readonly _ChoiceValue<Widget> kCircularFab = new _ChoiceValue<Widget>( |
|||
title: "Circular", |
|||
label: "circular floating action button", |
|||
value: new FloatingActionButton( |
|||
onPressed: _showSnackbar, |
|||
child: new Icon(Icons.add), |
|||
backgroundColor: Colors.orange |
|||
) |
|||
); |
|||
|
|||
private static readonly _ChoiceValue<Widget> kDiamondFab = new _ChoiceValue<Widget>( |
|||
title: "Diamond", |
|||
label: "diamond shape floating action button", |
|||
value: new _DiamondFab( |
|||
onPressed: _showSnackbar, |
|||
child: new Icon(Icons.add) |
|||
) |
|||
); |
|||
|
|||
// Notch
|
|||
private static readonly _ChoiceValue<bool> kShowNotchTrue = new _ChoiceValue<bool>( |
|||
title: "On", |
|||
label: "show bottom appbar notch", |
|||
value: true |
|||
); |
|||
|
|||
private static readonly _ChoiceValue<bool> kShowNotchFalse = new _ChoiceValue<bool>( |
|||
title: "Off", |
|||
label: "do not show bottom appbar notch", |
|||
value: false |
|||
); |
|||
|
|||
// FAB Position
|
|||
|
|||
private static readonly _ChoiceValue<FloatingActionButtonLocation> kFabEndDocked = |
|||
new _ChoiceValue<FloatingActionButtonLocation>( |
|||
title: "Attached - End", |
|||
label: "floating action button is docked at the end of the bottom app bar", |
|||
value: FloatingActionButtonLocation.endDocked |
|||
); |
|||
|
|||
private static readonly _ChoiceValue<FloatingActionButtonLocation> kFabCenterDocked = |
|||
new _ChoiceValue<FloatingActionButtonLocation>( |
|||
title: "Attached - Center", |
|||
label: "floating action button is docked at the center of the bottom app bar", |
|||
value: FloatingActionButtonLocation.centerDocked |
|||
); |
|||
|
|||
private static readonly _ChoiceValue<FloatingActionButtonLocation> kFabEndFloat = |
|||
new _ChoiceValue<FloatingActionButtonLocation>( |
|||
title: "Free - End", |
|||
label: "floating action button floats above the end of the bottom app bar", |
|||
value: FloatingActionButtonLocation.endFloat |
|||
); |
|||
|
|||
private static readonly _ChoiceValue<FloatingActionButtonLocation> kFabCenterFloat = |
|||
new _ChoiceValue<FloatingActionButtonLocation>( |
|||
title: "Free - Center", |
|||
label: "floating action button is floats above the center of the bottom app bar", |
|||
value: FloatingActionButtonLocation.centerFloat |
|||
); |
|||
|
|||
private static void _showSnackbar() |
|||
{ |
|||
string text = |
|||
"When the Scaffold\"s floating action button location changes, " + |
|||
"the floating action button animates to its new position. " + |
|||
"The BottomAppBar adapts its shape appropriately."; |
|||
|
|||
_scaffoldKey.currentState.showSnackBar( |
|||
new SnackBar(content: new Text(text)) |
|||
); |
|||
} |
|||
|
|||
// App bar color
|
|||
private static List<_NamedColor> kBabColors = new List<_NamedColor> |
|||
{ |
|||
new _NamedColor(null, "Clear"), |
|||
new _NamedColor(new Color(0xFFFFC100), "Orange"), |
|||
new _NamedColor(new Color(0xFF91FAFF), "Light Blue"), |
|||
new _NamedColor(new Color(0xFF00D1FF), "Cyan"), |
|||
new _NamedColor(new Color(0xFF00BCFF), "Cerulean"), |
|||
new _NamedColor(new Color(0xFF009BEE), "Blue"), |
|||
}; |
|||
|
|||
private _ChoiceValue<Widget> _fabShape = kCircularFab; |
|||
private _ChoiceValue<bool> _showNotch = kShowNotchTrue; |
|||
private _ChoiceValue<FloatingActionButtonLocation> _fabLocation = kFabEndDocked; |
|||
private Color _babColor = kBabColors.First().color; |
|||
|
|||
private void _onShowNotchChanged(_ChoiceValue<bool> value) |
|||
{ |
|||
this.setState(() => { this._showNotch = value; }); |
|||
} |
|||
|
|||
private void _onFabShapeChanged(_ChoiceValue<Widget> value) |
|||
{ |
|||
this.setState(() => { this._fabShape = value; }); |
|||
} |
|||
|
|||
private void _onFabLocationChanged(_ChoiceValue<FloatingActionButtonLocation> value) |
|||
{ |
|||
this.setState(() => { this._fabLocation = value; }); |
|||
} |
|||
|
|||
private void _onBabColorChanged(Color value) |
|||
{ |
|||
this.setState(() => { this._babColor = value; }); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Scaffold( |
|||
key: _scaffoldKey, |
|||
appBar: new AppBar( |
|||
title: new Text("Bottom app bar"), |
|||
elevation: 0.0f, |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(BottomAppBarDemo.routeName), |
|||
new IconButton( |
|||
icon: new Icon(Icons.sentiment_very_satisfied), |
|||
onPressed: () => |
|||
{ |
|||
this.setState(() => |
|||
{ |
|||
this._fabShape = this._fabShape == kCircularFab ? kDiamondFab : kCircularFab; |
|||
}); |
|||
} |
|||
) |
|||
} |
|||
), |
|||
body: new Scrollbar( |
|||
child: new ListView( |
|||
padding: EdgeInsets.only(bottom: 88.0f), |
|||
children: new List<Widget> |
|||
{ |
|||
new _Heading("FAB Shape"), |
|||
|
|||
new _RadioItem<Widget>(kCircularFab, this._fabShape, this._onFabShapeChanged), |
|||
new _RadioItem<Widget>(kDiamondFab, this._fabShape, this._onFabShapeChanged), |
|||
new _RadioItem<Widget>(kNoFab, this._fabShape, this._onFabShapeChanged), |
|||
|
|||
new Divider(), |
|||
new _Heading("Notch"), |
|||
|
|||
new _RadioItem<bool>(kShowNotchTrue, this._showNotch, this._onShowNotchChanged), |
|||
new _RadioItem<bool>(kShowNotchFalse, this._showNotch, this._onShowNotchChanged), |
|||
|
|||
new Divider(), |
|||
new _Heading("FAB Position"), |
|||
|
|||
new _RadioItem<FloatingActionButtonLocation>(kFabEndDocked, this._fabLocation, |
|||
this._onFabLocationChanged), |
|||
new _RadioItem<FloatingActionButtonLocation>(kFabCenterDocked, this._fabLocation, |
|||
this._onFabLocationChanged), |
|||
new _RadioItem<FloatingActionButtonLocation>(kFabEndFloat, this._fabLocation, |
|||
this._onFabLocationChanged), |
|||
new _RadioItem<FloatingActionButtonLocation>(kFabCenterFloat, this._fabLocation, |
|||
this._onFabLocationChanged), |
|||
|
|||
new Divider(), |
|||
new _Heading("App bar color"), |
|||
|
|||
new _ColorsItem(kBabColors, this._babColor, this._onBabColorChanged) |
|||
} |
|||
) |
|||
), |
|||
floatingActionButton: this._fabShape.value, |
|||
floatingActionButtonLocation: this._fabLocation.value, |
|||
bottomNavigationBar: new _DemoBottomAppBar( |
|||
color: this._babColor, |
|||
fabLocation: this._fabLocation.value, |
|||
shape: this._selectNotch() |
|||
) |
|||
); |
|||
} |
|||
|
|||
private NotchedShape _selectNotch() |
|||
{ |
|||
if (!this._showNotch.value) |
|||
return null; |
|||
if (this._fabShape == kCircularFab) |
|||
return new CircularNotchedRectangle(); |
|||
if (this._fabShape == kDiamondFab) |
|||
return new _DiamondNotchedRectangle(); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
internal class _ChoiceValue<T> |
|||
{ |
|||
public _ChoiceValue(T value, string title, string label) |
|||
{ |
|||
this.value = value; |
|||
this.title = title; |
|||
this.label = label; |
|||
} |
|||
|
|||
public readonly T value; |
|||
public readonly string title; |
|||
public readonly string label; // For the Semantics widget that contains title
|
|||
|
|||
public override string ToString() |
|||
{ |
|||
return $"{this.GetType()}(\"{this.title}\")"; |
|||
} |
|||
} |
|||
|
|||
internal class _RadioItem<T> : StatelessWidget |
|||
{ |
|||
public _RadioItem(_ChoiceValue<T> value, _ChoiceValue<T> groupValue, ValueChanged<_ChoiceValue<T>> onChanged) |
|||
{ |
|||
this.value = value; |
|||
this.groupValue = groupValue; |
|||
this.onChanged = onChanged; |
|||
} |
|||
|
|||
public readonly _ChoiceValue<T> value; |
|||
public readonly _ChoiceValue<T> groupValue; |
|||
public readonly ValueChanged<_ChoiceValue<T>> onChanged; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
return new Container( |
|||
height: 56.0f, |
|||
//TODO: uncomment this when fixes on EdgeInsetsDirectional lands
|
|||
//padding: const EdgeInsetsDirectional.only(start: 16.0),
|
|||
padding: EdgeInsets.only(left: 16.0f), |
|||
alignment: AlignmentDirectional.centerStart, |
|||
child: new Row( |
|||
children: new List<Widget> |
|||
{ |
|||
new Radio<_ChoiceValue<T>>( |
|||
value: this.value, |
|||
groupValue: this.groupValue, |
|||
onChanged: this.onChanged |
|||
), |
|||
new Expanded( |
|||
child: new GestureDetector( |
|||
behavior: HitTestBehavior.opaque, |
|||
onTap: () => { this.onChanged(this.value); }, |
|||
child: new Text(this.value.title, |
|||
style: theme.textTheme.subtitle1 |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _NamedColor |
|||
{ |
|||
public _NamedColor(Color color, string name) |
|||
{ |
|||
this.color = color; |
|||
this.name = name; |
|||
} |
|||
|
|||
public readonly Color color; |
|||
public readonly string name; |
|||
} |
|||
|
|||
internal class _ColorsItem : StatelessWidget |
|||
{ |
|||
public _ColorsItem(List<_NamedColor> colors, Color selectedColor, ValueChanged<Color> onChanged) |
|||
{ |
|||
this.colors = colors; |
|||
this.selectedColor = selectedColor; |
|||
this.onChanged = onChanged; |
|||
} |
|||
|
|||
public readonly List<_NamedColor> colors; |
|||
public readonly Color selectedColor; |
|||
public readonly ValueChanged<Color> onChanged; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
|||
children: this.colors.Select<_NamedColor, Widget>((_NamedColor namedColor) => |
|||
{ |
|||
return new RawMaterialButton( |
|||
onPressed: () => { this.onChanged(namedColor.color); }, |
|||
constraints: BoxConstraints.tightFor( |
|||
width: 32.0f, |
|||
height: 32.0f |
|||
), |
|||
fillColor: namedColor.color, |
|||
shape: new CircleBorder( |
|||
side: new BorderSide( |
|||
color: namedColor.color == this.selectedColor ? Colors.black : new Color(0xFFD5D7DA), |
|||
width: 2.0f |
|||
) |
|||
), |
|||
child: new Text( |
|||
namedColor.name |
|||
) |
|||
); |
|||
}).ToList() |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _Heading : StatelessWidget |
|||
{ |
|||
public _Heading(string text) |
|||
{ |
|||
this.text = text; |
|||
} |
|||
|
|||
public readonly string text; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
return new Container( |
|||
height: 48.0f, |
|||
//TODO: uncomment this when fixes on EdgeInsetsDirectional lands
|
|||
//padding: EdgeInsetsDirectional.only(start: 56.0),
|
|||
padding: EdgeInsets.only(left: 56.0f), |
|||
alignment: AlignmentDirectional.centerStart, |
|||
child: new Text(this.text, |
|||
style: theme.textTheme.bodyText2.copyWith( |
|||
color: theme.primaryColor |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _DemoBottomAppBar : StatelessWidget |
|||
{ |
|||
public _DemoBottomAppBar( |
|||
Color color = null, |
|||
FloatingActionButtonLocation fabLocation = null, |
|||
NotchedShape shape = null |
|||
) |
|||
{ |
|||
this.color = color; |
|||
this.fabLocation = fabLocation; |
|||
this.shape = shape; |
|||
} |
|||
|
|||
public readonly Color color; |
|||
public readonly FloatingActionButtonLocation fabLocation; |
|||
public readonly NotchedShape shape; |
|||
|
|||
private static readonly List<FloatingActionButtonLocation> kCenterLocations = |
|||
new List<FloatingActionButtonLocation> |
|||
{ |
|||
FloatingActionButtonLocation.centerDocked, |
|||
FloatingActionButtonLocation.centerFloat |
|||
}; |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
var children = new List<Widget> |
|||
{ |
|||
new IconButton( |
|||
icon: new Icon(Icons.menu), |
|||
onPressed: () => |
|||
{ |
|||
material_.showModalBottomSheet<object>( |
|||
context: context, |
|||
builder: (BuildContext subContext) => new _DemoDrawer() |
|||
); |
|||
} |
|||
) |
|||
}; |
|||
|
|||
if (kCenterLocations.Contains(this.fabLocation)) children.Add(new Expanded(child: new SizedBox())); |
|||
|
|||
children.Add( |
|||
new IconButton( |
|||
icon: new Icon(Icons.search), |
|||
onPressed: () => |
|||
{ |
|||
Scaffold.of(context).showSnackBar( |
|||
new SnackBar(content: new Text("This is a dummy search action.")) |
|||
); |
|||
} |
|||
) |
|||
); |
|||
|
|||
children.Add( |
|||
new IconButton( |
|||
icon: new Icon( |
|||
Theme.of(context).platform == RuntimePlatform.IPhonePlayer |
|||
? Icons.more_horiz |
|||
: Icons.more_vert |
|||
), |
|||
onPressed: () => |
|||
{ |
|||
Scaffold.of(context).showSnackBar( |
|||
new SnackBar(content: new Text("This is a dummy menu action.")) |
|||
); |
|||
} |
|||
) |
|||
); |
|||
|
|||
|
|||
return new BottomAppBar( |
|||
color: this.color, |
|||
shape: this.shape, |
|||
child: new Row(children: children) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _DemoDrawer : StatelessWidget |
|||
{ |
|||
public _DemoDrawer() |
|||
{ |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Drawer( |
|||
child: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
new ListTile( |
|||
leading: new Icon(Icons.search), |
|||
title: new Text("Search") |
|||
), |
|||
new ListTile( |
|||
leading: new Icon(Icons.threed_rotation), |
|||
title: new Text("3D") |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _DiamondFab : StatelessWidget |
|||
{ |
|||
public _DiamondFab( |
|||
Widget child = null, |
|||
VoidCallback onPressed = null |
|||
) |
|||
{ |
|||
this.child = child; |
|||
this.onPressed = onPressed; |
|||
} |
|||
|
|||
public readonly Widget child; |
|||
public readonly VoidCallback onPressed; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Material( |
|||
shape: new _DiamondBorder(), |
|||
color: Colors.orange, |
|||
child: new InkWell( |
|||
onTap: () => this.onPressed?.Invoke(), |
|||
child: new Container( |
|||
width: 56.0f, |
|||
height: 56.0f, |
|||
child: IconTheme.merge( |
|||
data: new IconThemeData(color: Theme.of(context).accentIconTheme.color), |
|||
child: this.child |
|||
) |
|||
) |
|||
), |
|||
elevation: 6.0f |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class _DiamondNotchedRectangle : NotchedShape |
|||
{ |
|||
public _DiamondNotchedRectangle() |
|||
{ |
|||
} |
|||
|
|||
public override Path getOuterPath(Rect host, Rect guest) |
|||
{ |
|||
if (!host.overlaps(guest)) |
|||
{ |
|||
var path = new Path(); |
|||
path.addRect(host); |
|||
return path; |
|||
} |
|||
|
|||
D.assert(guest.width > 0.0f); |
|||
|
|||
Rect intersection = guest.intersect(host); |
|||
// We are computing a "V" shaped notch, as in this diagram:
|
|||
// -----\**** /-----
|
|||
// \ /
|
|||
// \ /
|
|||
// \ /
|
|||
//
|
|||
// "-" marks the top edge of the bottom app bar.
|
|||
// "\" and "/" marks the notch outline
|
|||
//
|
|||
// notchToCenter is the horizontal distance between the guest's center and
|
|||
// the host's top edge where the notch starts (marked with "*").
|
|||
// We compute notchToCenter by similar triangles:
|
|||
float notchToCenter = |
|||
intersection.height * (guest.height / 2.0f) |
|||
/ (guest.width / 2.0f); |
|||
|
|||
var retPath = new Path(); |
|||
retPath.moveTo(host.left, host.top); |
|||
retPath.lineTo(guest.center.dx - notchToCenter, host.top); |
|||
retPath.lineTo(guest.left + guest.width / 2.0f, guest.bottom); |
|||
retPath.lineTo(guest.center.dx + notchToCenter, host.top); |
|||
retPath.lineTo(host.right, host.top); |
|||
retPath.lineTo(host.right, host.bottom); |
|||
retPath.lineTo(host.left, host.bottom); |
|||
retPath.close(); |
|||
|
|||
return retPath; |
|||
} |
|||
} |
|||
|
|||
internal class _DiamondBorder : ShapeBorder |
|||
{ |
|||
public _DiamondBorder() |
|||
{ |
|||
} |
|||
|
|||
public override EdgeInsetsGeometry dimensions => EdgeInsets.only(); |
|||
|
|||
|
|||
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) |
|||
{ |
|||
return this.getOuterPath(rect, textDirection: textDirection); |
|||
} |
|||
|
|||
|
|||
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) |
|||
{ |
|||
var path = new Path(); |
|||
path.moveTo(rect.left + rect.width / 2.0f, rect.top); |
|||
path.lineTo(rect.right, rect.top + rect.height / 2.0f); |
|||
path.lineTo(rect.left + rect.width / 2.0f, rect.bottom); |
|||
path.lineTo(rect.left, rect.top + rect.height / 2.0f); |
|||
path.close(); |
|||
return path; |
|||
} |
|||
|
|||
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) |
|||
{ |
|||
} |
|||
|
|||
|
|||
public override ShapeBorder scale(float t) |
|||
{ |
|||
return null; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: c1ce2a2020fa4af0b42ffceb1bba8f6a |
|||
timeCreated: 1612409991 |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using uiwidgets; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.scheduler2; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal class NavigationIconView |
|||
{ |
|||
internal NavigationIconView( |
|||
Widget icon = null, |
|||
Widget activeIcon = null, |
|||
string title = null, |
|||
Color color = null, |
|||
TickerProvider vsync = null |
|||
) |
|||
{ |
|||
this._icon = icon; |
|||
this._color = color; |
|||
this._title = title; |
|||
this.item = new BottomNavigationBarItem( |
|||
icon: icon, |
|||
activeIcon: activeIcon, |
|||
title: new Text(title), |
|||
backgroundColor: color |
|||
); |
|||
this.controller = new AnimationController( |
|||
duration: ThemeUtils.kThemeAnimationDuration, |
|||
vsync: vsync); |
|||
|
|||
this._animation = this.controller.drive(new CurveTween( |
|||
curve: new Interval(0.5f, 1.0f, curve: Curves.fastOutSlowIn) |
|||
)); |
|||
} |
|||
|
|||
public readonly Widget _icon; |
|||
public readonly Color _color; |
|||
public readonly string _title; |
|||
public readonly BottomNavigationBarItem item; |
|||
public readonly AnimationController controller; |
|||
private Animation<float> _animation; |
|||
|
|||
internal FadeTransition transition(BottomNavigationBarType type, BuildContext context) |
|||
{ |
|||
Color iconColor; |
|||
if (type == BottomNavigationBarType.shifting) |
|||
{ |
|||
iconColor = this._color; |
|||
} |
|||
else |
|||
{ |
|||
ThemeData themeData = Theme.of(context); |
|||
iconColor = themeData.brightness == Brightness.light |
|||
? themeData.primaryColor |
|||
: themeData.accentColor; |
|||
} |
|||
|
|||
return new FadeTransition( |
|||
opacity: this._animation, |
|||
child: new SlideTransition( |
|||
position: this._animation.drive( |
|||
new Tween<Offset>( |
|||
begin: new Offset(0.0f, 0.02f), // Slightly down.
|
|||
end: Offset.zero |
|||
) |
|||
), |
|||
child: new IconTheme( |
|||
data: new IconThemeData( |
|||
color: iconColor, |
|||
size: 120.0f |
|||
), |
|||
child: this._icon |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class CustomIcon : StatelessWidget |
|||
{ |
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
IconThemeData iconTheme = IconTheme.of(context); |
|||
return new Container( |
|||
margin: EdgeInsets.all(4.0f), |
|||
width: iconTheme.size - 8.0f, |
|||
height: iconTheme.size - 8.0f, |
|||
color: iconTheme.color |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class CustomInactiveIcon : StatelessWidget |
|||
{ |
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
IconThemeData iconTheme = IconTheme.of(context); |
|||
return new Container( |
|||
margin: EdgeInsets.all(4.0f), |
|||
width: iconTheme.size - 8.0f, |
|||
height: iconTheme.size - 8.0f, |
|||
decoration: new BoxDecoration( |
|||
border: Border.all(color: iconTheme.color, width: 2.0f) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class BottomNavigationDemo : StatefulWidget |
|||
{ |
|||
public static readonly string routeName = "/material/bottom_navigation"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _BottomNavigationDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _BottomNavigationDemoState : TickerProviderStateMixin<BottomNavigationDemo> |
|||
{ |
|||
private int _currentIndex = 0; |
|||
private BottomNavigationBarType _type = BottomNavigationBarType.shifting; |
|||
private List<NavigationIconView> _navigationViews; |
|||
|
|||
public override void initState() |
|||
{ |
|||
base.initState(); |
|||
this._navigationViews = new List<NavigationIconView> |
|||
{ |
|||
new NavigationIconView( |
|||
icon: new Icon(Icons.access_alarm), |
|||
title: "Alarm", |
|||
color: Colors.deepPurple, |
|||
vsync: this |
|||
), |
|||
new NavigationIconView( |
|||
activeIcon: new CustomIcon(), |
|||
icon: new CustomInactiveIcon(), |
|||
title: "Box", |
|||
color: Colors.deepOrange, |
|||
vsync: this |
|||
), |
|||
new NavigationIconView( |
|||
activeIcon: new Icon(Icons.cloud), |
|||
icon: new Icon(Icons.cloud_queue), |
|||
title: "Cloud", |
|||
color: Colors.teal, |
|||
vsync: this |
|||
), |
|||
new NavigationIconView( |
|||
activeIcon: new Icon(Icons.favorite), |
|||
icon: new Icon(Icons.favorite_border), |
|||
title: "Favorites", |
|||
color: Colors.indigo, |
|||
vsync: this |
|||
), |
|||
new NavigationIconView( |
|||
icon: new Icon(Icons.event_available), |
|||
title: "Event", |
|||
color: Colors.pink, |
|||
vsync: this |
|||
) |
|||
}; |
|||
|
|||
this._navigationViews[this._currentIndex].controller.setValue(1.0f); |
|||
} |
|||
|
|||
|
|||
public override void dispose() |
|||
{ |
|||
foreach (NavigationIconView view in this._navigationViews) |
|||
view.controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
private Widget _buildTransitionsStack() |
|||
{ |
|||
List<FadeTransition> transitions = new List<FadeTransition>(); |
|||
|
|||
foreach (NavigationIconView view in this._navigationViews) |
|||
transitions.Add(view.transition(this._type, this.context)); |
|||
|
|||
// We want to have the newly animating (fading in) views on top.
|
|||
transitions.Sort((FadeTransition a, FadeTransition b) => |
|||
{ |
|||
Animation<float> aAnimation = a.opacity; |
|||
Animation<float> bAnimation = b.opacity; |
|||
float aValue = aAnimation.value; |
|||
float bValue = bAnimation.value; |
|||
return aValue.CompareTo(bValue); |
|||
}); |
|||
|
|||
return new Stack(children: new List<Widget>(transitions)); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
BottomNavigationBar botNavBar = new BottomNavigationBar( |
|||
items: this._navigationViews |
|||
.Select<NavigationIconView, BottomNavigationBarItem>((NavigationIconView navigationView) => |
|||
navigationView.item) |
|||
.ToList(), |
|||
currentIndex: this._currentIndex, |
|||
type: this._type, |
|||
onTap: (int index) => |
|||
{ |
|||
this.setState(() => |
|||
{ |
|||
this._navigationViews[this._currentIndex].controller.reverse(); |
|||
this._currentIndex = index; |
|||
this._navigationViews[this._currentIndex].controller.forward(); |
|||
}); |
|||
} |
|||
); |
|||
|
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Bottom navigation"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(BottomNavigationDemo.routeName), |
|||
new PopupMenuButton<BottomNavigationBarType>( |
|||
onSelected: (BottomNavigationBarType value) => |
|||
{ |
|||
this.setState(() => { this._type = value; }); |
|||
}, |
|||
itemBuilder: (BuildContext subContext) => new List<PopupMenuEntry<BottomNavigationBarType>> |
|||
{ |
|||
new PopupMenuItem<BottomNavigationBarType>( |
|||
value: BottomNavigationBarType.fix, |
|||
child: new Text("Fixed") |
|||
), |
|||
new PopupMenuItem<BottomNavigationBarType>( |
|||
value: BottomNavigationBarType.shifting, |
|||
child: new Text("Shifting") |
|||
) |
|||
} |
|||
) |
|||
} |
|||
), |
|||
body: new Center( |
|||
child: this._buildTransitionsStack() |
|||
), |
|||
bottomNavigationBar: botNavBar |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0141eef318dd42e6acc4f3400430dcc8 |
|||
timeCreated: 1612419869 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
public static class ButtonsDemoUtils |
|||
{ |
|||
public static readonly string _raisedText = |
|||
"Raised buttons add dimension to mostly flat layouts. They emphasize " + |
|||
"functions on busy or wide spaces."; |
|||
|
|||
public static readonly string _raisedCode = "buttons_raised"; |
|||
|
|||
public static readonly string _flatText = "A flat button displays an ink splash on press " + |
|||
"but does not lift. Use flat buttons on toolbars, in dialogs and " + |
|||
"inline with padding"; |
|||
|
|||
public static readonly string _flatCode = "buttons_flat"; |
|||
|
|||
public static readonly string _outlineText = |
|||
"Outline buttons become opaque and elevate when pressed. They are often " + |
|||
"paired with raised buttons to indicate an alternative, secondary action."; |
|||
|
|||
public static readonly string _outlineCode = "buttons_outline"; |
|||
|
|||
public static readonly string _dropdownText = |
|||
"A dropdown button displays a menu that\"s used to select a value from a " + |
|||
"small set of values. The button displays the current value and a down " + |
|||
"arrow."; |
|||
|
|||
public static readonly string _dropdownCode = "buttons_dropdown"; |
|||
|
|||
public static readonly string _iconText = |
|||
"IconButtons are appropriate for toggle buttons that allow a single choice " + |
|||
"to be selected or deselected, such as adding or removing an item\"s star."; |
|||
|
|||
public static readonly string _iconCode = "buttons_icon"; |
|||
|
|||
public static readonly string _actionText = |
|||
"Floating action buttons are used for a promoted action. They are " + |
|||
"distinguished by a circled icon floating above the UI and can have motion " + |
|||
"behaviors that include morphing, launching, and a transferring anchor " + |
|||
"point."; |
|||
|
|||
public static readonly string _actionCode = "buttons_action"; |
|||
} |
|||
|
|||
class ButtonsDemo : StatefulWidget { |
|||
public static readonly string routeName = "/material/buttons"; |
|||
|
|||
public override State createState() => new _ButtonsDemoState(); |
|||
} |
|||
|
|||
class _ButtonsDemoState : State<ButtonsDemo> { |
|||
ShapeBorder _buttonShape; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ButtonThemeData buttonTheme = ButtonTheme.of(context).copyWith( |
|||
shape: _buttonShape |
|||
); |
|||
|
|||
List<ComponentDemoTabData> demos = new List<ComponentDemoTabData>{ |
|||
new ComponentDemoTabData( |
|||
tabName: "RAISED", |
|||
description: ButtonsDemoUtils._raisedText, |
|||
demoWidget: ButtonTheme.fromButtonThemeData( |
|||
data: buttonTheme, |
|||
child: buildRaisedButton() |
|||
), |
|||
exampleCodeTag: ButtonsDemoUtils._raisedCode, |
|||
documentationUrl: "https://docs.flutter.io/flutter/material/RaisedButton-class.html" |
|||
), |
|||
new ComponentDemoTabData( |
|||
tabName: "FLAT", |
|||
description: ButtonsDemoUtils._flatText, |
|||
demoWidget: ButtonTheme.fromButtonThemeData( |
|||
data: buttonTheme, |
|||
child: buildFlatButton() |
|||
), |
|||
exampleCodeTag: ButtonsDemoUtils._flatCode, |
|||
documentationUrl: "https://docs.flutter.io/flutter/material/FlatButton-class.html" |
|||
), |
|||
new ComponentDemoTabData( |
|||
tabName: "OUTLINE", |
|||
description: ButtonsDemoUtils._outlineText, |
|||
demoWidget: ButtonTheme.fromButtonThemeData( |
|||
data: buttonTheme, |
|||
child: buildOutlineButton() |
|||
), |
|||
exampleCodeTag: ButtonsDemoUtils._outlineCode, |
|||
documentationUrl: "https://docs.flutter.io/flutter/material/OutlineButton-class.html" |
|||
), |
|||
new ComponentDemoTabData( |
|||
tabName: "DROPDOWN", |
|||
description: ButtonsDemoUtils._dropdownText, |
|||
demoWidget: buildDropdownButton(), |
|||
exampleCodeTag: ButtonsDemoUtils._dropdownCode, |
|||
documentationUrl: "https://docs.flutter.io/flutter/material/DropdownButton-class.html" |
|||
), |
|||
new ComponentDemoTabData( |
|||
tabName: "ICON", |
|||
description: ButtonsDemoUtils._iconText, |
|||
demoWidget: buildIconButton(), |
|||
exampleCodeTag: ButtonsDemoUtils._iconCode, |
|||
documentationUrl: "https://docs.flutter.io/flutter/material/IconButton-class.html" |
|||
), |
|||
new ComponentDemoTabData( |
|||
tabName: "ACTION", |
|||
description: ButtonsDemoUtils._actionText, |
|||
demoWidget: buildActionButton(), |
|||
exampleCodeTag: ButtonsDemoUtils._actionCode, |
|||
documentationUrl: "https://docs.flutter.io/flutter/material/FloatingActionButton-class.html" |
|||
) |
|||
}; |
|||
|
|||
return new TabbedComponentDemoScaffold( |
|||
title: "Buttons", |
|||
demos: demos, |
|||
actions: new List<Widget>{ |
|||
new IconButton( |
|||
icon: new Icon(Icons.sentiment_very_satisfied), |
|||
onPressed: () => { |
|||
setState(() => { |
|||
_buttonShape = _buttonShape == null ? new StadiumBorder() : null; |
|||
}); |
|||
} |
|||
) |
|||
} |
|||
); |
|||
} |
|||
|
|||
Widget buildRaisedButton() { |
|||
return new Align( |
|||
alignment: new Alignment(0.0f, -0.2f), |
|||
child: new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new ButtonBar( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new RaisedButton( |
|||
child: new Text("RAISED BUTTON"), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
} |
|||
), |
|||
new RaisedButton( |
|||
child: new Text("DISABLED"), |
|||
onPressed: null |
|||
) |
|||
} |
|||
), |
|||
new ButtonBar( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
RaisedButton.icon( |
|||
icon: new Icon(Icons.add, size: 18.0f), |
|||
label: new Text("RAISED BUTTON"), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
} |
|||
), |
|||
RaisedButton.icon( |
|||
icon: new Icon(Icons.add, size: 18.0f), |
|||
label: new Text("DISABLED"), |
|||
onPressed: null |
|||
) |
|||
} |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget buildFlatButton() { |
|||
return new Align( |
|||
alignment: new Alignment(0.0f, -0.2f), |
|||
child: new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new ButtonBar( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new FlatButton( |
|||
child: new Text("FLAT BUTTON"), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
} |
|||
), |
|||
new FlatButton( |
|||
child: new Text("DISABLED"), |
|||
onPressed: null |
|||
) |
|||
} |
|||
), |
|||
new ButtonBar( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
FlatButton.icon( |
|||
icon: new Icon(Icons.add_circle_outline, size: 18.0f), |
|||
label: new Text("FLAT BUTTON"), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
} |
|||
), |
|||
FlatButton.icon( |
|||
icon: new Icon(Icons.add_circle_outline, size: 18.0f), |
|||
label: new Text("DISABLED"), |
|||
onPressed: null |
|||
) |
|||
} |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget buildOutlineButton() { |
|||
return new Align( |
|||
alignment: new Alignment(0.0f, -0.2f), |
|||
child: new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new ButtonBar( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new OutlineButton( |
|||
child: new Text("OUTLINE BUTTON"), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
} |
|||
), |
|||
new OutlineButton( |
|||
child: new Text("DISABLED"), |
|||
onPressed: null |
|||
) |
|||
} |
|||
), |
|||
new ButtonBar( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
OutlineButton.icon( |
|||
icon: new Icon(Icons.add, size: 18.0f), |
|||
label: new Text("OUTLINE BUTTON"), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
} |
|||
), |
|||
OutlineButton.icon( |
|||
icon: new Icon(Icons.add, size: 18.0f), |
|||
label: new Text("DISABLED"), |
|||
onPressed: null |
|||
) |
|||
} |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
// https://en.wikipedia.org/wiki/Free_Four
|
|||
string dropdown1Value = "Free"; |
|||
string dropdown2Value = ""; |
|||
string dropdown3Value = "Four"; |
|||
|
|||
Widget buildDropdownButton() { |
|||
return new Padding( |
|||
padding: EdgeInsets.all(24.0f), |
|||
child: new Column( |
|||
mainAxisAlignment: MainAxisAlignment.start, |
|||
children: new List<Widget>{ |
|||
new ListTile( |
|||
title: new Text("Simple dropdown:"), |
|||
trailing: new DropdownButton<string>( |
|||
value: dropdown1Value, |
|||
onChanged: (string newValue) => { |
|||
setState(() => { |
|||
dropdown1Value = newValue; |
|||
}); |
|||
}, |
|||
items: new List<string>{"One", "Two", "Free", "Four"}.Select<string, DropdownMenuItem<string>>((string value) => { |
|||
return new DropdownMenuItem<string>( |
|||
value: value, |
|||
child: new Text(value) |
|||
); |
|||
}).ToList() |
|||
) |
|||
), |
|||
new SizedBox( |
|||
height: 24.0f |
|||
), |
|||
new ListTile( |
|||
title: new Text("Dropdown with a hint:"), |
|||
trailing: new DropdownButton<string>( |
|||
value: dropdown2Value, |
|||
hint: new Text("Choose"), |
|||
onChanged: (string newValue) => { |
|||
setState(() => { |
|||
dropdown2Value = newValue; |
|||
}); |
|||
}, |
|||
items: new List<string>{"One", "Two", "Free", "Four"}.Select<string, DropdownMenuItem<string>>((string value) => { |
|||
return new DropdownMenuItem<string>( |
|||
value: value, |
|||
child: new Text(value) |
|||
); |
|||
}).ToList() |
|||
) |
|||
), |
|||
new SizedBox( |
|||
height: 24.0f |
|||
), |
|||
new ListTile( |
|||
title: new Text("Scrollable dropdown:"), |
|||
trailing: new DropdownButton<string>( |
|||
value: dropdown3Value, |
|||
onChanged: (string newValue) => { |
|||
setState(() => { |
|||
dropdown3Value = newValue; |
|||
}); |
|||
}, |
|||
items: new List<string>{ |
|||
"One", "Two", "Free", "Four", "Can", "I", "Have", "A", "Little", |
|||
"Bit", "More", "Five", "Six", "Seven", "Eight", "Nine", "Ten", |
|||
} |
|||
.Select<string, DropdownMenuItem<string>>((string value) => { |
|||
return new DropdownMenuItem<string>( |
|||
value: value, |
|||
child: new Text(value) |
|||
); |
|||
}) |
|||
.ToList() |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
bool iconButtonToggle = false; |
|||
|
|||
Widget buildIconButton() { |
|||
return new Align( |
|||
alignment: new Alignment(0.0f, -0.2f), |
|||
child: new Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: new List<Widget>{ |
|||
new IconButton( |
|||
icon: new Icon( |
|||
Icons.thumb_up |
|||
), |
|||
onPressed: () =>{ |
|||
setState(() => iconButtonToggle = !iconButtonToggle); |
|||
}, |
|||
color: iconButtonToggle ? Theme.of(context).primaryColor : null |
|||
), |
|||
new IconButton( |
|||
icon: new Icon( |
|||
Icons.thumb_up |
|||
), |
|||
onPressed: null |
|||
) |
|||
} |
|||
.Select<Widget, Widget>((Widget button) => new SizedBox(width: 64.0f, height: 64.0f, child: button)) |
|||
.ToList() |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget buildActionButton() { |
|||
return new Align( |
|||
alignment: new Alignment(0.0f, -0.2f), |
|||
child: new FloatingActionButton( |
|||
child: new Icon(Icons.add), |
|||
onPressed: () => { |
|||
// Perform some action
|
|||
}, |
|||
tooltip: "floating action button" |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d6d69568df64484b9aaee159d11dffc8 |
|||
timeCreated: 1612421132 |
|
|||
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.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using TextStyle = Unity.UIWidgets.painting.TextStyle; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
public static class CardsDemoUtils |
|||
{ |
|||
public static readonly string _kGalleryAssetsPackage = "flutter_gallery_assets"; |
|||
} |
|||
|
|||
internal enum CardDemoType |
|||
{ |
|||
standard, |
|||
tappable, |
|||
selectable, |
|||
} |
|||
|
|||
internal class TravelDestination |
|||
{ |
|||
public TravelDestination( |
|||
string assetName = null, |
|||
string assetPackage = null, |
|||
string title = null, |
|||
string description = null, |
|||
string city = null, |
|||
string location = null, |
|||
CardDemoType type = CardDemoType.standard |
|||
) |
|||
{ |
|||
D.assert(assetName != null); |
|||
D.assert(assetPackage != null); |
|||
D.assert(title != null); |
|||
D.assert(description != null); |
|||
D.assert(city != null); |
|||
D.assert(location != null); |
|||
} |
|||
|
|||
public readonly string assetName; |
|||
public readonly string assetPackage; |
|||
public readonly string title; |
|||
public readonly string description; |
|||
public readonly string city; |
|||
public readonly string location; |
|||
public readonly CardDemoType type; |
|||
|
|||
public static readonly List<TravelDestination> destinations = new List<TravelDestination> |
|||
{ |
|||
new TravelDestination( |
|||
assetName: "places/india_thanjavur_market.png", |
|||
assetPackage: CardsDemoUtils._kGalleryAssetsPackage, |
|||
title: "Top 10 Cities to Visit in Tamil Nadu", |
|||
description: "Number 10", |
|||
city: "Thanjavur", |
|||
location: "Thanjavur, Tamil Nadu" |
|||
), |
|||
new TravelDestination( |
|||
assetName: "places/india_chettinad_silk_maker.png", |
|||
assetPackage: CardsDemoUtils._kGalleryAssetsPackage, |
|||
title: "Artisans of Southern India", |
|||
description: "Silk Spinners", |
|||
city: "Chettinad", |
|||
location: "Sivaganga, Tamil Nadu", |
|||
type: CardDemoType.tappable |
|||
), |
|||
new TravelDestination( |
|||
assetName: "places/india_tanjore_thanjavur_temple.png", |
|||
assetPackage: CardsDemoUtils._kGalleryAssetsPackage, |
|||
title: "Brihadisvara Temple", |
|||
description: "Temples", |
|||
city: "Thanjavur", |
|||
location: "Thanjavur, Tamil Nadu", |
|||
type: CardDemoType.selectable |
|||
), |
|||
}; |
|||
} |
|||
|
|||
internal class TravelDestinationItem : StatelessWidget |
|||
{ |
|||
public TravelDestinationItem(Key key = null, TravelDestination destination = null, ShapeBorder shape = null) |
|||
: base(key: key) |
|||
{ |
|||
D.assert(destination != null); |
|||
this.destination = destination; |
|||
this.shape = shape; |
|||
} |
|||
|
|||
// This height will allow for all the Card's content to fit comfortably within the card.
|
|||
private const float height = 338.0f; |
|||
public readonly TravelDestination destination; |
|||
public readonly ShapeBorder shape; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Padding( |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
new SectionTitle(title: "Normal"), |
|||
new SizedBox( |
|||
height: height, |
|||
child: new Card( |
|||
// This ensures that the Card's children are clipped correctly.
|
|||
clipBehavior: Clip.antiAlias, |
|||
shape: this.shape, |
|||
child: new TravelDestinationContent(destination: this.destination) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class TappableTravelDestinationItem : StatelessWidget |
|||
{ |
|||
public TappableTravelDestinationItem(Key key = null, TravelDestination destination = null, |
|||
ShapeBorder shape = null) |
|||
: base(key: key) |
|||
{ |
|||
D.assert(destination != null); |
|||
this.destination = destination; |
|||
this.shape = shape; |
|||
} |
|||
|
|||
// This height will allow for all the Card's content to fit comfortably within the card.
|
|||
private const float height = 298.0f; |
|||
public readonly TravelDestination destination; |
|||
public readonly ShapeBorder shape; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Padding( |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
new SectionTitle(title: "Tappable"), |
|||
new SizedBox( |
|||
height: height, |
|||
child: new Card( |
|||
// This ensures that the Card's children (including the ink splash) are clipped correctly.
|
|||
clipBehavior: Clip.antiAlias, |
|||
shape: this.shape, |
|||
child: new InkWell( |
|||
onTap: () => { Debug.Log("Card was tapped"); }, |
|||
// Generally, material cards use onSurface with 12% opacity for the pressed state.
|
|||
splashColor: Theme.of(context).colorScheme.onSurface.withOpacity(0.12f), |
|||
// Generally, material cards do not have a highlight overlay.
|
|||
highlightColor: Colors.transparent, |
|||
child: new TravelDestinationContent(destination: this.destination) |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class SelectableTravelDestinationItem : StatefulWidget |
|||
{ |
|||
public SelectableTravelDestinationItem(Key key = null, TravelDestination destination = null, |
|||
ShapeBorder shape = null) |
|||
: base(key: key) |
|||
{ |
|||
D.assert(destination != null); |
|||
this.destination = destination; |
|||
this.shape = shape; |
|||
} |
|||
|
|||
public readonly TravelDestination destination; |
|||
public readonly ShapeBorder shape; |
|||
|
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _SelectableTravelDestinationItemState(); |
|||
} |
|||
} |
|||
|
|||
internal class _SelectableTravelDestinationItemState : State<SelectableTravelDestinationItem> |
|||
{ |
|||
// This height will allow for all the Card's content to fit comfortably within the card.
|
|||
private const float height = 298.0f; |
|||
private bool _isSelected = false; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ColorScheme colorScheme = Theme.of(context).colorScheme; |
|||
|
|||
return new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Padding( |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Column( |
|||
children: new List<Widget> |
|||
{ |
|||
new SectionTitle(title: "Selectable (long press)"), |
|||
new SizedBox( |
|||
height: height, |
|||
child: new Card( |
|||
// This ensures that the Card's children (including the ink splash) are clipped correctly.
|
|||
clipBehavior: Clip.antiAlias, |
|||
shape: this.widget.shape, |
|||
child: new InkWell( |
|||
onLongPress: () => |
|||
{ |
|||
Debug.Log("Selectable card state changed"); |
|||
this.setState(() => { this._isSelected = !this._isSelected; }); |
|||
}, |
|||
// Generally, material cards use onSurface with 12% opacity for the pressed state.
|
|||
splashColor: colorScheme.onSurface.withOpacity(0.12f), |
|||
// Generally, material cards do not have a highlight overlay.
|
|||
highlightColor: Colors.transparent, |
|||
child: new Stack( |
|||
children: new List<Widget> |
|||
{ |
|||
new Container( |
|||
color: this._isSelected |
|||
// Generally, material cards use primary with 8% opacity for the selected state.
|
|||
// See: https://material.io/design/interaction/states.html#anatomy
|
|||
? colorScheme.primary.withOpacity(0.08f) |
|||
: Colors.transparent |
|||
), |
|||
new TravelDestinationContent(destination: this.widget.destination), |
|||
new Align( |
|||
alignment: Alignment.topRight, |
|||
child: new Padding( |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Icon( |
|||
Icons.check_circle, |
|||
color: this._isSelected |
|||
? colorScheme.primary |
|||
: Colors.transparent |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class SectionTitle : StatelessWidget |
|||
{ |
|||
public SectionTitle( |
|||
Key key = null, |
|||
string title = null |
|||
) : base(key: key) |
|||
{ |
|||
this.title = title; |
|||
} |
|||
|
|||
public readonly string title; |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Padding( |
|||
padding: EdgeInsets.fromLTRB(4.0f, 4.0f, 4.0f, 12.0f), |
|||
child: new Align( |
|||
alignment: Alignment.centerLeft, |
|||
child: new Text(this.title, style: Theme.of(context).textTheme.subtitle1) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class TravelDestinationContent : StatelessWidget |
|||
{ |
|||
public TravelDestinationContent(Key key = null, TravelDestination destination = null) |
|||
: base(key: key) |
|||
{ |
|||
D.assert(destination != null); |
|||
this.destination = destination; |
|||
} |
|||
|
|||
public readonly TravelDestination destination; |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
ThemeData theme = Theme.of(context); |
|||
TextStyle titleStyle = theme.textTheme.headline5.copyWith(color: Colors.white); |
|||
TextStyle descriptionStyle = theme.textTheme.subtitle1; |
|||
|
|||
var children = new List<Widget> |
|||
{ |
|||
// Photo and title.
|
|||
new SizedBox( |
|||
height: 184.0f, |
|||
child: new Stack( |
|||
children: new List<Widget> |
|||
{ |
|||
Positioned.fill( |
|||
// In order to have the ink splash appear above the image, you
|
|||
// must use Ink.image. This allows the image to be painted as part
|
|||
// of the Material and display ink effects above it. Using a
|
|||
// standard Image will obscure the ink splash.
|
|||
child: Ink.image( |
|||
image: new FileImage(this.destination.assetPackage + "/" + |
|||
this.destination.assetName), |
|||
fit: BoxFit.cover, |
|||
child: new Container() |
|||
) |
|||
), |
|||
new Positioned( |
|||
bottom: 16.0f, |
|||
left: 16.0f, |
|||
right: 16.0f, |
|||
child: new FittedBox( |
|||
fit: BoxFit.scaleDown, |
|||
alignment: Alignment.centerLeft, |
|||
child: new Text(this.destination.title, |
|||
style: titleStyle |
|||
) |
|||
) |
|||
) |
|||
} |
|||
) |
|||
), |
|||
// Description and share/explore buttons.
|
|||
new Padding( |
|||
padding: EdgeInsets.fromLTRB(16.0f, 16.0f, 16.0f, 0.0f), |
|||
child: new DefaultTextStyle( |
|||
softWrap: false, |
|||
overflow: TextOverflow.ellipsis, |
|||
style: descriptionStyle, |
|||
child: new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: new List<Widget> |
|||
{ |
|||
// three line description
|
|||
new Padding( |
|||
padding: EdgeInsets.only(bottom: 8.0f), |
|||
child: new Text(this.destination.description, |
|||
style: descriptionStyle.copyWith(color: Colors.black54) |
|||
) |
|||
), |
|||
new Text(this.destination.city), |
|||
new Text(this.destination.location) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
}; |
|||
|
|||
if (this.destination.type == CardDemoType.standard) |
|||
// share, explore buttons
|
|||
children.Add(new ButtonBar( |
|||
alignment: MainAxisAlignment.start, |
|||
children: new List<Widget> |
|||
{ |
|||
new FlatButton( |
|||
child: new Text("SHARE"), |
|||
textColor: Colors.amber.shade500, |
|||
onPressed: () => { Debug.Log("pressed"); } |
|||
), |
|||
new FlatButton( |
|||
child: new Text("EXPLORE"), |
|||
textColor: Colors.amber.shade500, |
|||
onPressed: () => { Debug.Log("pressed"); } |
|||
) |
|||
} |
|||
)); |
|||
|
|||
return new Column( |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: children |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class CardsDemo : StatefulWidget |
|||
{ |
|||
public static readonly string routeName = "/material/cards"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _CardsDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _CardsDemoState : State<CardsDemo> |
|||
{ |
|||
private ShapeBorder _shape; |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Cards"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(CardsDemo.routeName), |
|||
new IconButton( |
|||
icon: new Icon( |
|||
Icons.sentiment_very_satisfied |
|||
), |
|||
onPressed: () => |
|||
{ |
|||
this.setState(() => |
|||
{ |
|||
this._shape = this._shape != null |
|||
? null |
|||
: new RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.only( |
|||
topLeft: Radius.circular(16.0f), |
|||
topRight: Radius.circular(16.0f), |
|||
bottomLeft: Radius.circular(2.0f), |
|||
bottomRight: Radius.circular(2.0f) |
|||
) |
|||
); |
|||
}); |
|||
} |
|||
) |
|||
} |
|||
), |
|||
body: new Scrollbar( |
|||
child: new ListView( |
|||
padding: EdgeInsets.only(top: 8.0f, left: 8.0f, right: 8.0f), |
|||
children: TravelDestination.destinations.Select<TravelDestination, Widget>( |
|||
(TravelDestination destination) => |
|||
{ |
|||
Widget child = null; |
|||
switch (destination.type) |
|||
{ |
|||
case CardDemoType.standard: |
|||
child = new TravelDestinationItem(destination: destination, shape: this._shape); |
|||
break; |
|||
case CardDemoType.tappable: |
|||
child = new TappableTravelDestinationItem(destination: destination, |
|||
shape: this._shape); |
|||
break; |
|||
case CardDemoType.selectable: |
|||
child = new SelectableTravelDestinationItem(destination: destination, |
|||
shape: this._shape); |
|||
break; |
|||
} |
|||
|
|||
return new Container( |
|||
margin: EdgeInsets.only(bottom: 8.0f), |
|||
child: child |
|||
); |
|||
}).ToList() |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e5eef436049c4b8ba60592f26681bb56 |
|||
timeCreated: 1612423408 |
|
|||
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.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
public static class ChipDemoUtils |
|||
{ |
|||
public static void AddRange<T>(this HashSet<T> hashSet, List<T> list) |
|||
{ |
|||
foreach (var item in list) hashSet.Add(item); |
|||
} |
|||
|
|||
public static void AddRange<T>(this HashSet<T> hashSet, HashSet<T> list) |
|||
{ |
|||
foreach (var item in list) hashSet.Add(item); |
|||
} |
|||
|
|||
public static readonly List<string> _defaultMaterials = new List<string> |
|||
{ |
|||
"poker", |
|||
"tortilla", |
|||
"fish and", |
|||
"micro", |
|||
"wood" |
|||
}; |
|||
|
|||
public static readonly List<string> _defaultActions = new List<string> |
|||
{ |
|||
"flake", |
|||
"cut", |
|||
"fragment", |
|||
"splinter", |
|||
"nick", |
|||
"fry", |
|||
"solder", |
|||
"cash in", |
|||
"eat" |
|||
}; |
|||
|
|||
public static readonly Dictionary<string, string> _results = new Dictionary<string, string>() |
|||
{ |
|||
{"flake", "flaking"}, |
|||
{"cut", "cutting"}, |
|||
{"fragment", "fragmenting"}, |
|||
{"splinter", "splintering"}, |
|||
{"nick", "nicking"}, |
|||
{"fry", "frying"}, |
|||
{"solder", "soldering"}, |
|||
{"cash in", "cashing in"}, |
|||
{"eat", "eating"}, |
|||
}; |
|||
|
|||
public static readonly List<string> _defaultTools = new List<string> |
|||
{ |
|||
"hammer", |
|||
"chisel", |
|||
"fryer", |
|||
"fabricator", |
|||
"customer" |
|||
}; |
|||
|
|||
public static readonly Dictionary<string, string> _avatars = new Dictionary<string, string>() |
|||
{ |
|||
{"hammer", "people/square/ali.png"}, |
|||
{"chisel", "people/square/sandra.png"}, |
|||
{"fryer", "people/square/trevor.png"}, |
|||
{"fabricator", "people/square/stella.png"}, |
|||
{"customer", "people/square/peter.png"}, |
|||
}; |
|||
|
|||
public static readonly Dictionary<string, HashSet<string>> _toolActions = |
|||
new Dictionary<string, HashSet<string>> |
|||
{ |
|||
{"hammer", new HashSet<string> {"flake", "fragment", "splinter"}}, |
|||
{"chisel", new HashSet<string> {"flake", "nick", "splinter"}}, |
|||
{"fryer", new HashSet<string> {"fry"}}, |
|||
{"fabricator", new HashSet<string> {"solder"}}, |
|||
{"customer", new HashSet<string> {"cash in", "eat"}}, |
|||
}; |
|||
|
|||
public static readonly Dictionary<string, HashSet<string>> _materialActions = |
|||
new Dictionary<string, HashSet<string>> |
|||
{ |
|||
{"poker", new HashSet<string> {"cash in"}}, |
|||
{"tortilla", new HashSet<string> {"fry", "eat"}}, |
|||
{"fish and", new HashSet<string> {"fry", "eat"}}, |
|||
{"micro", new HashSet<string> {"solder", "fragment"}}, |
|||
{"wood", new HashSet<string> {"flake", "cut", "splinter", "nick"}}, |
|||
}; |
|||
} |
|||
|
|||
internal class _ChipsTile : StatelessWidget |
|||
{ |
|||
public _ChipsTile( |
|||
Key key = null, |
|||
string label = null, |
|||
List<Widget> children = null |
|||
) : base(key: key) |
|||
{ |
|||
this.label = label; |
|||
this.children = children; |
|||
} |
|||
|
|||
public readonly string label; |
|||
public readonly List<Widget> children; |
|||
|
|||
// Wraps a list of chips into a ListTile for display as a section in the demo.
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
var cardChildren = new List<Widget> |
|||
{ |
|||
new Container( |
|||
padding: EdgeInsets.only(top: 16.0f, bottom: 4.0f), |
|||
alignment: Alignment.center, |
|||
child: new Text(this.label, textAlign: TextAlign.start)) |
|||
}; |
|||
|
|||
if (this.children != null && this.children.isNotEmpty()) |
|||
cardChildren.Add(new Wrap( |
|||
children: this.children.Select<Widget, Widget>((Widget chip) => |
|||
{ |
|||
return new Padding(padding: EdgeInsets.all(2.0f), |
|||
child: chip); |
|||
}).ToList() |
|||
)); |
|||
else |
|||
cardChildren.Add(new Container( |
|||
alignment: Alignment.center, |
|||
constraints: new BoxConstraints(minWidth: 48.0f, minHeight: 48.0f), |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Text("None", |
|||
style: Theme.of(context).textTheme.caption.copyWith(fontStyle: FontStyle.italic)) |
|||
)); |
|||
|
|||
|
|||
return new Card( |
|||
child: new Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: cardChildren |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
internal class ChipDemo : StatefulWidget |
|||
{ |
|||
public static readonly string routeName = "/material/chip"; |
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _ChipDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _ChipDemoState : State<ChipDemo> |
|||
{ |
|||
public _ChipDemoState() |
|||
{ |
|||
this._reset(); |
|||
} |
|||
|
|||
private readonly HashSet<string> _materials = new HashSet<string>(); |
|||
private string _selectedMaterial = ""; |
|||
private string _selectedAction = ""; |
|||
private readonly HashSet<string> _tools = new HashSet<string>(); |
|||
private readonly HashSet<string> _selectedTools = new HashSet<string>(); |
|||
private readonly HashSet<string> _actions = new HashSet<string>(); |
|||
private bool _showShapeBorder = false; |
|||
|
|||
// Initialize members with the default data.
|
|||
private void _reset() |
|||
{ |
|||
this._materials.Clear(); |
|||
this._materials.AddRange(ChipDemoUtils._defaultMaterials); |
|||
this._actions.Clear(); |
|||
this._actions.AddRange(ChipDemoUtils._defaultActions); |
|||
this._tools.Clear(); |
|||
this._tools.AddRange(ChipDemoUtils._defaultTools); |
|||
this._selectedMaterial = ""; |
|||
this._selectedAction = ""; |
|||
this._selectedTools.Clear(); |
|||
} |
|||
|
|||
private void _removeMaterial(string name) |
|||
{ |
|||
this._materials.Remove(name); |
|||
if (this._selectedMaterial == name) this._selectedMaterial = ""; |
|||
} |
|||
|
|||
private void _removeTool(string name) |
|||
{ |
|||
this._tools.Remove(name); |
|||
this._selectedTools.Remove(name); |
|||
} |
|||
|
|||
private string _capitalize(string name) |
|||
{ |
|||
D.assert(name != null && name.isNotEmpty()); |
|||
return name.Substring(0, 1).ToUpper() + name.Substring(1); |
|||
} |
|||
|
|||
// This converts a String to a unique color, based on the hash value of the
|
|||
// String object. It takes the bottom 16 bits of the hash, and uses that to
|
|||
// pick a hue for an HSV color, and then creates the color (with a preset
|
|||
// saturation and value). This means that any unique strings will also have
|
|||
// unique colors, but they'll all be readable, since they have the same
|
|||
// saturation and value.
|
|||
private Color _nameToColor(string name) |
|||
{ |
|||
D.assert(name.Length > 1); |
|||
int hash = name.GetHashCode() & 0xffff; |
|||
float hue = (360.0f * hash / (1 << 15)) % 360.0f; |
|||
return HSVColor.fromAHSV(1.0f, hue, 0.4f, 0.90f).toColor(); |
|||
} |
|||
|
|||
private FileImage _nameToAvatar(string name) |
|||
{ |
|||
D.assert(ChipDemoUtils._avatars.ContainsKey(name)); |
|||
return new FileImage( |
|||
ChipDemoUtils._avatars[name] |
|||
); |
|||
} |
|||
|
|||
private string _createResult() |
|||
{ |
|||
if (this._selectedAction.isEmpty()) return ""; |
|||
return this._capitalize(ChipDemoUtils._results[this._selectedAction]) + "!"; |
|||
} |
|||
|
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
List<Widget> chips = this._materials.Select<string, Widget>((string name) => |
|||
{ |
|||
return new Chip( |
|||
key: new ValueKey<string>(name), |
|||
backgroundColor: this._nameToColor(name), |
|||
label: new Text(this._capitalize(name)), |
|||
onDeleted: () => { this.setState(() => { this._removeMaterial(name); }); } |
|||
); |
|||
}).ToList(); |
|||
|
|||
List<Widget> inputChips = this._tools.Select<string, Widget>((string name) => |
|||
{ |
|||
return new InputChip( |
|||
key: new ValueKey<string>(name), |
|||
avatar: new CircleAvatar( |
|||
backgroundImage: this._nameToAvatar(name) |
|||
), |
|||
label: new Text(this._capitalize(name)), |
|||
onDeleted: () => { this.setState(() => { this._removeTool(name); }); }); |
|||
}).ToList(); |
|||
|
|||
List<Widget> choiceChips = this._materials.Select<string, Widget>((string name) => |
|||
{ |
|||
return new ChoiceChip( |
|||
key: new ValueKey<string>(name), |
|||
backgroundColor: this._nameToColor(name), |
|||
label: new Text(this._capitalize(name)), |
|||
selected: this._selectedMaterial == name, |
|||
onSelected: (bool value) => |
|||
{ |
|||
this.setState(() => { this._selectedMaterial = value ? name : ""; }); |
|||
} |
|||
); |
|||
}).ToList(); |
|||
|
|||
List<Widget> filterChips = ChipDemoUtils._defaultTools.Select<string, Widget>((string name) => |
|||
{ |
|||
return new FilterChip( |
|||
key: new ValueKey<string>(name), |
|||
label: new Text(this._capitalize(name)), |
|||
selected: this._tools.Contains(name) && this._selectedTools.Contains(name), |
|||
onSelected: !this._tools.Contains(name) |
|||
? (ValueChanged<bool>) null |
|||
: (bool value) => |
|||
{ |
|||
this.setState(() => |
|||
{ |
|||
if (!value) |
|||
this._selectedTools.Remove(name); |
|||
else |
|||
this._selectedTools.Add(name); |
|||
}); |
|||
} |
|||
); |
|||
}).ToList(); |
|||
|
|||
List<string> allowedActions = new List<string>(); |
|||
if (this._selectedMaterial != null && this._selectedMaterial.isNotEmpty()) |
|||
{ |
|||
foreach (string tool in this._selectedTools) allowedActions.AddRange(ChipDemoUtils._toolActions[tool]); |
|||
allowedActions = allowedActions.Intersect(ChipDemoUtils._materialActions[this._selectedMaterial]) |
|||
.ToList(); |
|||
} |
|||
|
|||
List<Widget> actionChips = allowedActions.Select<string, Widget>((string name) => |
|||
{ |
|||
return new ActionChip( |
|||
label: new Text(this._capitalize(name)), |
|||
onPressed: () => { this.setState(() => { this._selectedAction = name; }); } |
|||
); |
|||
}).ToList(); |
|||
|
|||
ThemeData theme = Theme.of(context); |
|||
List<Widget> tiles = new List<Widget> |
|||
{ |
|||
new SizedBox(height: 8.0f, width: 0.0f), |
|||
new _ChipsTile(label: "Available Materials (Chip)", children: chips), |
|||
new _ChipsTile(label: "Available Tools (InputChip)", children: inputChips), |
|||
new _ChipsTile(label: "Choose a Material (ChoiceChip)", children: choiceChips), |
|||
new _ChipsTile(label: "Choose Tools (FilterChip)", children: filterChips), |
|||
new _ChipsTile(label: "Perform Allowed Action (ActionChip)", children: actionChips), |
|||
new Divider(), |
|||
new Padding( |
|||
padding: EdgeInsets.all(8.0f), |
|||
child: new Center( |
|||
child: new Text(this._createResult(), |
|||
style: theme.textTheme.headline6 |
|||
) |
|||
) |
|||
) |
|||
}; |
|||
|
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Chips"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(ChipDemo.routeName), |
|||
new IconButton( |
|||
onPressed: () => |
|||
{ |
|||
this.setState(() => { this._showShapeBorder = !this._showShapeBorder; }); |
|||
}, |
|||
icon: new Icon(Icons.vignette) |
|||
) |
|||
} |
|||
), |
|||
body: new ChipTheme( |
|||
data: this._showShapeBorder |
|||
? theme.chipTheme.copyWith( |
|||
shape: new BeveledRectangleBorder( |
|||
side: new BorderSide(width: 0.66f, style: BorderStyle.solid, color: Colors.grey), |
|||
borderRadius: BorderRadius.circular(10.0f) |
|||
)) |
|||
: theme.chipTheme, |
|||
child: new Scrollbar(child: new ListView(children: tiles)) |
|||
), |
|||
floatingActionButton: new FloatingActionButton( |
|||
onPressed: () => this.setState(this._reset), |
|||
child: new Icon(Icons.refresh) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: f9c596e7b509434aab8b7b7830e287ab |
|||
timeCreated: 1612425059 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UIWidgetsGallery.gallery; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.material; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.demo.material |
|||
{ |
|||
internal delegate T getDessertField<T>(Dessert d); |
|||
|
|||
internal class Dessert |
|||
{ |
|||
public Dessert(string name, int calories, float fat, int carbs, float protein, int sodium, int calcium, |
|||
int iron) |
|||
{ |
|||
this.name = name; |
|||
this.calories = calories; |
|||
this.fat = fat; |
|||
this.carbs = carbs; |
|||
this.protein = protein; |
|||
this.sodium = sodium; |
|||
this.calcium = calcium; |
|||
this.iron = iron; |
|||
} |
|||
|
|||
public readonly string name; |
|||
public readonly int calories; |
|||
public readonly float fat; |
|||
public readonly int carbs; |
|||
public readonly float protein; |
|||
public readonly int sodium; |
|||
public readonly int calcium; |
|||
public readonly int iron; |
|||
|
|||
internal bool selected = false; |
|||
} |
|||
|
|||
internal class DessertDataSource : DataTableSource |
|||
{ |
|||
public readonly List<Dessert> _desserts = new List<Dessert> |
|||
{ |
|||
new Dessert("Frozen yogurt", 159, 6.0f, 24, 4.0f, 87, 14, 1), |
|||
new Dessert("Ice cream sandwich", 237, 9.0f, 37, 4.3f, 129, 8, 1), |
|||
new Dessert("Eclair", 262, 16.0f, 24, 6.0f, 337, 6, 7), |
|||
new Dessert("Cupcake", 305, 3.7f, 67, 4.3f, 413, 3, 8), |
|||
new Dessert("Gingerbread", 356, 16.0f, 49, 3.9f, 327, 7, 16), |
|||
new Dessert("Jelly bean", 375, 0.0f, 94, 0.0f, 50, 0, 0), |
|||
new Dessert("Lollipop", 392, 0.2f, 98, 0.0f, 38, 0, 2), |
|||
new Dessert("Honeycomb", 408, 3.2f, 87, 6.5f, 562, 0, 45), |
|||
new Dessert("Donut", 452, 25.0f, 51, 4.9f, 326, 2, 22), |
|||
new Dessert("KitKat", 518, 26.0f, 65, 7.0f, 54, 12, 6), |
|||
|
|||
new Dessert("Frozen yogurt with sugar", 168, 6.0f, 26, 4.0f, 87, 14, 1), |
|||
new Dessert("Ice cream sandwich with sugar", 246, 9.0f, 39, 4.3f, 129, 8, 1), |
|||
new Dessert("Eclair with sugar", 271, 16.0f, 26, 6.0f, 337, 6, 7), |
|||
new Dessert("Cupcake with sugar", 314, 3.7f, 69, 4.3f, 413, 3, 8), |
|||
new Dessert("Gingerbread with sugar", 345, 16.0f, 51, 3.9f, 327, 7, 16), |
|||
new Dessert("Jelly bean with sugar", 364, 0.0f, 96, 0.0f, 50, 0, 0), |
|||
new Dessert("Lollipop with sugar", 401, 0.2f, 100, 0.0f, 38, 0, 2), |
|||
new Dessert("Honeycomb with sugar", 417, 3.2f, 89, 6.5f, 562, 0, 45), |
|||
new Dessert("Donut with sugar", 461, 25.0f, 53, 4.9f, 326, 2, 22), |
|||
new Dessert("KitKat with sugar", 527, 26.0f, 67, 7.0f, 54, 12, 6), |
|||
|
|||
new Dessert("Frozen yogurt with honey", 223, 6.0f, 36, 4.0f, 87, 14, 1), |
|||
new Dessert("Ice cream sandwich with honey", 301, 9.0f, 49, 4.3f, 129, 8, 1), |
|||
new Dessert("Eclair with honey", 326, 16.0f, 36, 6.0f, 337, 6, 7), |
|||
new Dessert("Cupcake with honey", 369, 3.7f, 79, 4.3f, 413, 3, 8), |
|||
new Dessert("Gingerbread with honey", 420, 16.0f, 61, 3.9f, 327, 7, 16), |
|||
new Dessert("Jelly bean with honey", 439, 0.0f, 106, 0.0f, 50, 0, 0), |
|||
new Dessert("Lollipop with honey", 456, 0.2f, 110, 0.0f, 38, 0, 2), |
|||
new Dessert("Honeycomb with honey", 472, 3.2f, 99, 6.5f, 562, 0, 45), |
|||
new Dessert("Donut with honey", 516, 25.0f, 63, 4.9f, 326, 2, 22), |
|||
new Dessert("KitKat with honey", 582, 26.0f, 77, 7.0f, 54, 12, 6), |
|||
|
|||
new Dessert("Frozen yogurt with milk", 262, 8.4f, 36, 12.0f, 194, 44, 1), |
|||
new Dessert("Ice cream sandwich with milk", 339, 11.4f, 49, 12.3f, 236, 38, 1), |
|||
new Dessert("Eclair with milk", 365, 18.4f, 36, 14.0f, 444, 36, 7), |
|||
new Dessert("Cupcake with milk", 408, 6.1f, 79, 12.3f, 520, 33, 8), |
|||
new Dessert("Gingerbread with milk", 459, 18.4f, 61, 11.9f, 434, 37, 16), |
|||
new Dessert("Jelly bean with milk", 478, 2.4f, 106, 8.0f, 157, 30, 0), |
|||
new Dessert("Lollipop with milk", 495, 2.6f, 110, 8.0f, 145, 30, 2), |
|||
new Dessert("Honeycomb with milk", 511, 5.6f, 99, 14.5f, 669, 30, 45), |
|||
new Dessert("Donut with milk", 555, 27.4f, 63, 12.9f, 433, 32, 22), |
|||
new Dessert("KitKat with milk", 621, 28.4f, 77, 15.0f, 161, 42, 6), |
|||
|
|||
new Dessert("Coconut slice and frozen yogurt", 318, 21.0f, 31, 5.5f, 96, 14, 7), |
|||
new Dessert("Coconut slice and ice cream sandwich", 396, 24.0f, 44, 5.8f, 138, 8, 7), |
|||
new Dessert("Coconut slice and eclair", 421, 31.0f, 31, 7.5f, 346, 6, 13), |
|||
new Dessert("Coconut slice and cupcake", 464, 18.7f, 74, 5.8f, 422, 3, 14), |
|||
new Dessert("Coconut slice and gingerbread", 515, 31.0f, 56, 5.4f, 316, 7, 22), |
|||
new Dessert("Coconut slice and jelly bean", 534, 15.0f, 101, 1.5f, 59, 0, 6), |
|||
new Dessert("Coconut slice and lollipop", 551, 15.2f, 105, 1.5f, 47, 0, 8), |
|||
new Dessert("Coconut slice and honeycomb", 567, 18.2f, 94, 8.0f, 571, 0, 51), |
|||
new Dessert("Coconut slice and donut", 611, 40.0f, 58, 6.4f, 335, 2, 28), |
|||
new Dessert("Coconut slice and KitKat", 677, 41.0f, 72, 8.5f, 63, 12, 12), |
|||
}; |
|||
|
|||
internal void _sort<T>(getDessertField<T> getField, bool isAscending) where T : IComparable |
|||
{ |
|||
this._desserts.Sort((Dessert a, Dessert b) => |
|||
{ |
|||
if (!isAscending) |
|||
{ |
|||
Dessert c = a; |
|||
a = b; |
|||
b = c; |
|||
} |
|||
|
|||
T aValue = getField(a); |
|||
T bValue = getField(b); |
|||
return aValue.CompareTo(bValue); |
|||
}); |
|||
|
|||
this.notifyListeners(); |
|||
} |
|||
|
|||
private int _selectedCount = 0; |
|||
|
|||
public override DataRow getRow(int index) |
|||
{ |
|||
D.assert(index >= 0); |
|||
if (index >= this._desserts.Count) |
|||
return null; |
|||
|
|||
Dessert dessert = this._desserts[index]; |
|||
return DataRow.byIndex( |
|||
index: index, |
|||
selected: dessert.selected, |
|||
onSelectChanged: (bool value) => |
|||
{ |
|||
if (dessert.selected != value) |
|||
{ |
|||
this._selectedCount += value ? 1 : -1; |
|||
D.assert(this._selectedCount >= 0); |
|||
dessert.selected = value; |
|||
this.notifyListeners(); |
|||
} |
|||
}, |
|||
cells: new List<DataCell> |
|||
{ |
|||
new DataCell(new Text(dessert.name)), |
|||
new DataCell(new Text($"{dessert.calories}")), |
|||
new DataCell(new Text($"{dessert.fat:F1}")), |
|||
new DataCell(new Text($"{dessert.carbs}")), |
|||
new DataCell(new Text($"{dessert.protein:F1}")), |
|||
new DataCell(new Text($"{dessert.sodium}")), |
|||
new DataCell(new Text($"{dessert.calcium}%")), |
|||
new DataCell(new Text($"{dessert.iron}%")), |
|||
} |
|||
); |
|||
} |
|||
|
|||
private new int rowCount => this._desserts.Count; |
|||
|
|||
private new bool isRowCountApproximate => false; |
|||
|
|||
private new int selectedRowCount => this._selectedCount; |
|||
|
|||
public void _selectAll(bool isChecked) |
|||
{ |
|||
foreach (Dessert dessert in this._desserts) |
|||
dessert.selected = isChecked; |
|||
this._selectedCount = isChecked ? this._desserts.Count : 0; |
|||
this.notifyListeners(); |
|||
} |
|||
} |
|||
|
|||
internal class DataTableDemo : StatefulWidget |
|||
{ |
|||
public const string routeName = "/material/data-table"; |
|||
|
|||
|
|||
public override State createState() |
|||
{ |
|||
return new _DataTableDemoState(); |
|||
} |
|||
} |
|||
|
|||
internal class _DataTableDemoState : State<DataTableDemo> |
|||
{ |
|||
private int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage; |
|||
private int _sortColumnIndex; |
|||
private bool _sortAscending = true; |
|||
private DessertDataSource _dessertsDataSource = new DessertDataSource(); |
|||
|
|||
private void _sort<T>(getDessertField<T> getField, int columnIndex, bool ascending) where T : IComparable |
|||
{ |
|||
this._dessertsDataSource._sort<T>(getField, ascending); |
|||
this.setState(() => |
|||
{ |
|||
this._sortColumnIndex = columnIndex; |
|||
this._sortAscending = ascending; |
|||
}); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) |
|||
{ |
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
title: new Text("Data tables"), |
|||
actions: new List<Widget> |
|||
{ |
|||
new MaterialDemoDocumentationButton(DataTableDemo.routeName) |
|||
} |
|||
), |
|||
body: new Scrollbar( |
|||
child: new ListView( |
|||
padding: EdgeInsets.all(20.0f), |
|||
children: new List<Widget> |
|||
{ |
|||
new PaginatedDataTable( |
|||
header: new Text("Nutrition"), |
|||
rowsPerPage: this._rowsPerPage, |
|||
onRowsPerPageChanged: (int value) => |
|||
{ |
|||
this.setState(() => { this._rowsPerPage = value; }); |
|||
}, |
|||
sortColumnIndex: this._sortColumnIndex, |
|||
sortAscending: this._sortAscending, |
|||
onSelectAll: this._dessertsDataSource._selectAll, |
|||
columns: new List<DataColumn> |
|||
{ |
|||
new DataColumn( |
|||
label: new Text("Dessert (100g serving)"), |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<string>((Dessert d) => d.name, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Calories"), |
|||
tooltip: "The total amount of food energy in the given serving size.", |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<int>((Dessert d) => d.calories, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Fat (g)"), |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<float>((Dessert d) => d.fat, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Carbs (g)"), |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<int>((Dessert d) => d.carbs, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Protein (g)"), |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<float>((Dessert d) => d.protein, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Sodium (mg)"), |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<int>((Dessert d) => d.sodium, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Calcium (%)"), |
|||
tooltip: |
|||
"The amount of calcium as a percentage of the recommended daily amount.", |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<int>((Dessert d) => d.calcium, columnIndex, ascending) |
|||
), |
|||
new DataColumn( |
|||
label: new Text("Iron (%)"), |
|||
numeric: true, |
|||
onSort: (int columnIndex, bool ascending) => |
|||
this._sort<int>((Dessert d) => d.iron, columnIndex, ascending) |
|||
) |
|||
}, |
|||
source: this._dessertsDataSource |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3074c923fe324b40ab4ba2c7e57c4132 |
|||
timeCreated: 1612427217 |
撰写
预览
正在加载...
取消
保存
Reference in new issue