Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4d9fbe78
Unverified
Commit
4d9fbe78
authored
Oct 31, 2017
by
Michael Goderbauer
Committed by
GitHub
Oct 31, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a custom semantics sample (#12742)
* Add a custom semantics sample * typo * Review comments
parent
722fa869
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
268 additions
and
0 deletions
+268
-0
custom_semantics.dart
examples/catalog/lib/custom_semantics.dart
+152
-0
custom_semantics_test.dart
examples/catalog/test/custom_semantics_test.dart
+116
-0
No files found.
examples/catalog/lib/custom_semantics.dart
0 → 100644
View file @
4d9fbe78
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
/// A [ListTile] containing a dropdown menu that exposes itself as an
/// "Adjustable" to screen readers (e.g. TalkBack on Android and VoiceOver on
/// iOS).
///
/// This allows screen reader users to swipe up/down (on iOS) or use the volume
/// keys (on Android) to switch between the values in the dropdown menu.
/// Depending on what the values in the dropdown menu are this can be a more
/// intuitive way of switching values compared to exposing the content of the
/// drop down menu as a screen overlay from which the user can select.
///
/// Users that do not use a screen reader will just see a regular dropdown menu.
class
AdjustableDropdownListTile
extends
StatelessWidget
{
const
AdjustableDropdownListTile
({
this
.
label
,
this
.
value
,
this
.
items
,
this
.
onChanged
,
});
final
String
label
;
final
String
value
;
final
List
<
String
>
items
;
final
ValueChanged
<
String
>
onChanged
;
@override
Widget
build
(
BuildContext
context
)
{
final
int
indexOfValue
=
items
.
indexOf
(
value
);
assert
(
indexOfValue
!=
-
1
);
final
bool
canIncrease
=
indexOfValue
<
items
.
length
-
1
;
final
bool
canDecrease
=
indexOfValue
>
0
;
return
new
Semantics
(
container:
true
,
label:
label
,
value:
value
,
increasedValue:
canIncrease
?
_increasedValue
:
null
,
decreasedValue:
canDecrease
?
_decreasedValue
:
null
,
onIncrease:
canIncrease
?
_performIncrease
:
null
,
onDecrease:
canDecrease
?
_performDecrease
:
null
,
child:
new
ExcludeSemantics
(
child:
new
ListTile
(
title:
new
Text
(
label
),
trailing:
new
DropdownButton
<
String
>(
value:
value
,
onChanged:
onChanged
,
items:
items
.
map
((
String
item
)
{
return
new
DropdownMenuItem
<
String
>(
value:
item
,
child:
new
Text
(
item
),
);
}).
toList
(),
),
),
)
);
}
String
get
_increasedValue
{
final
int
indexOfValue
=
items
.
indexOf
(
value
);
assert
(
indexOfValue
<
items
.
length
-
1
);
return
items
[
indexOfValue
+
1
];
}
String
get
_decreasedValue
{
final
int
indexOfValue
=
items
.
indexOf
(
value
);
assert
(
indexOfValue
>
0
);
return
items
[
indexOfValue
-
1
];
}
void
_performIncrease
()
=>
onChanged
(
_increasedValue
);
void
_performDecrease
()
=>
onChanged
(
_decreasedValue
);
}
class
AdjustableDropdownExample
extends
StatefulWidget
{
@override
AdjustableDropdownExampleState
createState
()
=>
new
AdjustableDropdownExampleState
();
}
class
AdjustableDropdownExampleState
extends
State
<
AdjustableDropdownExample
>
{
final
List
<
String
>
items
=
<
String
>[
'1 second'
,
'5 seconds'
,
'15 seconds'
,
'30 seconds'
,
'1 minute'
];
String
timeout
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
MaterialApp
(
home:
new
Scaffold
(
appBar:
new
AppBar
(
title:
const
Text
(
'Adjustable DropDown'
),
),
body:
new
ListView
(
children:
<
Widget
>[
new
AdjustableDropdownListTile
(
label:
'Timeout'
,
value:
timeout
??
items
[
2
],
items:
items
,
onChanged:
(
String
value
)
{
setState
(()
{
timeout
=
value
;
});
},
),
],
),
),
);
}
}
void
main
(
)
{
runApp
(
new
AdjustableDropdownExample
());
}
/*
Sample Catalog
Title: AdjustableDropdownListTile
Summary: A dropdown menu that exposes itself as an "Adjustable" to screen
readers.
Description:
This app presents a dropdown menu to the user that exposes itself as an
"Adjustable" to screen readers (e.g. TalkBack on Android and VoiceOver on iOS).
This allows users of screen readers to cycle through the values of the dropdown
menu by swiping up or down on the screen with one finger (on iOS) or by using
the volume keys (on Android). Depending on the values in the dropdown this
behavior may be more intuitive to screen reader users compared to showing the
classical dropdown overlay on screen to choose a value.
When the screen reader is turned off, the dropdown menu behaves like any
dropdown menu would.
Classes: Semantics
Sample: AdjustableDropdownListTile
*/
examples/catalog/test/custom_semantics_test.dart
0 → 100644
View file @
4d9fbe78
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/rendering.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../lib/custom_semantics.dart'
as
custom_semantics
show
main
;
import
'../lib/custom_semantics.dart'
;
void
main
(
)
{
testWidgets
(
'custom_semantics sample smoke test'
,
(
WidgetTester
tester
)
async
{
// Turn on Semantics
final
SemanticsHandle
semanticsHandler
=
tester
.
binding
.
pipelineOwner
.
ensureSemantics
();
final
SemanticsOwner
semanticsOwner
=
tester
.
binding
.
pipelineOwner
.
semanticsOwner
;
// Build the sample app
custom_semantics
.
main
();
await
tester
.
pump
();
// Verify it correctly exposes its semantics.
// TODO(goderbauer): Use `SemanticsTester` after https://github.com/flutter/flutter/issues/12286.
final
SemanticsNode
semantics
=
tester
.
renderObject
(
find
.
byType
(
AdjustableDropdownListTile
))
.
debugSemantics
;
expectAdjustable
(
semantics
,
hasIncreaseAction:
true
,
hasDecreaseAction:
true
,
label:
'Timeout'
,
decreasedValue:
'5 seconds'
,
value:
'15 seconds'
,
increasedValue:
'30 seconds'
,
);
// Increase
semanticsOwner
.
performAction
(
semantics
.
id
,
SemanticsAction
.
increase
);
await
tester
.
pump
();
expectAdjustable
(
semantics
,
hasIncreaseAction:
true
,
hasDecreaseAction:
true
,
label:
'Timeout'
,
decreasedValue:
'15 seconds'
,
value:
'30 seconds'
,
increasedValue:
'1 minute'
,
);
// Increase all the way to highest value
semanticsOwner
.
performAction
(
semantics
.
id
,
SemanticsAction
.
increase
);
await
tester
.
pump
();
expectAdjustable
(
semantics
,
hasIncreaseAction:
false
,
hasDecreaseAction:
true
,
label:
'Timeout'
,
decreasedValue:
'30 seconds'
,
value:
'1 minute'
,
);
// Decrease
semanticsOwner
.
performAction
(
semantics
.
id
,
SemanticsAction
.
decrease
);
await
tester
.
pump
();
expectAdjustable
(
semantics
,
hasIncreaseAction:
true
,
hasDecreaseAction:
true
,
label:
'Timeout'
,
decreasedValue:
'15 seconds'
,
value:
'30 seconds'
,
increasedValue:
'1 minute'
,
);
// Decrease all the way to lowest value
semanticsOwner
.
performAction
(
semantics
.
id
,
SemanticsAction
.
decrease
);
await
tester
.
pump
();
semanticsOwner
.
performAction
(
semantics
.
id
,
SemanticsAction
.
decrease
);
await
tester
.
pump
();
semanticsOwner
.
performAction
(
semantics
.
id
,
SemanticsAction
.
decrease
);
await
tester
.
pump
();
expectAdjustable
(
semantics
,
hasIncreaseAction:
true
,
hasDecreaseAction:
false
,
label:
'Timeout'
,
value:
'1 second'
,
increasedValue:
'5 seconds'
,
);
// Clean-up
semanticsHandler
.
dispose
();
});
}
void
expectAdjustable
(
SemanticsNode
node
,
{
bool
hasIncreaseAction:
true
,
bool
hasDecreaseAction:
true
,
String
label:
''
,
String
decreasedValue:
''
,
String
value:
''
,
String
increasedValue:
''
,
})
{
final
SemanticsData
semanticsData
=
node
.
getSemanticsData
();
int
actions
=
0
;
if
(
hasIncreaseAction
)
actions
|=
SemanticsAction
.
increase
.
index
;
if
(
hasDecreaseAction
)
actions
|=
SemanticsAction
.
decrease
.
index
;
expect
(
semanticsData
.
actions
,
actions
);
expect
(
semanticsData
.
label
,
label
);
expect
(
semanticsData
.
decreasedValue
,
decreasedValue
);
expect
(
semanticsData
.
value
,
value
);
expect
(
semanticsData
.
increasedValue
,
increasedValue
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment