mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->
previous https://github.com/flutter/flutter/pull/167363
I have to factor out abstract class for RadioGroupRegistry and
RadioClient which are subclassed by RadioGroupState and RawRadio
respectively.
I have to do this because the RadioListTile that has 2 focusnode one for
listTile and one for the radio it builds. The issue is that RadioGroup's
keyboard shortcut has to tightly couples with the focus node of each
radio, but the radioListtile has to mute the radio's focusnode so it can
act as one control under keyboard shortcut
d582b35809/packages/flutter/lib/src/material/radio_list_tile.dart (L484)
Therefore i abstract the out the logic of RadioGroup so that another
widget can participate by implementing the interface.
fixes https://github.com/flutter/flutter/issues/113562
migration guide: https://github.com/flutter/website/pull/12080/files
## Pre-launch Checklist
- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [ ] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
242 lines
6.0 KiB
Dart
242 lines
6.0 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// This code is not runnable, it contains code snippets displayed in the Gallery.
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
class ButtonsDemo {
|
|
void setState(VoidCallback callback) {}
|
|
late BuildContext context;
|
|
|
|
void buttons() {
|
|
// START buttons_elevated
|
|
// Create an elevated button.
|
|
ElevatedButton(
|
|
child: const Text('BUTTON TITLE'),
|
|
onPressed: () {
|
|
// Perform some action
|
|
},
|
|
);
|
|
|
|
// Create a disabled button.
|
|
// Buttons are disabled when onPressed isn't
|
|
// specified or is null.
|
|
const ElevatedButton(onPressed: null, child: Text('BUTTON TITLE'));
|
|
|
|
// Create a button with an icon and a
|
|
// title.
|
|
ElevatedButton.icon(
|
|
icon: const Icon(Icons.add, size: 18.0),
|
|
label: const Text('BUTTON TITLE'),
|
|
onPressed: () {
|
|
// Perform some action
|
|
},
|
|
);
|
|
// END
|
|
|
|
// START buttons_outlined
|
|
// Create an outlined button.
|
|
OutlinedButton(
|
|
child: const Text('BUTTON TITLE'),
|
|
onPressed: () {
|
|
// Perform some action
|
|
},
|
|
);
|
|
|
|
// Create a disabled button.
|
|
// Buttons are disabled when onPressed isn't
|
|
// specified or is null.
|
|
const OutlinedButton(onPressed: null, child: Text('BUTTON TITLE'));
|
|
|
|
// Create a button with an icon and a
|
|
// title.
|
|
OutlinedButton.icon(
|
|
icon: const Icon(Icons.add, size: 18.0),
|
|
label: const Text('BUTTON TITLE'),
|
|
onPressed: () {
|
|
// Perform some action
|
|
},
|
|
);
|
|
// END
|
|
|
|
// START buttons_text
|
|
// Create a text button.
|
|
TextButton(
|
|
child: const Text('BUTTON TITLE'),
|
|
onPressed: () {
|
|
// Perform some action
|
|
},
|
|
);
|
|
|
|
// Create a disabled button.
|
|
// Buttons are disabled when onPressed isn't
|
|
// specified or is null.
|
|
const TextButton(onPressed: null, child: Text('BUTTON TITLE'));
|
|
// END
|
|
|
|
// START buttons_dropdown
|
|
// Member variable holding value.
|
|
String? dropdownValue;
|
|
|
|
// Dropdown button with string values.
|
|
DropdownButton<String>(
|
|
value: dropdownValue,
|
|
onChanged: (String? newValue) {
|
|
// null indicates the user didn't select a
|
|
// new value.
|
|
setState(() {
|
|
if (newValue != null) {
|
|
dropdownValue = newValue;
|
|
}
|
|
});
|
|
},
|
|
items:
|
|
<String>['One', 'Two', 'Free', 'Four'].map<DropdownMenuItem<String>>((String value) {
|
|
return DropdownMenuItem<String>(value: value, child: Text(value));
|
|
}).toList(),
|
|
);
|
|
// END
|
|
|
|
// START buttons_icon
|
|
// Member variable holding toggle value.
|
|
late bool value = true;
|
|
|
|
// Toggleable icon button.
|
|
IconButton(
|
|
icon: const Icon(Icons.thumb_up),
|
|
onPressed: () {
|
|
setState(() => value = !value);
|
|
},
|
|
color: value ? Theme.of(context).primaryColor : null,
|
|
);
|
|
// END
|
|
|
|
// START buttons_action
|
|
// Floating action button in Scaffold.
|
|
Scaffold(
|
|
appBar: AppBar(title: const Text('Demo')),
|
|
floatingActionButton: const FloatingActionButton(onPressed: null, child: Icon(Icons.add)),
|
|
);
|
|
// END
|
|
}
|
|
}
|
|
|
|
class SelectionControls {
|
|
void setState(VoidCallback callback) {}
|
|
|
|
void selectionControls() {
|
|
// START selectioncontrols_checkbox
|
|
// Member variable holding the checkbox's value.
|
|
bool? checkboxValue = false;
|
|
|
|
// Create a checkbox.
|
|
Checkbox(
|
|
value: checkboxValue,
|
|
onChanged: (bool? value) {
|
|
setState(() {
|
|
checkboxValue = value;
|
|
});
|
|
},
|
|
);
|
|
|
|
// Create a tristate checkbox.
|
|
Checkbox(
|
|
tristate: true,
|
|
value: checkboxValue,
|
|
onChanged: (bool? value) {
|
|
setState(() {
|
|
checkboxValue = value;
|
|
});
|
|
},
|
|
);
|
|
|
|
// Create a disabled checkbox.
|
|
// Checkboxes are disabled when onChanged isn't
|
|
// specified or null.
|
|
const Checkbox(value: false, onChanged: null);
|
|
// END
|
|
|
|
// START selectioncontrols_radio
|
|
// Member variable holding value.
|
|
int? radioValue = 0;
|
|
|
|
// Method setting value.
|
|
void handleRadioValueChanged(int? value) {
|
|
setState(() {
|
|
radioValue = value;
|
|
});
|
|
}
|
|
|
|
// Creates a set of radio buttons.
|
|
Row(
|
|
children: <Widget>[
|
|
Radio<int>(value: 0, groupValue: radioValue, onChanged: handleRadioValueChanged),
|
|
Radio<int>(value: 1, groupValue: radioValue, onChanged: handleRadioValueChanged),
|
|
Radio<int>(value: 2, groupValue: radioValue, onChanged: handleRadioValueChanged),
|
|
],
|
|
);
|
|
|
|
// Creates a disabled radio button.
|
|
const Radio<int>(value: 0, groupValue: 0);
|
|
// END
|
|
|
|
// START selectioncontrols_switch
|
|
// Member variable holding value.
|
|
bool switchValue = false;
|
|
|
|
// Create a switch.
|
|
Switch(
|
|
value: switchValue,
|
|
onChanged: (bool value) {
|
|
setState(() {
|
|
switchValue = value;
|
|
});
|
|
},
|
|
);
|
|
|
|
// Create a disabled switch.
|
|
// Switches are disabled when onChanged isn't
|
|
// specified or null.
|
|
const Switch(value: false, onChanged: null);
|
|
// END
|
|
}
|
|
}
|
|
|
|
class GridLists {
|
|
void gridlists() {
|
|
// START gridlists
|
|
// Creates a scrollable grid list with images
|
|
// loaded from the web.
|
|
GridView.count(
|
|
crossAxisCount: 3,
|
|
padding: const EdgeInsets.all(4.0),
|
|
mainAxisSpacing: 4.0,
|
|
crossAxisSpacing: 4.0,
|
|
children:
|
|
<String>[
|
|
'https://example.com/image-0.jpg',
|
|
'https://example.com/image-1.jpg',
|
|
'https://example.com/image-2.jpg',
|
|
'...',
|
|
'https://example.com/image-n.jpg',
|
|
].map<Widget>((String url) {
|
|
return GridTile(
|
|
footer: GridTileBar(title: Text(url)),
|
|
child: Image.network(url, fit: BoxFit.cover),
|
|
);
|
|
}).toList(),
|
|
);
|
|
// END
|
|
}
|
|
}
|
|
|
|
class AnimatedImage {
|
|
void animatedImage() {
|
|
// START animated_image
|
|
Image.network('https://example.com/animated-image.gif');
|
|
// END
|
|
}
|
|
}
|