Skip to content

Commit 16898f4

Browse files
list view,
title change, nested listing
1 parent 07aa209 commit 16898f4

File tree

3 files changed

+143
-23
lines changed

3 files changed

+143
-23
lines changed

lib/main.dart

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import 'package:flutter_examples/ui/collapsibletoolbar/CollapsibleToolbar.dart';
1111
import 'package:flutter_examples/ui/dragdrop/ExampleDragDrop.dart';
1212
import 'package:flutter_examples/ui/drawer/NavigationDrawer.dart';
1313
import 'package:flutter_examples/ui/hardwarekey/RawKeyboardDemo.dart';
14-
import 'package:flutter_examples/ui/lifecycle/Lifecycle.dart';
1514
import 'package:flutter_examples/ui/local_auth/LocalAuth.dart';
15+
import 'package:flutter_examples/ui/nestedlist/NestedListExample.dart';
1616
import 'package:flutter_examples/ui/progressbutton/ProgressButton.dart';
1717
import 'package:flutter_examples/ui/staggeredanimation/StaggerDemo.dart';
1818
import 'package:flutter_examples/ui/stepper/StepperExample.dart';
@@ -37,8 +37,7 @@ class MyApp extends StatelessWidget {
3737
home: new MyHomePage(title: Strings.appName),
3838
routes: <String, WidgetBuilder>{
3939
Strings.appBarExampleRoute: (BuildContext context) => AppBarExample(),
40-
Strings.tabBarExampleRoute: (BuildContext context) =>
41-
TabBarExample(
40+
Strings.tabBarExampleRoute: (BuildContext context) => TabBarExample(
4241
title: Strings.TabBarTitle,
4342
),
4443
Strings.navigationDrawerExampleRoute: (BuildContext context) =>
@@ -73,7 +72,7 @@ class MyApp extends StatelessWidget {
7372
Strings.aboutListTileExampleRoute: (BuildContext context) =>
7473
AboutListTileExample(title: Strings.aboutListTileExampleTitle),
7574
Strings.lifeCycleStateExampleRoute: (BuildContext context) =>
76-
Lifecycle(title: Strings.lifeCycleStateExampleTitle),
75+
NestedListExample(),
7776
Strings.localAuthExampleRoute: (BuildContext context) => LocalAuth(),
7877
});
7978
}
@@ -148,10 +147,9 @@ class _MyHomePageState extends State<MyHomePage>
148147
_buildExampleItemsWidget(bool status) {
149148
if (status) {
150149
return new ListView.builder(
151-
itemBuilder: (BuildContext context, int index) =>
152-
new ExampleNameItem(
153-
exampleNames: names[index],
154-
),
150+
itemBuilder: (BuildContext context, int index) => new ExampleNameItem(
151+
exampleNames: names[index],
152+
),
155153
itemCount: names.length,
156154
);
157155
} else {
@@ -160,10 +158,9 @@ class _MyHomePageState extends State<MyHomePage>
160158
crossAxisCount: 2,
161159
childAspectRatio: 3.0,
162160
),
163-
itemBuilder: (BuildContext context, int index) =>
164-
new ExampleNameItem(
165-
exampleNames: names[index],
166-
),
161+
itemBuilder: (BuildContext context, int index) => new ExampleNameItem(
162+
exampleNames: names[index],
163+
),
167164
itemCount: names.length,
168165
);
169166
}

lib/ui/local_auth/LocalAuth.dart

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@ class LocalAuth extends StatefulWidget {
1212
class _LocalAuthState extends State<LocalAuth> {
1313
String _authorized = 'Not Authorized';
1414

15+
Future<Null> _authenticateWithBiometrics() async {
16+
final LocalAuthentication auth = new LocalAuthentication();
17+
bool authenticated = false;
18+
try {
19+
authenticated = await auth.authenticateWithBiometrics(
20+
localizedReason: 'Scan your fingerprint to authenticate',
21+
useErrorDialogs: true,
22+
stickyAuth: false);
23+
} on PlatformException catch (e) {
24+
print(e);
25+
}
26+
if (!mounted) return;
27+
28+
setState(() {
29+
_authorized = authenticated ? 'Authorized' : 'Not Authorized';
30+
});
31+
}
32+
1533
Future<Null> _authenticate() async {
1634
final LocalAuthentication auth = new LocalAuthentication();
1735
bool authenticated = false;
@@ -35,19 +53,23 @@ class _LocalAuthState extends State<LocalAuth> {
3553
return new MaterialApp(
3654
home: new Scaffold(
3755
appBar: new AppBar(
38-
title: const Text('Plugin example app'),
56+
title: const Text('Local authentication'),
3957
),
4058
body: new ConstrainedBox(
41-
constraints: const BoxConstraints.expand(),
42-
child: new Column(
43-
mainAxisAlignment: MainAxisAlignment.spaceAround,
44-
children: <Widget>[
45-
new Text('Current State: $_authorized\n'),
46-
new RaisedButton(
47-
child: const Text('Authenticate'),
48-
onPressed: _authenticate,
49-
)
50-
])),
59+
constraints: const BoxConstraints.expand(),
60+
child: ListView(
61+
children: <Widget>[
62+
new RaisedButton(
63+
child: const Text('Authenticate'),
64+
onPressed: _authenticateWithBiometrics,
65+
),
66+
new RaisedButton(
67+
child: const Text('Authenticate'),
68+
onPressed: _authenticateWithBiometrics,
69+
),
70+
],
71+
),
72+
),
5173
));
5274
}
5375
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import 'package:flutter/material.dart';
2+
3+
// The base class for the different types of items the List can contain
4+
abstract class ListItem {}
5+
6+
// A ListItem that contains data to display a heading
7+
class HeadingItem implements ListItem {
8+
final String heading;
9+
10+
HeadingItem(this.heading);
11+
}
12+
13+
// A ListItem that contains data to display a message
14+
class MessageItem implements ListItem {
15+
final String sender;
16+
final String body;
17+
18+
MessageItem(this.sender, this.body);
19+
}
20+
21+
class NestedListExample extends StatefulWidget {
22+
final items = List<ListItem>.generate(
23+
20,
24+
(i) => HeadingItem("Heading $i"),
25+
);
26+
27+
@override
28+
_NestedListExampleState createState() => _NestedListExampleState();
29+
}
30+
31+
class _NestedListExampleState extends State<NestedListExample>
32+
with SingleTickerProviderStateMixin {
33+
TabController _tabController;
34+
ScrollController _scrollController;
35+
var _globalKey = GlobalKey();
36+
37+
@override
38+
void initState() {
39+
_tabController =
40+
new TabController(length: widget.items.length, vsync: this);
41+
_scrollController = ScrollController();
42+
_tabController.addListener(_handleTabSelection);
43+
super.initState();
44+
}
45+
46+
@override
47+
void dispose() {
48+
_scrollController.dispose();
49+
_tabController.dispose();
50+
super.dispose();
51+
}
52+
53+
void _handleTabSelection() {
54+
setState(() {
55+
var height = _globalKey.currentContext;
56+
final RenderBox box = height.findRenderObject();
57+
_scrollController.animateTo(_tabController.offset,
58+
curve: Curves.ease, duration: Duration(seconds: 2));
59+
});
60+
}
61+
62+
@override
63+
Widget build(BuildContext context) {
64+
return Scaffold(
65+
appBar: AppBar(
66+
title: Text("Nested List"),
67+
bottom: TabBar(
68+
isScrollable: true,
69+
tabs: List<Widget>.generate(
70+
widget.items.length,
71+
(int index) {
72+
return new Tab(
73+
text: "$index",
74+
);
75+
},
76+
),
77+
controller: _tabController,
78+
),
79+
),
80+
body: ListView.builder(
81+
controller: _scrollController,
82+
// Let the ListView know how many items it needs to build
83+
itemCount: widget.items.length,
84+
// Provide a builder function. This is where the magic happens! We'll
85+
// convert each item into a Widget based on the type of item it is.
86+
itemBuilder: (context, index) {
87+
final item = widget.items[index];
88+
if (item is HeadingItem) {
89+
return ListTile(
90+
key: _globalKey,
91+
title: Text(
92+
item.heading,
93+
style: Theme.of(context).textTheme.headline,
94+
),
95+
);
96+
}
97+
},
98+
),
99+
);
100+
}
101+
}

0 commit comments

Comments
 (0)