Repository: Dn-a/flutter_tags
Branch: master
Commit: cf6d3f861354
Files: 35
Total size: 158.7 KB
Directory structure:
gitextract_ehrk8p54/
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example/
│ ├── .gitignore
│ ├── .metadata
│ ├── README.md
│ ├── ios/
│ │ ├── Flutter/
│ │ │ ├── AppFrameworkInfo.plist
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── flutter_export_environment.sh
│ │ ├── Runner/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── LaunchImage.imageset/
│ │ │ │ ├── Contents.json
│ │ │ │ └── README.md
│ │ │ ├── Base.lproj/
│ │ │ │ ├── LaunchScreen.storyboard
│ │ │ │ └── Main.storyboard
│ │ │ ├── Info.plist
│ │ │ └── Runner-Bridging-Header.h
│ │ ├── Runner.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace/
│ │ │ │ └── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── Runner.xcscheme
│ │ └── Runner.xcworkspace/
│ │ └── contents.xcworkspacedata
│ ├── lib/
│ │ └── main.dart
│ ├── pubspec.yaml
│ └── test/
│ └── widget_test.dart
├── flutter_tags.iml
├── lib/
│ ├── flutter_tags.dart
│ └── src/
│ ├── item_tags.dart
│ ├── suggestions_textfield.dart
│ ├── tags.dart
│ └── util/
│ └── custom_wrap.dart
├── pubspec.yaml
└── test/
└── flutter_tags_test.dart
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
.dart_tool/
.packages
.pub/
build/
ios/.generated/
ios/Flutter/Generated.xcconfig
ios/Runner/GeneratedPluginRegistrant.*
lib/generated/
res/
.idea/
android/
lib/selectable_tags_back.dart
example/lib/main_back.dart
================================================
FILE: .metadata
================================================
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: d48e6e433cc5ca67b24b19f70aaa197e84ba63c1
channel: beta
project_type: package
================================================
FILE: CHANGELOG.md
================================================
## [0.4.9+1] - 2020-11-11.
* `[Fixed]` - Issue #66.
* `[Fixed]` - `DataList` null id.
## [0.4.9] - 2020-09-15.
* `[Added]` - Possibility to to define the padding of the `textField`.
## [0.4.8+2] - 2020-06-02.
* `[Updated]` - Documentation.
## [0.4.8+1] - 2020-05-13.
* `[Updated]` - Documentation.
## [0.4.8] - 2020-03-07.
* `[Updated]` - Documentation.
## [0.4.7] - 2020-02-26.
* `[Updated]` - Documentation.
* General improvement of the code.
## [0.4.6] - 2020-02-26.
* `[Fixed]` - some problem.
* `[Added]` - Possibility to disabled/enabled `textField` field - Issue #36.
* `[Added]` - Possibility to insert tags not present in the list of suggestions with the `constraintSuggestion` field - Issue #33.
* `onRemoved` field has been moved inside `ItemTagsRemoveButton()` to maintain consistency.
* `onRemoved` now has a bool return type (ex: when you want to add a control before removing a tag).
## [0.4.5] - 2019-10-30.
* Renamed `TagstextField` to `TagsTextField`.
* Added `textCapitalization` field in `TagsTextField`.
## [0.4.4] - 2019-10-16.
* New Features and Documentation Updates.
* Added `child` field in `ItemTagsImage()`, allows more control over the images.
* Fixed alignment `textField` and `suggestions` - Issue #31.
* Added the possibility to get a list of all the `ItemTags` via GlobalKey<TagsState>.
## [0.4.3] - 2019-07-28.
* Minor Update Documentation.
* Fixed some problem.
* removed the 'position' parameter in TagsTexField () because it is not essential. the same result can be obtained by setting the verticalDirection and TextDirection parameters in Tags ().
## [0.4.2] - 2019-07-27.
* Update Documentation.
* General improvement of the code.
## [0.4.1] - 2019-07-27.
* Minor Update Documentation.
## [0.4.0] - 2019-07-27.
* **Improvements, new Structure, new Features and Documentation Updates**
*
* `SelectableTags` and `InputTags`have been removed, now there is only one widget. **Tags()**
* Now it is possible to personalize every single tag, with the possibility of adding icons, images and a removal button.
* Possibility to display the list with horizontal scroll.
## [0.3.2] - 2019-06-20.
* Issue #14 and #13 fixed.
* Added `customData` field in Tag Class.
## [0.3.1] - 2019-05-13.
* General improvement of the code.
## [0.3.0] - 2019-04-09.
* **New features**
* Possibility to create a customizable popupMenu.
* **SelectableTags**. Possibility to set a color and an activeColor for each tag.
* **InputTags**. Possibility to hide textField.
## [0.2.4] - 2019-04-08.
* fixed some problem.
## [0.2.3] - 2019-04-05.
* General improvement of the code.
* OnInsert, onDelete and onPressed are now optional.
## [0.2.2] - 2019-03-02.
* Added property `textStyle` in InputTags. NOTE: `textColor` has been removed. now it can be set with `textStyle`.
* added property `textStyle` in SelectableTags. NOTE: if you set `color` in it will be ignored, you must use `textColor` `textActiveColor`.
* Created InputSuggestions. Return suggestions in the TextField. Is not complete, soon the list of suggestions will be implemented.
* General improvement of the code.
## [0.2.1] - 2019-03-01.
* The code has been largely rewritten.
* Now the Tag width calculation is very accurate.
## [0.2.0] - 2019-02-24.
* Improved tag width calculation;
* Possibility to change the margin and padding of the close icon ( InputTags ).
## [0.1.9] - 2019-02-23.
* Width calculated based on the byte length of the title;
* When the orientation changes, a recalculation of the screen width is performed.
## [0.1.8] - 2019-02-16.
* Improvement of library documentation.
## [0.1.7] - 2019-02-07.
* Added new feature SingleItem on SelectableTags;
* Possibility to change color/background-color icon on InputTags; - General improvement of the code.
## [0.1.6] - 2019-01-07.
* Fixed error "Infinity or NaN toInt" on InputTags; - general improvement of the code.
## [0.1.5] - 2018-12-24.
* General improvement of the code.
## [0.1.4] - 2018-12-18.
* Added new features.
## [0.1.3] - 2018-12-16.
* Added new highlight feature (InputTags) - general improvement of the code.
## [0.1.2] - 2018-12-15.
* Add InputTags Widget - Improved documentation.
## [0.1.1] - 2018-12-08.
* Improved documentation.
## [0.1.0] - 2018-12-08.
* Did some changing readme.
## [0.0.1] - 2018-12-08.
* Created Selectable Tags.
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2018 Antonino Di Natale
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
================================================
FILE: README.md
================================================
# flutter_tags
[](https://pub.dartlang.org/packages/flutter_tags)
[](https://github.com/Solido/awesome-flutter#ui)
[](https://www.paypal.me/dnag88)
Create beautiful tags quickly and easily.
## Installing
Add this to your package's pubspec.yaml file:
```dart
dependencies:
flutter_tags: "^0.4.9+1"
```
## DEMO
<div align="center">
<table>
<tr>
<td style="text-align:center">
<img width = "250px" src="https://github.com/Dn-a/flutter_tags/raw/master/repo-file/img/example0.4.0_1.gif" />
</td>
<td style="text-align:center">
<img width = "250px" src="https://github.com/Dn-a/flutter_tags/raw/master/repo-file/img/example0.4.0_2.gif" />
</td>
</tr>
</table>
</div>
## Simple usage
```dart
import 'package:flutter_tags/flutter_tags.dart';
.
.
.
List _items;
double _fontSize = 14;
@override
void initState(){
super.initState();
// if you store data on a local database (sqflite), then you could do something like this
Model().getItems().then((items){
_items = items;
});
}
@override
Widget build(BuildContext context) {
return Tags(
key:_tagStateKey,
textField: TagsTextField(
textStyle: TextStyle(fontSize: _fontSize),
constraintSuggestion: true, suggestions: [],
//width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 10),
onSubmitted: (String str) {
// Add item to the data source.
setState(() {
// required
_items.add(str);
});
},
),
itemCount: _items.length, // required
itemBuilder: (int index){
final item = _items[index];
return ItemTags(
// Each ItemTags must contain a Key. Keys allow Flutter to
// uniquely identify widgets.
key: Key(index.toString()),
index: index, // required
title: item.title,
active: item.active,
customData: item.customData,
textStyle: TextStyle( fontSize: _fontSize, ),
combine: ItemTagsCombine.withTextBefore,
image: ItemTagsImage(
image: AssetImage("img.jpg") // OR NetworkImage("https://...image.png")
), // OR null,
icon: ItemTagsIcon(
icon: Icons.add,
), // OR null,
removeButton: ItemTagsRemoveButton(
onRemoved: (){
// Remove the item from the data source.
setState(() {
// required
_items.removeAt(index);
});
//required
return true;
},
), // OR null,
onPressed: (item) => print(item),
onLongPressed: (item) => print(item),
);
},
);
}
final GlobalKey<TagsState> _tagStateKey = GlobalKey<TagsState>();
// Allows you to get a list of all the ItemTags
_getAllItem(){
List<Item> lst = _tagStateKey.currentState?.getAllItem;
if(lst!=null)
lst.where((a) => a.active==true).forEach( ( a) => print(a.title));
}
```
## Wrapped widget example
You are free to wrap ItemTags () inside another widget
```dart
Tags(
itemCount: items.length,
itemBuilder: (int index){
return Tooltip(
message: item.title,
child:ItemTags(
title:item.title,
)
);
},
);
```
### Tags() parameters
|PropName|Description|default value|
|:-------|:----------|:------------|
|`columns`|*Possibility to set number of columns when necessary*|null|
|`itemCount`|*Tag number to display*|required|
|`symmetry`|*Ability to view and scroll tags horizontally*|false|
|`horizontalScroll`|*Offset drawer width*|0.4|
|`heightHorizontalScroll`|*height for HorizontalScroll to set to display tags correctly*|60|
|`spacing`|*Horizontal space between the tags*|6|
|`runSpacing`|*Vertical space between the tags*|14|
|`alignment`|*Horizontal WrapAlignment*|WrapAlignment.center|
|`runAlignment`|*Vertical WrapAlignment*|WrapAlignment.center|
|`direction`|*Direction of the ItemTags*|Axis.horizontal|
|`verticalDirection`|*Iterate Item from the lower to the upper direction or vice versa*|VerticalDirection.down|
|`textDirection`|*Text direction of the ItemTags*|TextDirection.ltr|
|`itemBuilder`|*tag generator*||
|`textField`|*add textField*|TagsTextFiled()|
### ItemTags() parameters
* `index` - *required*
* `title` - *required*
* `textScaleFactor` - *custom textScaleFactor*
* `active` - *bool value (default true)*
* `pressEnabled` - *active onPress tag ( default true)*
* `customData` - *Possibility to add any custom value in customData field, you can retrieve this later. A good example: store an id from Firestore document.*
* `textStyle` - *textStyle()*
* `alignment` - *MainAxisAlignment ( default MainAxisAlignment.center)*
* `combine` - * ability to combine text, icons, images in different ways ( default ItemTagsCombine.imageOrIconOrText)*
* `icon` - *ItemTagsIcon()*
* `image` - *ItemTagsImage()*
* `removeButton` - *ItemTagsRemoveButton()*
* `borderRadius` - *BorderRadius*
* `border` - *custom border-side*
* `padding` - *default EdgeInsets.symmetric(horizontal: 7, vertical: 5)*
* `elevation` - *default 5*
* `singleItem` - *default false*
* `textOverflow` - *default TextOverflow.fade*
* `textColor` - *default Colors.black*
* `textActiveColor` - *default Colors.white*
* `color` - *default Colors.white*
* `activeColor` - *default Colors.blueGrey*
* `highlightColor` -
* `splashColor` -
* `colorShowDuplicate` - *default Colors.red*
* `onPressed` - *callback*
* `onLongPressed` - *callback*
* `onRemoved` - *callback*
## Donate
It takes time to carry on this project. If you found it useful or learned something from the source code please consider the idea of donating 5, 20, 50 € or whatever you can to support the project.
- [](https://www.paypal.me/dnag88)
## Issues
If you encounter problems, open an issue. Pull request are also welcome.
================================================
FILE: example/.gitignore
================================================
# Miscellaneous
*.class
*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.packages
.pub-cache/
.pub/
build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
================================================
FILE: example/.metadata
================================================
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b
channel: beta
project_type: app
================================================
FILE: example/README.md
================================================
# Example Flutter Tags
An example of how you could implement it.
## Getting Started - Selectable Tags
```dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_tags/flutter_tags.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tags Demo',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: MyHomePage(title: 'Flutter Tags'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
ScrollController _scrollViewController;
final List<String> _list = [
'0',
'SDK',
'plugin updates',
'Facebook',
'哔了狗了QP又不够了',
'Kirchhoff',
'Italy',
'France',
'Spain',
'美',
'Dart',
'SDK',
'Foo',
'Select',
'lorem ip',
'9',
'Star',
'Flutter Selectable Tags',
'1',
'Hubble',
'2',
'Input flutter tags',
'A B C',
'8',
'Android Studio developer',
'welcome to the jungle',
'Gauss',
'美术',
'互联网',
'炫舞时代',
'篝火营地',
];
bool _symmetry = false;
bool _removeButton = true;
bool _singleItem = false;
bool _startDirection = false;
bool _horizontalScroll = false;
bool _withSuggesttions = false;
int _count = 0;
int _column = 0;
double _fontSize = 14;
String _itemCombine = 'withTextBefore';
String _onPressed = '';
List _icon = [Icons.home, Icons.language, Icons.headset];
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
_scrollViewController = ScrollController();
_items = _list.toList();
}
List _items;
final GlobalKey<TagsState> _tagStateKey = GlobalKey<TagsState>();
@override
Widget build(BuildContext context) {
//List<Item> lst = _tagStateKey.currentState?.getAllItem; lst.forEach((f) => print(f.title));
return Scaffold(
body: NestedScrollView(
controller: _scrollViewController,
headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Text("flutter tags"),
centerTitle: true,
pinned: true,
expandedHeight: 0,
floating: true,
forceElevated: boxIsScrolled,
bottom: TabBar(
isScrollable: false,
indicatorSize: TabBarIndicatorSize.label,
labelStyle: TextStyle(fontSize: 18.0),
tabs: [
Tab(text: "Demo 1"),
Tab(text: "Demo 2"),
],
controller: _tabController,
),
)
];
},
body: TabBarView(
controller: _tabController,
children: [
CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey[300], width: 0.5))),
margin:
EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: ExpansionTile(
title: Text("Settings"),
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _removeButton,
onChanged: (a) {
setState(() {
_removeButton = !_removeButton;
});
}),
Text('Remove Button')
],
),
onTap: () {
setState(() {
_removeButton = !_removeButton;
});
},
),
Padding(
padding: EdgeInsets.all(5),
),
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _symmetry,
onChanged: (a) {
setState(() {
_symmetry = !_symmetry;
});
}),
Text('Symmetry')
],
),
onTap: () {
setState(() {
_symmetry = !_symmetry;
});
},
),
Padding(
padding: EdgeInsets.all(5),
),
DropdownButton(
hint: _column == 0
? Text("Not set")
: Text(_column.toString()),
items: _buildItems(),
onChanged: (a) {
setState(() {
_column = a;
});
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _horizontalScroll,
onChanged: (a) {
setState(() {
_horizontalScroll =
!_horizontalScroll;
});
}),
Text('Horizontal scroll')
],
),
onTap: () {
setState(() {
_horizontalScroll = !_horizontalScroll;
});
},
),
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _singleItem,
onChanged: (a) {
setState(() {
_singleItem = !_singleItem;
});
}),
Text('Single Item')
],
),
onTap: () {
setState(() {
_singleItem = !_singleItem;
});
},
),
],
),
Column(
children: <Widget>[
Text('Font Size'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
value: _fontSize,
min: 6,
max: 30,
onChanged: (a) {
setState(() {
_fontSize = (a.round()).toDouble();
});
},
),
Text(_fontSize.toString()),
Padding(
padding:
EdgeInsets.symmetric(horizontal: 20),
),
Container(
height: 30,
width: 30,
//color: Colors.blueGrey,
child: IconButton(
padding: EdgeInsets.all(0),
//color: Colors.white,
icon: Icon(Icons.add),
onPressed: () {
setState(() {
_count++;
_items.add(_count.toString());
//_items.removeAt(3); _items.removeAt(10);
});
},
),
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: 5),
),
Container(
height: 30,
width: 30,
//color: Colors.grey,
child: IconButton(
padding: EdgeInsets.all(0),
//color: Colors.white,
icon: Icon(Icons.refresh),
onPressed: () {
setState(() {
_items = _list.toList();
});
},
),
),
],
),
],
),
],
),
),
Padding(
padding: EdgeInsets.all(20),
),
_tags1,
Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Divider(
color: Colors.blueGrey,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Text(_onPressed),
),
],
)),
])),
],
),
CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey[300], width: 0.5))),
margin:
EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: ExpansionTile(
title: Text("Settings"),
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _withSuggesttions,
onChanged: (a) {
setState(() {
_withSuggesttions =
!_withSuggesttions;
});
}),
Text('Suggestions')
],
),
onTap: () {
setState(() {
_withSuggesttions = !_withSuggesttions;
});
},
),
Padding(
padding: EdgeInsets.all(20),
),
DropdownButton(
hint: Text(_itemCombine),
items: _buildItems2(),
onChanged: (val) {
setState(() {
_itemCombine = val;
});
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _horizontalScroll,
onChanged: (a) {
setState(() {
_horizontalScroll =
!_horizontalScroll;
});
}),
Text('Horizontal scroll')
],
),
onTap: () {
setState(() {
_horizontalScroll = !_horizontalScroll;
});
},
),
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _startDirection,
onChanged: (a) {
setState(() {
_startDirection = !_startDirection;
});
}),
Text('Start Direction')
],
),
onTap: () {
setState(() {
_startDirection = !_startDirection;
});
},
),
],
),
Column(
children: <Widget>[
Text('Font Size'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
value: _fontSize,
min: 6,
max: 30,
onChanged: (a) {
setState(() {
_fontSize = (a.round()).toDouble();
});
},
),
Text(_fontSize.toString()),
],
),
],
),
],
),
),
Padding(
padding: EdgeInsets.all(20),
),
_tags2,
Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Divider(
color: Colors.blueGrey,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Text(_onPressed),
),
],
)),
])),
],
),
],
)),
);
}
Widget get _tags1 {
return Tags(
key: _tagStateKey,
symmetry: _symmetry,
columns: _column,
horizontalScroll: _horizontalScroll,
//verticalDirection: VerticalDirection.up, textDirection: TextDirection.rtl,
heightHorizontalScroll: 60 * (_fontSize / 14),
itemCount: _items.length,
itemBuilder: (index) {
final item = _items[index];
return ItemTags(
key: Key(index.toString()),
index: index,
title: item,
pressEnabled: true,
activeColor: Colors.blueGrey[600],
singleItem: _singleItem,
splashColor: Colors.green,
combine: ItemTagsCombine.withTextBefore,
image: index > 0 && index < 5
? ItemTagsImage(
//image: AssetImage("img/p$index.jpg"),
child: Image.network(
"http://www.clipartpanda.com/clipart_images/user-66327738/download",
width: 16 * _fontSize / 14,
height: 16 * _fontSize / 14,
))
: (1 == 1
? ItemTagsImage(
image: NetworkImage(
"https://d32ogoqmya1dw8.cloudfront.net/images/serc/empty_user_icon_256.v2.png"),
)
: null),
icon: (item == '0' || item == '1' || item == '2')
? ItemTagsIcon(
icon: _icon[int.parse(item)],
)
: null,
removeButton: _removeButton
? ItemTagsRemoveButton(
onRemoved: () {
setState(() {
_items.removeAt(index);
});
return true;
},
)
: null,
textScaleFactor:
utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1,
textStyle: TextStyle(
fontSize: _fontSize,
),
onPressed: (item) => print(item),
);
},
);
}
// Position for popup menu
Offset _tapPosition;
Widget get _tags2 {
//popup Menu
final RenderBox overlay = Overlay.of(context).context?.findRenderObject();
ItemTagsCombine combine = ItemTagsCombine.onlyText;
switch (_itemCombine) {
case 'onlyText':
combine = ItemTagsCombine.onlyText;
break;
case 'onlyIcon':
combine = ItemTagsCombine.onlyIcon;
break;
case 'onlyIcon':
combine = ItemTagsCombine.onlyIcon;
break;
case 'onlyImage':
combine = ItemTagsCombine.onlyImage;
break;
case 'imageOrIconOrText':
combine = ItemTagsCombine.imageOrIconOrText;
break;
case 'withTextAfter':
combine = ItemTagsCombine.withTextAfter;
break;
case 'withTextBefore':
combine = ItemTagsCombine.withTextBefore;
break;
}
return Tags(
key: Key("2"),
symmetry: _symmetry,
columns: _column,
horizontalScroll: _horizontalScroll,
verticalDirection:
_startDirection ? VerticalDirection.up : VerticalDirection.down,
textDirection: _startDirection ? TextDirection.rtl : TextDirection.ltr,
heightHorizontalScroll: 60 * (_fontSize / 14),
textField: _textField,
itemCount: _items.length,
itemBuilder: (index) {
final item = _items[index];
return GestureDetector(
child: ItemTags(
key: Key(index.toString()),
index: index,
title: item,
pressEnabled: false,
activeColor: Colors.green[400],
combine: combine,
image: index > 0 && index < 5
? ItemTagsImage(image: AssetImage("img/p$index.jpg"))
: (1 == 1
? ItemTagsImage(
image: NetworkImage(
"https://image.flaticon.com/icons/png/512/44/44948.png"))
: null),
icon: (item == '0' || item == '1' || item == '2')
? ItemTagsIcon(
icon: _icon[int.parse(item)],
)
: null,
removeButton: ItemTagsRemoveButton(
backgroundColor: Colors.green[900],
onRemoved: () {
setState(() {
_items.removeAt(index);
});
return true;
},
),
textScaleFactor:
utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1,
textStyle: TextStyle(
fontSize: _fontSize,
),
),
onTapDown: (details) => _tapPosition = details.globalPosition,
onLongPress: () {
showMenu(
//semanticLabel: item,
items: <PopupMenuEntry>[
PopupMenuItem(
child: Text(item, style: TextStyle(color: Colors.blueGrey)),
enabled: false,
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Row(
children: <Widget>[
Icon(Icons.content_copy),
Text("Copy text"),
],
),
),
],
context: context,
position: RelativeRect.fromRect(
_tapPosition & Size(40, 40),
Offset.zero &
overlay
.size) // & RelativeRect.fromLTRB(65.0, 40.0, 0.0, 0.0),
)
.then((value) {
if (value == 1) Clipboard.setData(ClipboardData(text: item));
});
},
);
},
);
}
TagsTextField get _textField {
return TagsTextField(
autofocus: false,
//width: double.infinity,
//padding: EdgeInsets.symmetric(horizontal: 10),
textStyle: TextStyle(
fontSize: _fontSize,
//height: 1
),
enabled: true,
constraintSuggestion: true,
suggestions: _withSuggesttions
? [
"One",
"two",
"android",
"Dart",
"flutter",
"test",
"tests",
"androids",
"androidsaaa",
"Test",
"suggest",
"suggestions",
"互联网",
"last",
"lest",
"炫舞时代"
]
: null,
onSubmitted: (String str) {
setState(() {
_items.add(str);
});
},
);
}
List<DropdownMenuItem> _buildItems() {
List<DropdownMenuItem> list = [];
int count = 19;
list.add(
DropdownMenuItem(
child: Text("Not set"),
value: 0,
),
);
for (int i = 1; i < count; i++)
list.add(
DropdownMenuItem(
child: Text(i.toString()),
value: i,
),
);
return list;
}
List<DropdownMenuItem> _buildItems2() {
List<DropdownMenuItem> list = [];
list.add(DropdownMenuItem(
child: Text("onlyText"),
value: 'onlyText',
));
list.add(DropdownMenuItem(
child: Text("onlyIcon"),
value: 'onlyIcon',
));
list.add(DropdownMenuItem(
child: Text("onlyImage"),
value: 'onlyImage',
));
list.add(DropdownMenuItem(
child: Text("imageOrIconOrText"),
value: 'imageOrIconOrText',
));
list.add(DropdownMenuItem(
child: Text("withTextBefore"),
value: 'withTextBefore',
));
list.add(DropdownMenuItem(
child: Text("withTextAfter"),
value: 'withTextAfter',
));
return list;
}
}
```
## DEMO


## Other
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.io/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
================================================
FILE: example/ios/Flutter/AppFrameworkInfo.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>
================================================
FILE: example/ios/Flutter/Debug.xcconfig
================================================
#include "Generated.xcconfig"
================================================
FILE: example/ios/Flutter/Release.xcconfig
================================================
#include "Generated.xcconfig"
================================================
FILE: example/ios/Flutter/flutter_export_environment.sh
================================================
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=C:\flutter"
export "FLUTTER_APPLICATION_PATH=D:\Android\Flutter\package\flutter_tags\example"
export "FLUTTER_TARGET=lib\main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build\ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=C:\flutter\bin\cache\artifacts\engine\ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
================================================
FILE: example/ios/Runner/AppDelegate.swift
================================================
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
================================================
FILE: example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
================================================
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
================================================
FILE: example/ios/Runner/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
================================================
FILE: example/ios/Runner/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
================================================
FILE: example/ios/Runner/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>example_flutter_tags</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
================================================
FILE: example/ios/Runner/Runner-Bridging-Header.h
================================================
#import "GeneratedPluginRegistrant.h"
================================================
FILE: example/ios/Runner.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 0910;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.dna.exampleFlutterTags;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.dna.exampleFlutterTags;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.dna.exampleFlutterTags;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
================================================
FILE: example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: example/ios/Runner.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: example/lib/main.dart
================================================
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_tags/flutter_tags.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Tags Demo',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: MyHomePage(title: 'Flutter Tags'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
ScrollController _scrollViewController;
final List<String> _list = [
'0',
'SDK',
'plugin updates',
'Facebook',
'哔了狗了QP又不够了',
'Kirchhoff',
'Italy',
'France',
'Spain',
'美',
'Dart',
'SDK',
'Foo',
'Select',
'lorem ip',
'9',
'Star',
'Flutter Selectable Tags',
'1',
'Hubble',
'2',
'Input flutter tags',
'A B C',
'8',
'Android Studio developer',
'welcome to the jungle',
'Gauss',
'美术',
'互联网',
'炫舞时代',
'篝火营地',
];
bool _symmetry = false;
bool _removeButton = true;
bool _singleItem = true;
bool _startDirection = false;
bool _horizontalScroll = true;
bool _withSuggesttions = false;
int _count = 0;
int _column = 0;
double _fontSize = 14;
String _itemCombine = 'withTextBefore';
String _onPressed = '';
List _icon = [Icons.home, Icons.language, Icons.headset];
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
_scrollViewController = ScrollController();
_items = _list.toList();
}
List _items;
final GlobalKey<TagsState> _tagStateKey = GlobalKey<TagsState>();
@override
Widget build(BuildContext context) {
//List<Item> lst = _tagStateKey.currentState?.getAllItem; lst.forEach((f) => print(f.title));
return Scaffold(
body: NestedScrollView(
controller: _scrollViewController,
headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
return <Widget>[
SliverAppBar(
title: Text("flutter tags"),
centerTitle: true,
pinned: true,
expandedHeight: 0,
floating: true,
forceElevated: boxIsScrolled,
bottom: TabBar(
isScrollable: false,
indicatorSize: TabBarIndicatorSize.label,
labelStyle: TextStyle(fontSize: 18.0),
tabs: [
Tab(text: "Demo 1"),
Tab(text: "Demo 2"),
],
controller: _tabController,
),
)
];
},
body: TabBarView(
controller: _tabController,
children: [
CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey[300], width: 0.5))),
margin:
EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: ExpansionTile(
title: Text("Settings"),
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _removeButton,
onChanged: (a) {
setState(() {
_removeButton = !_removeButton;
});
}),
Text('Remove Button')
],
),
onTap: () {
setState(() {
_removeButton = !_removeButton;
});
},
),
Padding(
padding: EdgeInsets.all(5),
),
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _symmetry,
onChanged: (a) {
setState(() {
_symmetry = !_symmetry;
});
}),
Text('Symmetry')
],
),
onTap: () {
setState(() {
_symmetry = !_symmetry;
});
},
),
Padding(
padding: EdgeInsets.all(5),
),
DropdownButton(
hint: _column == 0
? Text("Not set")
: Text(_column.toString()),
items: _buildItems(),
onChanged: (a) {
setState(() {
_column = a;
});
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _horizontalScroll,
onChanged: (a) {
setState(() {
_horizontalScroll =
!_horizontalScroll;
});
}),
Text('Horizontal scroll')
],
),
onTap: () {
setState(() {
_horizontalScroll = !_horizontalScroll;
});
},
),
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _singleItem,
onChanged: (a) {
setState(() {
_singleItem = !_singleItem;
});
}),
Text('Single Item')
],
),
onTap: () {
setState(() {
_singleItem = !_singleItem;
});
},
),
],
),
Column(
children: <Widget>[
Text('Font Size'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
value: _fontSize,
min: 6,
max: 30,
onChanged: (a) {
setState(() {
_fontSize = (a.round()).toDouble();
});
},
),
Text(_fontSize.toString()),
Padding(
padding:
EdgeInsets.symmetric(horizontal: 20),
),
Container(
height: 30,
width: 30,
//color: Colors.blueGrey,
child: IconButton(
padding: EdgeInsets.all(0),
//color: Colors.white,
icon: Icon(Icons.add),
onPressed: () {
setState(() {
_count++;
_items.add(_count.toString());
//_items.removeAt(3); _items.removeAt(10);
});
},
),
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: 5),
),
Container(
height: 30,
width: 30,
//color: Colors.grey,
child: IconButton(
padding: EdgeInsets.all(0),
//color: Colors.white,
icon: Icon(Icons.refresh),
onPressed: () {
setState(() {
_items = _list.toList();
});
},
),
),
],
),
],
),
],
),
),
Padding(
padding: EdgeInsets.all(20),
),
_tags1,
Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Divider(
color: Colors.blueGrey,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Text(_onPressed),
),
],
)),
])),
],
),
CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey[300], width: 0.5))),
margin:
EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: ExpansionTile(
title: Text("Settings"),
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _withSuggesttions,
onChanged: (a) {
setState(() {
_withSuggesttions =
!_withSuggesttions;
});
}),
Text('Suggestions')
],
),
onTap: () {
setState(() {
_withSuggesttions = !_withSuggesttions;
});
},
),
Padding(
padding: EdgeInsets.all(20),
),
DropdownButton(
hint: Text(_itemCombine),
items: _buildItems2(),
onChanged: (val) {
setState(() {
_itemCombine = val;
});
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _horizontalScroll,
onChanged: (a) {
setState(() {
_horizontalScroll =
!_horizontalScroll;
});
}),
Text('Horizontal scroll')
],
),
onTap: () {
setState(() {
_horizontalScroll = !_horizontalScroll;
});
},
),
GestureDetector(
child: Row(
children: <Widget>[
Checkbox(
value: _startDirection,
onChanged: (a) {
setState(() {
_startDirection = !_startDirection;
});
}),
Text('Start Direction')
],
),
onTap: () {
setState(() {
_startDirection = !_startDirection;
});
},
),
],
),
Column(
children: <Widget>[
Text('Font Size'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
value: _fontSize,
min: 6,
max: 30,
onChanged: (a) {
setState(() {
_fontSize = (a.round()).toDouble();
});
},
),
Text(_fontSize.toString()),
],
),
],
),
],
),
),
Padding(
padding: EdgeInsets.all(20),
),
_tags2,
Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Divider(
color: Colors.blueGrey,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Text(_onPressed),
),
],
)),
])),
],
),
],
)),
);
}
Widget get _tags1 {
return Tags(
key: _tagStateKey,
symmetry: _symmetry,
columns: _column,
horizontalScroll: _horizontalScroll,
//verticalDirection: VerticalDirection.up, textDirection: TextDirection.rtl,
heightHorizontalScroll: 60 * (_fontSize / 14),
itemCount: _items.length,
itemBuilder: (index) {
final item = _items[index];
return ItemTags(
key: Key(index.toString()),
index: index,
title: item,
pressEnabled: true,
activeColor: Colors.blueGrey[600],
singleItem: _singleItem,
splashColor: Colors.green,
combine: ItemTagsCombine.withTextBefore,
image: index > 0 && index < 5
? ItemTagsImage(
//image: AssetImage("img/p$index.jpg"),
child: Image.network(
"http://www.clipartpanda.com/clipart_images/user-66327738/download",
width: 16 * _fontSize / 14,
height: 16 * _fontSize / 14,
))
: (1 == 1
? ItemTagsImage(
image: NetworkImage(
"https://d32ogoqmya1dw8.cloudfront.net/images/serc/empty_user_icon_256.v2.png"),
)
: null),
icon: (item == '0' || item == '1' || item == '2')
? ItemTagsIcon(
icon: _icon[int.parse(item)],
)
: null,
removeButton: _removeButton
? ItemTagsRemoveButton(
onRemoved: () {
setState(() {
_items.removeAt(index);
});
return true;
},
)
: null,
textScaleFactor:
utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1,
textStyle: TextStyle(
fontSize: _fontSize,
),
onPressed: (item) => print(item),
);
},
);
}
// Position for popup menu
Offset _tapPosition;
Widget get _tags2 {
//popup Menu
final RenderBox overlay = Overlay.of(context).context?.findRenderObject();
ItemTagsCombine combine = ItemTagsCombine.onlyText;
switch (_itemCombine) {
case 'onlyText':
combine = ItemTagsCombine.onlyText;
break;
case 'onlyIcon':
combine = ItemTagsCombine.onlyIcon;
break;
case 'onlyIcon':
combine = ItemTagsCombine.onlyIcon;
break;
case 'onlyImage':
combine = ItemTagsCombine.onlyImage;
break;
case 'imageOrIconOrText':
combine = ItemTagsCombine.imageOrIconOrText;
break;
case 'withTextAfter':
combine = ItemTagsCombine.withTextAfter;
break;
case 'withTextBefore':
combine = ItemTagsCombine.withTextBefore;
break;
}
return Tags(
key: Key("2"),
symmetry: _symmetry,
columns: _column,
horizontalScroll: _horizontalScroll,
verticalDirection:
_startDirection ? VerticalDirection.up : VerticalDirection.down,
textDirection: _startDirection ? TextDirection.rtl : TextDirection.ltr,
heightHorizontalScroll: 60 * (_fontSize / 14),
textField: _textField,
itemCount: _items.length,
itemBuilder: (index) {
final item = _items[index];
return GestureDetector(
child: ItemTags(
key: Key(index.toString()),
index: index,
title: item,
pressEnabled: false,
activeColor: Colors.green[400],
combine: combine,
image: index > 0 && index < 5
? ItemTagsImage(image: AssetImage("img/p$index.jpg"))
: (1 == 1
? ItemTagsImage(
image: NetworkImage(
"https://image.flaticon.com/icons/png/512/44/44948.png"))
: null),
icon: (item == '0' || item == '1' || item == '2')
? ItemTagsIcon(
icon: _icon[int.parse(item)],
)
: null,
removeButton: ItemTagsRemoveButton(
backgroundColor: Colors.green[900],
onRemoved: () {
setState(() {
_items.removeAt(index);
});
return true;
},
),
textScaleFactor:
utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1,
textStyle: TextStyle(
fontSize: _fontSize,
),
),
onTapDown: (details) => _tapPosition = details.globalPosition,
onLongPress: () {
showMenu(
//semanticLabel: item,
items: <PopupMenuEntry>[
PopupMenuItem(
child: Text(item, style: TextStyle(color: Colors.blueGrey)),
enabled: false,
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Row(
children: <Widget>[
Icon(Icons.content_copy),
Text("Copy text"),
],
),
),
],
context: context,
position: RelativeRect.fromRect(
_tapPosition & Size(40, 40),
Offset.zero &
overlay
.size) // & RelativeRect.fromLTRB(65.0, 40.0, 0.0, 0.0),
)
.then((value) {
if (value == 1) Clipboard.setData(ClipboardData(text: item));
});
},
);
},
);
}
TagsTextField get _textField {
return TagsTextField(
autofocus: false,
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 10),
textStyle: TextStyle(
fontSize: _fontSize,
//height: 1
),
enabled: true,
constraintSuggestion: true,
suggestions: _withSuggesttions
? [
"One",
"two",
"android",
"Dart",
"flutter",
"test",
"tests",
"androids",
"androidsaaa",
"Test",
"suggest",
"suggestions",
"互联网",
"last",
"lest",
"炫舞时代"
]
: null,
onSubmitted: (String str) {
setState(() {
_items.add(str);
});
},
);
}
List<DropdownMenuItem> _buildItems() {
List<DropdownMenuItem> list = [];
int count = 19;
list.add(
DropdownMenuItem(
child: Text("Not set"),
value: 0,
),
);
for (int i = 1; i < count; i++)
list.add(
DropdownMenuItem(
child: Text(i.toString()),
value: i,
),
);
return list;
}
List<DropdownMenuItem> _buildItems2() {
List<DropdownMenuItem> list = [];
list.add(DropdownMenuItem(
child: Text("onlyText"),
value: 'onlyText',
));
list.add(DropdownMenuItem(
child: Text("onlyIcon"),
value: 'onlyIcon',
));
list.add(DropdownMenuItem(
child: Text("onlyImage"),
value: 'onlyImage',
));
list.add(DropdownMenuItem(
child: Text("imageOrIconOrText"),
value: 'imageOrIconOrText',
));
list.add(DropdownMenuItem(
child: Text("withTextBefore"),
value: 'withTextBefore',
));
list.add(DropdownMenuItem(
child: Text("withTextAfter"),
value: 'withTextAfter',
));
return list;
}
}
================================================
FILE: example/pubspec.yaml
================================================
name: example_flutter_tags
description: A new Flutter application.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org.
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
flutter_tags:
path: ../
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- img/p1.jpg
- img/p2.jpg
- img/p3.jpg
- img/p4.jpg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
================================================
FILE: example/test/widget_test.dart
================================================
import 'package:flutter/material.dart';
void main() {}
================================================
FILE: flutter_tags.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/build" />
<excludeFolder url="file://$MODULE_DIR$/example/example_flutter_tags/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/example_flutter_tags/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/example_flutter_tags/build" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Flutter Plugins" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>
================================================
FILE: lib/flutter_tags.dart
================================================
library flutter_tags;
export 'src/suggestions_textfield.dart';
export 'src/item_tags.dart';
export 'src/tags.dart';
================================================
FILE: lib/src/item_tags.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_tags/src/tags.dart';
/// Used by [ItemTags.onPressed].
typedef OnPressedCallback = void Function(Item i);
/// Used by [ItemTags.OnLongPressed].
typedef OnLongPressedCallback = void Function(Item i);
/// Used by [ItemTags.removeButton.onRemoved].
typedef OnRemovedCallback = bool Function();
/// combines icon text or image
enum ItemTagsCombine {
onlyText,
onlyIcon,
onlyImage,
imageOrIconOrText,
withTextBefore,
withTextAfter
}
class ItemTags extends StatefulWidget {
ItemTags(
{@required this.index,
@required this.title,
this.textScaleFactor,
this.active = true,
this.pressEnabled = true,
this.customData,
this.textStyle = const TextStyle(fontSize: 14),
this.alignment = MainAxisAlignment.center,
this.combine = ItemTagsCombine.imageOrIconOrText,
this.icon,
this.image,
this.removeButton,
this.borderRadius,
this.border,
this.padding = const EdgeInsets.symmetric(horizontal: 7, vertical: 5),
this.elevation = 5,
this.singleItem = false,
this.textOverflow = TextOverflow.fade,
this.textColor = Colors.black,
this.textActiveColor = Colors.white,
this.color = Colors.white,
this.activeColor = Colors.blueGrey,
this.highlightColor,
this.splashColor,
this.colorShowDuplicate = Colors.red,
this.onPressed,
this.onLongPressed,
Key key})
: assert(index != null),
assert(title != null),
super(key: key);
/// Id of [ItemTags] - required
final int index;
/// Title of [ItemTags] - required
final String title;
/// Scale Factor of [ItemTags] - double
final double textScaleFactor;
/// Initial bool value
final bool active;
/// Initial bool value
final bool pressEnabled;
/// Possibility to add any custom value in customData field, you can retrieve this later. A good example: store an id from Firestore document.
final dynamic customData;
/// ItemTagsCombine (text,icon,textIcon,textImage) of [ItemTags]
final ItemTagsCombine combine;
/// Icon of [ItemTags]
final ItemTagsIcon icon;
/// Image of [ItemTags]
final ItemTagsImage image;
/// Custom Remove Button of [ItemTags]
final ItemTagsRemoveButton removeButton;
/// TextStyle of the [ItemTags]
final TextStyle textStyle;
/// TextStyle of the [ItemTags]
final MainAxisAlignment alignment;
/// border-radius of [ItemTags]
final BorderRadius borderRadius;
/// custom border-side of [ItemTags]
final BoxBorder border;
/// padding of the [ItemTags]
final EdgeInsets padding;
/// BoxShadow of the [ItemTags]
final double elevation;
/// when you want only one tag selected. same radio-button
final bool singleItem;
/// type of text overflow within the [ItemTags]
final TextOverflow textOverflow;
/// text color of the [ItemTags]
final Color textColor;
/// color of the [ItemTags] text activated
final Color textActiveColor;
/// background color [ItemTags]
final Color color;
/// background color [ItemTags] activated
final Color activeColor;
/// highlight Color [ItemTags]
final Color highlightColor;
/// Splash color [ItemTags]
final Color splashColor;
/// Color show duplicate [ItemTags]
final Color colorShowDuplicate;
/// callback
final OnPressedCallback onPressed;
/// callback
final OnLongPressedCallback onLongPressed;
@override
_ItemTagsState createState() => _ItemTagsState();
}
class _ItemTagsState extends State<ItemTags> {
final double _initBorderRadius = 50;
DataListInherited _dataListInherited;
DataList _dataList;
void _setDataList() {
// Get List<DataList> from Tags widget
_dataListInherited = DataListInherited.of(context);
// set List length
if (_dataListInherited.list.length < _dataListInherited.itemCount)
_dataListInherited.list.length = _dataListInherited.itemCount;
if (_dataListInherited.list.length > (widget.index + 1) &&
_dataListInherited.list.elementAt(widget.index) != null &&
_dataListInherited.list.elementAt(widget.index).title != widget.title) {
// when an element is removed from the data source
_dataListInherited.list.removeAt(widget.index);
// when all item list changed in data source
if (_dataListInherited.list.elementAt(widget.index) != null &&
_dataListInherited.list.elementAt(widget.index).title != widget.title)
_dataListInherited.list
.removeRange(widget.index, _dataListInherited.list.length);
}
// add new Item in the List
if (_dataListInherited.list.length < (widget.index + 1)) {
//print("add");
_dataListInherited.list.insert(
widget.index,
DataList(
title: widget.title,
index: widget.index,
active: widget.singleItem ? false : widget.active,
customData: widget.customData));
} else if (_dataListInherited.list.elementAt(widget.index) == null) {
//print("replace");
_dataListInherited.list[widget.index] = DataList(
title: widget.title,
index: widget.index,
active: widget.singleItem ? false : widget.active,
customData: widget.customData);
}
// removes items that have been orphaned
if (_dataListInherited.itemCount == widget.index + 1 &&
_dataListInherited.list.length > _dataListInherited.itemCount)
_dataListInherited.list
.removeRange(widget.index + 1, _dataListInherited.list.length);
//print(_dataListInherited.list.length);
// update Listener
if (_dataList != null) _dataList.removeListener(_didValueChange);
_dataList = _dataListInherited.list.elementAt(widget.index);
_dataList.addListener(_didValueChange);
}
_didValueChange() => setState(() {});
@override
void dispose() {
_dataList.removeListener(_didValueChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
_setDataList();
final double fontSize = widget.textStyle.fontSize;
Color color = _dataList.active ? widget.activeColor : widget.color;
if (_dataList.showDuplicate) color = widget.colorShowDuplicate;
return Material(
color: color,
borderRadius:
widget.borderRadius ?? BorderRadius.circular(_initBorderRadius),
elevation: widget.elevation,
//shadowColor: _dataList.highlights? Colors.red : Colors.blue,
child: InkWell(
borderRadius:
widget.borderRadius ?? BorderRadius.circular(_initBorderRadius),
highlightColor:
widget.pressEnabled ? widget.highlightColor : Colors.transparent,
splashColor:
widget.pressEnabled ? widget.splashColor : Colors.transparent,
child: Container(
decoration: BoxDecoration(
border: widget.border ??
Border.all(color: widget.activeColor, width: 0.5),
borderRadius: widget.borderRadius ??
BorderRadius.circular(_initBorderRadius)),
padding: widget.padding * (fontSize / 14),
child: _combine),
onTap: widget.pressEnabled
? () {
if (widget.singleItem) {
_singleItem(_dataListInherited, _dataList);
_dataList.active = true;
} else
_dataList.active = !_dataList.active;
if (widget.onPressed != null)
widget.onPressed(Item(
index: widget.index,
title: _dataList.title,
active: _dataList.active,
customData: widget.customData));
}
: null,
onLongPress: widget.onLongPressed != null
? () => widget.onLongPressed(Item(
index: widget.index,
title: _dataList.title,
active: _dataList.active,
customData: widget.customData))
: null,
),
);
}
Widget get _combine {
if (widget.image != null)
assert((widget.image.image != null && widget.image.child == null) ||
(widget.image.child != null && widget.image.image == null));
final Widget text = Text(
widget.title,
softWrap: false,
textAlign: _textAlignment,
overflow: widget.textOverflow,
textScaleFactor: widget.textScaleFactor,
style: _textStyle,
);
final Widget icon = widget.icon != null
? Container(
padding: widget.icon.padding ??
(widget.combine == ItemTagsCombine.onlyIcon ||
widget.combine == ItemTagsCombine.imageOrIconOrText
? null
: widget.combine == ItemTagsCombine.withTextAfter
? EdgeInsets.only(right: 5)
: EdgeInsets.only(left: 5)),
child: Icon(
widget.icon.icon,
color: _textStyle.color,
size: _textStyle.fontSize * 1.2,
),
)
: text;
final Widget image = widget.image != null
? Container(
padding: widget.image.padding ??
(widget.combine == ItemTagsCombine.onlyImage ||
widget.combine == ItemTagsCombine.imageOrIconOrText
? null
: widget.combine == ItemTagsCombine.withTextAfter
? EdgeInsets.only(right: 5)
: EdgeInsets.only(left: 5)),
child: widget.image.child ??
CircleAvatar(
radius:
widget.image.radius * (widget.textStyle.fontSize / 14),
backgroundColor: Colors.transparent,
backgroundImage: widget.image.image,
),
)
: text;
final List list = List();
switch (widget.combine) {
case ItemTagsCombine.onlyText:
list.add(text);
break;
case ItemTagsCombine.onlyIcon:
list.add(icon);
break;
case ItemTagsCombine.onlyImage:
list.add(image);
break;
case ItemTagsCombine.imageOrIconOrText:
list.add((image != text ? image : icon));
break;
case ItemTagsCombine.withTextBefore:
list.add(text);
if (image != text)
list.add(image);
else if (icon != text) list.add(icon);
break;
case ItemTagsCombine.withTextAfter:
if (image != text)
list.add(image);
else if (icon != text) list.add(icon);
list.add(text);
}
final Widget row = Row(
mainAxisAlignment: widget.alignment,
mainAxisSize: MainAxisSize.min,
children: List.generate(list.length, (i) {
if (i == 0 && list.length > 1)
return Flexible(
flex: widget.combine == ItemTagsCombine.withTextAfter ? 0 : 1,
child: list[i],
);
return Flexible(
flex: widget.combine == ItemTagsCombine.withTextAfter ||
list.length == 1
? 1
: 0,
child: list[i],
);
}));
if (widget.removeButton != null)
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
fit:
_dataListInherited.symmetry ? FlexFit.tight : FlexFit.loose,
flex: 2,
child: row),
Flexible(
flex: 0,
child: FittedBox(
alignment: Alignment.centerRight,
fit: BoxFit.fill,
child: GestureDetector(
child: Container(
margin: widget.removeButton.margin ??
EdgeInsets.only(left: 5),
padding:
(widget.removeButton.padding ?? EdgeInsets.all(2)) *
(widget.textStyle.fontSize / 14),
decoration: BoxDecoration(
color: widget.removeButton.backgroundColor ??
Colors.black,
borderRadius: widget.removeButton.borderRadius ??
BorderRadius.circular(_initBorderRadius),
),
child: widget.removeButton.padding ??
Icon(
Icons.clear,
color: widget.removeButton.color ?? Colors.white,
size: (widget.removeButton.size ?? 12) *
(widget.textStyle.fontSize / 14),
),
),
onTap: () {
if (widget.removeButton.onRemoved != null) {
if (widget.removeButton.onRemoved())
_dataListInherited.list.removeAt(widget.index);
}
},
)))
]);
return row;
}
///Text Alignment
TextAlign get _textAlignment {
switch (widget.alignment) {
case MainAxisAlignment.spaceBetween:
case MainAxisAlignment.start:
return TextAlign.start;
break;
case MainAxisAlignment.end:
return TextAlign.end;
break;
case MainAxisAlignment.spaceAround:
case MainAxisAlignment.spaceEvenly:
case MainAxisAlignment.center:
return TextAlign.center;
}
return null;
}
///TextStyle
TextStyle get _textStyle {
return widget.textStyle.apply(
color: _dataList.active ? widget.textActiveColor : widget.textColor,
);
}
/// Single item selection
void _singleItem(DataListInherited dataSetIn, DataList dataSet) {
dataSetIn.list
.where((tg) => tg != null)
.where((tg) => tg.active)
.where((tg2) => tg2 != dataSet)
.forEach((tg) => tg.active = false);
}
}
///callback
class Item {
Item({this.index, this.title, this.active, this.customData});
final int index;
final String title;
final bool active;
final dynamic customData;
@override
String toString() {
return "id:$index, title: $title, active: $active, customData: $customData";
}
}
/// ItemTag Image
class ItemTagsImage {
ItemTagsImage({this.radius = 8, this.padding, this.image, this.child});
final double radius;
final EdgeInsets padding;
final ImageProvider image;
final Widget child;
}
/// ItemTag Icon
class ItemTagsIcon {
ItemTagsIcon({this.padding, @required this.icon});
final EdgeInsets padding;
final IconData icon;
}
/// ItemTag RemoveButton
class ItemTagsRemoveButton {
ItemTagsRemoveButton(
{this.icon,
this.size,
this.backgroundColor,
this.color,
this.borderRadius,
this.padding,
this.margin,
this.onRemoved});
final IconData icon;
final double size;
final Color backgroundColor;
final Color color;
final BorderRadius borderRadius;
final EdgeInsets padding;
final EdgeInsets margin;
/// callback
final OnRemovedCallback onRemoved;
}
================================================
FILE: lib/src/suggestions_textfield.dart
================================================
import 'package:flutter/material.dart';
// InputSuggestions version 0.0.1
// currently yield inline suggestions
// I will soon implement a list with suggestions
// Credit Dn-a -> https://github.com/Dn-a
/// Used by [SuggestionsTextField.onChanged].
typedef OnChangedCallback = void Function(String string);
/// Used by [SuggestionsTextField.onSubmitted].
typedef OnSubmittedCallback = void Function(String string);
class SuggestionsTextField extends StatefulWidget {
SuggestionsTextField(
{@required this.tagsTextField, this.onSubmitted, Key key})
: assert(tagsTextField != null),
super(key: key);
final TagsTextField tagsTextField;
final OnSubmittedCallback onSubmitted;
@override
_SuggestionsTextFieldState createState() => _SuggestionsTextFieldState();
}
class _SuggestionsTextFieldState extends State<SuggestionsTextField> {
final _controller = TextEditingController();
List<String> _matches = List();
String _helperText;
bool _helperCheck = true;
List<String> _suggestions;
bool _constraintSuggestion;
double _fontSize;
InputDecoration _inputDecoration;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
_helperText = widget.tagsTextField.helperText ?? "no matches";
_suggestions = widget.tagsTextField.suggestions;
_constraintSuggestion = widget.tagsTextField.constraintSuggestion;
_inputDecoration = widget.tagsTextField.inputDecoration;
_fontSize = widget.tagsTextField.textStyle.fontSize;
return Stack(
alignment: Alignment.centerLeft,
children: <Widget>[
Visibility(
visible: _suggestions != null,
child: Container(
//width: double.infinity,
padding: _inputDecoration != null
? _inputDecoration.contentPadding
: EdgeInsets.symmetric(
vertical: 6 * (_fontSize / 14),
horizontal: 6 * (_fontSize / 14)),
child: Text(
_matches.isNotEmpty ? (_matches.first) : "",
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(
height: widget.tagsTextField.textStyle.height == null
? 1
: widget.tagsTextField.textStyle.height,
fontSize: _fontSize ?? null,
color: widget.tagsTextField.suggestionTextColor ?? Colors.red,
),
),
),
),
TextField(
controller: _controller,
enabled: widget.tagsTextField.enabled,
autofocus: widget.tagsTextField.autofocus ?? true,
keyboardType: widget.tagsTextField.keyboardType ?? null,
textCapitalization: widget.tagsTextField.textCapitalization ??
TextCapitalization.none,
maxLength: widget.tagsTextField.maxLength ?? null,
maxLines: 1,
autocorrect: widget.tagsTextField.autocorrect ?? false,
style: widget.tagsTextField.textStyle.copyWith(
height: widget.tagsTextField.textStyle.height == null ? 1 : null),
decoration: _initialInputDecoration,
onChanged: (str) => _checkOnChanged(str),
onSubmitted: (str) => _onSubmitted(str),
)
],
);
}
InputDecoration get _initialInputDecoration {
var input = _inputDecoration ??
InputDecoration(
disabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
vertical: 6 * (_fontSize / 14),
horizontal: 6 * (_fontSize / 14)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.blueGrey[300],
),
),
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.blueGrey[400].withOpacity(0.3)),
),
border: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.blueGrey[400].withOpacity(0.3)),
));
return input.copyWith(
helperText: _helperCheck || _suggestions == null ? null : _helperText,
helperStyle: widget.tagsTextField.helperTextStyle,
hintText: widget.tagsTextField.hintText ?? 'Add a tag',
hintStyle: TextStyle(color: widget.tagsTextField.hintTextColor));
}
///OnSubmitted
void _onSubmitted(String str) {
var onSubmitted = widget.onSubmitted;
if (_suggestions != null && _matches.isNotEmpty) str = _matches.first;
if (widget.tagsTextField.lowerCase) str = str.toLowerCase();
str = str.trim();
if (_suggestions != null) {
if (_matches.isNotEmpty || !_constraintSuggestion) {
if (onSubmitted != null) onSubmitted(str);
setState(() {
_matches = [];
});
_controller.clear();
}
} else if (str.isNotEmpty) {
if (onSubmitted != null) onSubmitted(str);
_controller.clear();
}
}
///Check onChanged
void _checkOnChanged(String str) {
if (_suggestions != null) {
_matches =
_suggestions.where((String sgt) => sgt.startsWith(str)).toList();
if (str.isEmpty) _matches = [];
if (_matches.length > 1) _matches.removeWhere((String mtc) => mtc == str);
setState(() {
_helperCheck =
_matches.isNotEmpty || str.isEmpty || !_constraintSuggestion
? true
: false;
_matches.sort((a, b) => a.compareTo(b));
});
}
if (widget.tagsTextField.onChanged != null)
widget.tagsTextField.onChanged(str);
}
}
/// Tags TextField
class TagsTextField {
TagsTextField(
{this.lowerCase = false,
this.textStyle = const TextStyle(fontSize: 14),
this.width = 200,
this.padding,
this.enabled = true,
this.duplicates = false,
this.suggestions,
this.constraintSuggestion = true,
this.autocorrect,
this.autofocus,
this.hintText,
this.hintTextColor,
this.suggestionTextColor,
this.helperText,
this.helperTextStyle,
this.keyboardType,
this.textCapitalization,
this.maxLength,
this.inputDecoration,
this.onSubmitted,
this.onChanged});
final double width;
final EdgeInsets padding;
final bool enabled;
final bool duplicates;
final TextStyle textStyle;
final InputDecoration inputDecoration;
final bool autocorrect;
final List<String> suggestions;
/// Allows you to insert tags not present in the list of suggestions
final bool constraintSuggestion;
final bool lowerCase;
final bool autofocus;
final String hintText;
final Color hintTextColor;
final Color suggestionTextColor;
final String helperText;
final TextStyle helperTextStyle;
final TextInputType keyboardType;
final TextCapitalization textCapitalization;
final int maxLength;
final OnSubmittedCallback onSubmitted;
final OnChangedCallback onChanged;
}
================================================
FILE: lib/src/tags.dart
================================================
import 'package:flutter/material.dart';
import '../flutter_tags.dart';
import 'util/custom_wrap.dart';
import 'package:flutter_tags/src/suggestions_textfield.dart';
///ItemBuilder
typedef Widget ItemBuilder(int index);
class Tags extends StatefulWidget {
Tags(
{this.columns,
this.itemCount = 0,
this.symmetry = false,
this.horizontalScroll = false,
this.heightHorizontalScroll = 60,
this.spacing = 6,
this.runSpacing = 14,
this.alignment = WrapAlignment.center,
this.runAlignment = WrapAlignment.center,
this.direction = Axis.horizontal,
this.verticalDirection = VerticalDirection.down,
this.textDirection = TextDirection.ltr,
this.itemBuilder,
this.textField,
Key key})
: assert(itemCount >= 0),
assert(alignment != null),
assert(runAlignment != null),
assert(direction != null),
assert(verticalDirection != null),
assert(textDirection != null),
super(key: key);
///specific number of columns
final int columns;
///numer of item List
final int itemCount;
/// imposes the same width and the same number of columns for each row
final bool symmetry;
/// ability to scroll tags horizontally
final bool horizontalScroll;
/// horizontal spacing of the [ItemTags]
final double heightHorizontalScroll;
/// horizontal spacing of the [ItemTags]
final double spacing;
/// vertical spacing of the [ItemTags]
final double runSpacing;
/// horizontal alignment of the [ItemTags]
final WrapAlignment alignment;
/// vertical alignment of the [ItemTags]
final WrapAlignment runAlignment;
/// direction of the [ItemTags]
final Axis direction;
/// Iterate [Item] from the lower to the upper direction or vice versa
final VerticalDirection verticalDirection;
/// Text direction of the [ItemTags]
final TextDirection textDirection;
/// Generates a list of [ItemTags].
///
/// Creates a list with [length] positions and fills it with values created by
/// calling [generator] for each index in the range `0` .. `length - 1`
/// in increasing order.
final ItemBuilder itemBuilder;
/// custom TextField
final TagsTextField textField;
@override
TagsState createState() => TagsState();
}
class TagsState extends State<Tags> {
final GlobalKey _containerKey = GlobalKey();
Orientation _orientation = Orientation.portrait;
double _width = 0;
final List<DataList> _list = List();
List<Item> get getAllItem => _list.toList();
//get the current width of the screen
void _getWidthContext() {
WidgetsBinding.instance.addPostFrameCallback((_) {
final keyContext = _containerKey.currentContext;
if (keyContext != null) {
final RenderBox box = keyContext.findRenderObject();
final size = box.size;
setState(() {
_width = size.width;
});
}
});
}
@override
Widget build(BuildContext context) {
// essential to avoid infinite loop of addPostFrameCallback
if (widget.symmetry &&
(MediaQuery.of(context).orientation != _orientation || _width == 0)) {
_orientation = MediaQuery.of(context).orientation;
_getWidthContext();
}
Widget child;
if (widget.horizontalScroll && !widget.symmetry)
child = Container(
height: widget.heightHorizontalScroll,
color: Colors.transparent,
child: ListView(
padding: EdgeInsets.all(0),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
physics: ClampingScrollPhysics(),
children: _buildItems(),
),
);
else
child = CustomWrap(
key: _containerKey,
alignment: widget.alignment,
runAlignment: widget.runAlignment,
spacing: widget.spacing,
runSpacing: widget.runSpacing,
column: widget.columns,
symmetry: widget.symmetry,
textDirection: widget.textDirection,
direction: widget.direction,
verticalDirection: widget.verticalDirection,
crossAxisAlignment: WrapCrossAlignment.end,
children: _buildItems(),
);
return DataListInherited(
list: _list,
symmetry: widget.symmetry,
itemCount: widget.itemCount,
child: child,
);
}
List<Widget> _buildItems() {
/*if(_list.length < widget.itemCount)
_list.clear();*/
final Widget textField = widget.textField != null
? Container(
alignment: Alignment.center,
width: widget.symmetry ? _widthCalc() : widget.textField.width,
padding: widget.textField.padding,
child: SuggestionsTextField(
tagsTextField: widget.textField,
onSubmitted: (String str) {
if (!widget.textField.duplicates) {
final List<DataList> lst =
_list.where((l) => l.title == str).toList();
if (lst.isNotEmpty) {
lst.forEach((d) => d.showDuplicate = true);
return;
}
}
if (widget.textField.onSubmitted != null)
widget.textField.onSubmitted(str);
},
),
)
: null;
List<Widget> finalList = List();
List<Widget> itemList = List.generate(widget.itemCount, (i) {
final Widget item = widget.itemBuilder(i);
if (widget.symmetry)
return Container(
width: _widthCalc(),
child: item,
);
else if (widget.horizontalScroll)
return Container(
margin: EdgeInsets.symmetric(horizontal: widget.spacing),
alignment: Alignment.center,
child: item,
);
return item;
});
if (widget.horizontalScroll && widget.textDirection == TextDirection.rtl)
itemList = itemList.reversed.toList();
if (textField == null) {
finalList.addAll(itemList);
return finalList;
}
if (widget.horizontalScroll &&
widget.verticalDirection == VerticalDirection.up) {
finalList.add(textField);
finalList.addAll(itemList);
} else {
finalList.addAll(itemList);
finalList.add(textField);
}
return finalList;
}
//Container width divided by the number of columns when symmetry is active
double _widthCalc() {
int columns = widget.columns ?? 0;
int margin = widget.spacing.round();
int subtraction = columns * (margin);
double width = (_width > 1) ? (_width - subtraction) / columns : _width;
return width;
}
}
/// Inherited Widget
class DataListInherited extends InheritedWidget {
DataListInherited(
{Key key, this.list, this.symmetry, this.itemCount, Widget child})
: super(key: key, child: child);
final List<DataList> list;
final bool symmetry;
final int itemCount;
@override
bool updateShouldNotify(DataListInherited old) {
//print("inherited");
return false;
}
/*static DataListInherited of(BuildContext context) =>
context.inheritFromWidgetOfExactType(DataListInherited);*/
static DataListInherited of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType();
}
/// Data List
class DataList extends ValueNotifier implements Item {
DataList(
{@required this.title,
this.index,
bool highlights = false,
bool active = true,
this.customData})
: _showDuplicate = highlights,
_active = active,
super(active);
final String title;
final dynamic customData;
final int index;
get showDuplicate {
final val = _showDuplicate;
_showDuplicate = false;
return val;
}
bool _showDuplicate;
set showDuplicate(bool a) {
_showDuplicate = a;
// rebuild only the specific Item that changes its value
notifyListeners();
}
get active => _active;
bool _active;
set active(bool a) {
_active = a;
// rebuild only the specific Item that changes its value
notifyListeners();
}
}
================================================
FILE: lib/src/util/custom_wrap.dart
================================================
import 'dart:math' as math;
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
/// Custom Wrap
class CustomWrap extends MultiChildRenderObjectWidget {
CustomWrap({
Key key,
this.column,
this.symmetry,
this.direction = Axis.horizontal,
this.alignment = WrapAlignment.start,
this.spacing = 0.0,
this.runAlignment = WrapAlignment.start,
this.runSpacing = 0.0,
this.crossAxisAlignment = WrapCrossAlignment.start,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
List<Widget> children = const <Widget>[],
}) : super(key: key, children: children);
final int column;
final bool symmetry;
final Axis direction;
final WrapAlignment alignment;
final double spacing;
final WrapAlignment runAlignment;
final double runSpacing;
final WrapCrossAlignment crossAxisAlignment;
final TextDirection textDirection;
final VerticalDirection verticalDirection;
@override
CustomRenderWrap createRenderObject(BuildContext context) {
return CustomRenderWrap(
column: column,
symmetry: symmetry,
direction: direction,
alignment: alignment,
spacing: spacing,
runAlignment: runAlignment,
runSpacing: runSpacing,
crossAxisAlignment: crossAxisAlignment,
textDirection: textDirection ?? Directionality.of(context),
verticalDirection: verticalDirection,
);
}
@override
void updateRenderObject(BuildContext context, CustomRenderWrap renderObject) {
renderObject
..column = column
..symmetry = symmetry
..direction = direction
..alignment = alignment
..spacing = spacing
..runAlignment = runAlignment
..runSpacing = runSpacing
..crossAxisAlignment = crossAxisAlignment
..textDirection = textDirection ?? Directionality.of(context)
..verticalDirection = verticalDirection;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(EnumProperty<Axis>('direction', direction));
properties.add(EnumProperty<WrapAlignment>('alignment', alignment));
properties.add(DoubleProperty('spacing', spacing));
properties.add(EnumProperty<WrapAlignment>('runAlignment', runAlignment));
properties.add(DoubleProperty('runSpacing', runSpacing));
properties.add(DoubleProperty('crossAxisAlignment', runSpacing));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection,
defaultValue: null));
properties.add(EnumProperty<VerticalDirection>(
'verticalDirection', verticalDirection,
defaultValue: VerticalDirection.down));
}
}
/// Displays its children in multiple horizontal or vertical runs.
class CustomRenderWrap extends RenderBox
with
ContainerRenderObjectMixin<RenderBox, WrapParentData>,
RenderBoxContainerDefaultsMixin<RenderBox, WrapParentData> {
CustomRenderWrap({
List<RenderBox> children,
int column,
bool symmetry,
Axis direction = Axis.horizontal,
WrapAlignment alignment = WrapAlignment.start,
double spacing = 0.0,
WrapAlignment runAlignment = WrapAlignment.start,
double runSpacing = 0.0,
WrapCrossAlignment crossAxisAlignment = WrapCrossAlignment.start,
TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
}) : assert(direction != null),
assert(alignment != null),
assert(spacing != null),
assert(runAlignment != null),
assert(runSpacing != null),
assert(crossAxisAlignment != null),
_column = column,
_symmetry = symmetry,
_direction = direction,
_alignment = alignment,
_spacing = spacing,
_runAlignment = runAlignment,
_runSpacing = runSpacing,
_crossAxisAlignment = crossAxisAlignment,
_textDirection = textDirection,
_verticalDirection = verticalDirection {
addAll(children);
}
int get column => _column;
int _column;
set column(int value) {
if (column == value) return;
_column = value;
markNeedsLayout();
}
bool get symmetry => _symmetry;
bool _symmetry;
set symmetry(bool value) {
if (symmetry == value) return;
_symmetry = value;
markNeedsLayout();
}
Axis get direction => _direction;
Axis _direction;
set direction(Axis value) {
assert(value != null);
if (_direction == value) return;
_direction = value;
markNeedsLayout();
}
WrapAlignment get alignment => _alignment;
WrapAlignment _alignment;
set alignment(WrapAlignment value) {
assert(value != null);
if (_alignment == value) return;
_alignment = value;
markNeedsLayout();
}
double get spacing => _spacing;
double _spacing;
set spacing(double value) {
assert(value != null);
if (_spacing == value) return;
_spacing = value;
markNeedsLayout();
}
WrapAlignment get runAlignment => _runAlignment;
WrapAlignment _runAlignment;
set runAlignment(WrapAlignment value) {
assert(value != null);
if (_runAlignment == value) return;
_runAlignment = value;
markNeedsLayout();
}
double get runSpacing => _runSpacing;
double _runSpacing;
set runSpacing(double value) {
assert(value != null);
if (_runSpacing == value) return;
_runSpacing = value;
markNeedsLayout();
}
WrapCrossAlignment get crossAxisAlignment => _crossAxisAlignment;
WrapCrossAlignment _crossAxisAlignment;
set crossAxisAlignment(WrapCrossAlignment value) {
assert(value != null);
if (_crossAxisAlignment == value) return;
_crossAxisAlignment = value;
markNeedsLayout();
}
TextDirection get textDirection => _textDirection;
TextDirection _textDirection;
set textDirection(TextDirection value) {
if (_textDirection != value) {
_textDirection = value;
markNeedsLayout();
}
}
VerticalDirection get verticalDirection => _verticalDirection;
VerticalDirection _verticalDirection;
set verticalDirection(VerticalDirection value) {
if (_verticalDirection != value) {
_verticalDirection = value;
markNeedsLayout();
}
}
bool get _debugHasNecessaryDirections {
assert(direction != null);
assert(alignment != null);
assert(runAlignment != null);
assert(crossAxisAlignment != null);
if (firstChild != null && lastChild != firstChild) {
// i.e. there's more than one child
switch (direction) {
case Axis.horizontal:
assert(textDirection != null,
'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.');
break;
case Axis.vertical:
assert(verticalDirection != null,
'Vertical $runtimeType with multiple children has a null verticalDirection, so the layout order is undefined.');
break;
}
}
if (alignment == WrapAlignment.start || alignment == WrapAlignment.end) {
switch (direction) {
case Axis.horizontal:
assert(textDirection != null,
'Horizontal $runtimeType with alignment $alignment has a null textDirection, so the alignment cannot be resolved.');
break;
case Axis.vertical:
assert(verticalDirection != null,
'Vertical $runtimeType with alignment $alignment has a null verticalDirection, so the alignment cannot be resolved.');
break;
}
}
if (runAlignment == WrapAlignment.start ||
runAlignment == WrapAlignment.end) {
switch (direction) {
case Axis.horizontal:
assert(verticalDirection != null,
'Horizontal $runtimeType with runAlignment $runAlignment has a null verticalDirection, so the alignment cannot be resolved.');
break;
case Axis.vertical:
assert(textDirection != null,
'Vertical $runtimeType with runAlignment $runAlignment has a null textDirection, so the alignment cannot be resolved.');
break;
}
}
if (crossAxisAlignment == WrapCrossAlignment.start ||
crossAxisAlignment == WrapCrossAlignment.end) {
switch (direction) {
case Axis.horizontal:
assert(verticalDirection != null,
'Horizontal $runtimeType with crossAxisAlignment $crossAxisAlignment has a null verticalDirection, so the alignment cannot be resolved.');
break;
case Axis.vertical:
assert(textDirection != null,
'Vertical $runtimeType with crossAxisAlignment $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.');
break;
}
}
return true;
}
@override
void setupParentData(RenderBox child) {
if (child.parentData is! WrapParentData)
child.parentData = WrapParentData();
}
double _computeIntrinsicHeightForWidth(double width) {
assert(direction == Axis.horizontal);
int runCount = 0;
double height = 0.0;
double runWidth = 0.0;
double runHeight = 0.0;
int childCount = 0;
RenderBox child = firstChild;
while (child != null) {
final double childWidth = child.getMaxIntrinsicWidth(double.infinity);
final double childHeight = child.getMaxIntrinsicHeight(childWidth);
if (runWidth + childWidth > width) {
height += runHeight;
if (runCount > 0) height += runSpacing;
runCount += 1;
runWidth = 0.0;
runHeight = 0.0;
childCount = 0;
}
runWidth += childWidth;
runHeight = math.max(runHeight, childHeight);
if (childCount > 0) runWidth += spacing;
childCount += 1;
child = childAfter(child);
}
if (childCount > 0) height += runHeight + runSpacing;
return height;
}
double _computeIntrinsicWidthForHeight(double height) {
assert(direction == Axis.vertical);
int runCount = 0;
double width = 0.0;
double runHeight = 0.0;
double runWidth = 0.0;
int childCount = 0;
RenderBox child = firstChild;
while (child != null) {
final double childHeight = child.getMaxIntrinsicHeight(double.infinity);
final double childWidth = child.getMaxIntrinsicWidth(childHeight);
if (runHeight + childHeight > height) {
width += runWidth;
if (runCount > 0) width += runSpacing;
runCount += 1;
runHeight = 0.0;
runWidth = 0.0;
childCount = 0;
}
runHeight += childHeight;
runWidth = math.max(runWidth, childWidth);
if (childCount > 0) runHeight += spacing;
childCount += 1;
child = childAfter(child);
}
if (childCount > 0) width += runWidth + runSpacing;
return width;
}
@override
double computeMinIntrinsicWidth(double height) {
switch (direction) {
case Axis.horizontal:
double width = 0.0;
RenderBox child = firstChild;
while (child != null) {
width = math.max(width, child.getMinIntrinsicWidth(double.infinity));
child = childAfter(child);
}
return width;
case Axis.vertical:
return _computeIntrinsicWidthForHeight(height);
}
return null;
}
@override
double computeMaxIntrinsicWidth(double height) {
switch (direction) {
case Axis.horizontal:
double width = 0.0;
RenderBox child = firstChild;
while (child != null) {
width += child.getMaxIntrinsicWidth(double.infinity);
child = childAfter(child);
}
return width;
case Axis.vertical:
return _computeIntrinsicWidthForHeight(height);
}
return null;
}
@override
double computeMinIntrinsicHeight(double width) {
switch (direction) {
case Axis.horizontal:
return _computeIntrinsicHeightForWidth(width);
case Axis.vertical:
double height = 0.0;
RenderBox child = firstChild;
while (child != null) {
height =
math.max(height, child.getMinIntrinsicHeight(double.infinity));
child = childAfter(child);
}
return height;
}
return null;
}
@override
double computeMaxIntrinsicHeight(double width) {
switch (direction) {
case Axis.horizontal:
return _computeIntrinsicHeightForWidth(width);
case Axis.vertical:
double height = 0.0;
RenderBox child = firstChild;
while (child != null) {
height += child.getMaxIntrinsicHeight(double.infinity);
child = childAfter(child);
}
return height;
}
return null;
}
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
return defaultComputeDistanceToHighestActualBaseline(baseline);
}
double _getMainAxisExtent(RenderBox child) {
switch (direction) {
case Axis.horizontal:
return child.size.width;
case Axis.vertical:
return child.size.height;
}
return 0.0;
}
double _getCrossAxisExtent(RenderBox child) {
switch (direction) {
case Axis.horizontal:
return child.size.height;
case Axis.vertical:
return child.size.width;
}
return 0.0;
}
Offset _getOffset(double mainAxisOffset, double crossAxisOffset) {
switch (direction) {
case Axis.horizontal:
return Offset(mainAxisOffset, crossAxisOffset);
case Axis.vertical:
return Offset(crossAxisOffset, mainAxisOffset);
}
return Offset.zero;
}
double _getChildCrossAxisOffset(bool flipCrossAxis, double runCrossAxisExtent,
double childCrossAxisExtent) {
final double freeSpace = runCrossAxisExtent - childCrossAxisExtent;
switch (crossAxisAlignment) {
case WrapCrossAlignment.start:
return flipCrossAxis ? freeSpace : 0.0;
case WrapCrossAlignment.end:
return flipCrossAxis ? 0.0 : freeSpace;
case WrapCrossAlignment.center:
return freeSpace / 2.0;
}
return 0.0;
}
bool _hasVisualOverflow = false;
@override
void performLayout() {
assert(_debugHasNecessaryDirections);
_hasVisualOverflow = false;
RenderBox child = firstChild;
if (child == null) {
size = constraints.smallest;
return;
}
BoxConstraints childConstraints;
double mainAxisLimit = 0.0;
bool flipMainAxis = false;
bool flipCrossAxis = false;
switch (direction) {
case Axis.horizontal:
childConstraints = BoxConstraints(maxWidth: constraints.maxWidth);
mainAxisLimit = constraints.maxWidth;
if (textDirection == TextDirection.rtl) flipMainAxis = true;
if (verticalDirection == VerticalDirection.up) flipCrossAxis = true;
break;
case Axis.vertical:
childConstraints = BoxConstraints(maxHeight: constraints.maxHeight);
mainAxisLimit = constraints.maxHeight;
if (verticalDirection == VerticalDirection.up) flipMainAxis = true;
if (textDirection == TextDirection.rtl) flipCrossAxis = true;
break;
}
assert(childConstraints != null);
assert(mainAxisLimit != null);
final double spacing = this.spacing;
final double runSpacing = this.runSpacing;
final List<_RunMetrics> runMetrics = <_RunMetrics>[];
double mainAxisExtent = 0.0;
double crossAxisExtent = 0.0;
double runMainAxisExtent = 0.0;
double runCrossAxisExtent = 0.0;
int childCount = 0;
int cnt = 0;
while (child != null) {
child.layout(childConstraints, parentUsesSize: true);
final double childMainAxisExtent = _getMainAxisExtent(child);
final double childCrossAxisExtent = _getCrossAxisExtent(child);
if ((childCount > 0 &&
runMainAxisExtent + spacing + childMainAxisExtent >
mainAxisLimit) ||
(_column != null && _column != 0 && cnt == _column)) {
cnt = 0;
mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent);
crossAxisExtent += runCrossAxisExtent;
if (runMetrics.isNotEmpty) crossAxisExtent += runSpacing;
runMetrics.add(
_RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount));
runMainAxisExtent = 0.0;
runCrossAxisExtent = 0.0;
childCount = 0;
}
cnt++;
runMainAxisExtent += childMainAxisExtent;
if (childCount > 0) runMainAxisExtent += spacing;
runCrossAxisExtent = math.max(runCrossAxisExtent, childCrossAxisExtent);
childCount += 1;
final WrapParentData childParentData = child.parentData;
childParentData._runIndex = runMetrics.length;
child = childParentData.nextSibling;
}
if (childCount > 0) {
mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent);
crossAxisExtent += runCrossAxisExtent;
if (runMetrics.isNotEmpty) crossAxisExtent += runSpacing;
runMetrics
.add(_RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount));
}
final int runCount = runMetrics.length;
assert(runCount > 0);
double containerMainAxisExtent = 0.0;
double containerCrossAxisExtent = 0.0;
switch (direction) {
case Axis.horizontal:
size = constraints.constrain(Size(mainAxisExtent, crossAxisExtent));
containerMainAxisExtent = size.width;
containerCrossAxisExtent = size.height;
break;
case Axis.vertical:
size = constraints.constrain(Size(crossAxisExtent, mainAxisExtent));
containerMainAxisExtent = size.height;
containerCrossAxisExtent = size.width;
break;
}
_hasVisualOverflow = containerMainAxisExtent < mainAxisExtent ||
containerCrossAxisExtent < crossAxisExtent;
final double crossAxisFreeSpace =
math.max(0.0, containerCrossAxisExtent - crossAxisExtent);
double runLeadingSpace = 0.0;
double runBetweenSpace = 0.0;
switch (runAlignment) {
case WrapAlignment.start:
break;
case WrapAlignment.end:
runLeadingSpace = crossAxisFreeSpace;
break;
case WrapAlignment.center:
runLeadingSpace = crossAxisFreeSpace / 2.0;
break;
case WrapAlignment.spaceBetween:
runBetweenSpace =
runCount > 1 ? crossAxisFreeSpace / (runCount - 1) : 0.0;
break;
case WrapAlignment.spaceAround:
runBetweenSpace = crossAxisFreeSpace / runCount;
runLeadingSpace = runBetweenSpace / 2.0;
break;
case WrapAlignment.spaceEvenly:
runBetweenSpace = crossAxisFreeSpace / (runCount + 1);
runLeadingSpace = runBetweenSpace;
break;
}
runBetweenSpace += runSpacing;
double crossAxisOffset = flipCrossAxis
? containerCrossAxisExtent - runLeadingSpace
: runLeadingSpace;
child = firstChild;
for (int i = 0; i < runCount; ++i) {
final _RunMetrics metrics = runMetrics[i];
final double runMainAxisExtent = metrics.mainAxisExtent;
final double runCrossAxisExtent = metrics.crossAxisExtent;
final int childCount = metrics.childCount;
final double mainAxisFreeSpace =
math.max(0.0, containerMainAxisExtent - runMainAxisExtent);
double childLeadingSpace = 0.0;
double childBetweenSpace = 0.0;
//print(symmetry);
switch (alignment) {
case WrapAlignment.start:
if (symmetry) childLeadingSpace = spacing / 2;
break;
case WrapAlignment.end:
childLeadingSpace = mainAxisFreeSpace;
if (symmetry) childLeadingSpace = mainAxisFreeSpace - spacing / 2;
break;
case WrapAlignment.center:
childLeadingSpace = mainAxisFreeSpace / 2.0;
break;
case WrapAlignment.spaceBetween:
childBetweenSpace =
childCount > 1 ? mainAxisFreeSpace / (childCount - 1) : 0.0;
break;
case WrapAlignment.spaceAround:
childBetweenSpace = mainAxisFreeSpace / childCount;
childLeadingSpace = childBetweenSpace / 2.0;
break;
case WrapAlignment.spaceEvenly:
childBetweenSpace = mainAxisFreeSpace / (childCount + 1);
childLeadingSpace = childBetweenSpace;
break;
}
childBetweenSpace += spacing;
double childMainPosition = flipMainAxis
? containerMainAxisExtent - childLeadingSpace
: childLeadingSpace;
if (flipCrossAxis) crossAxisOffset -= runCrossAxisExtent;
while (child != null) {
final WrapParentData childParentData = child.parentData;
if (childParentData._runIndex != i) break;
final double childMainAxisExtent = _getMainAxisExtent(child);
final double childCrossAxisExtent = _getCrossAxisExtent(child);
final double childCrossAxisOffset = _getChildCrossAxisOffset(
flipCrossAxis, runCrossAxisExtent, childCrossAxisExtent);
if (flipMainAxis) childMainPosition -= childMainAxisExtent;
childParentData.offset = _getOffset(
childMainPosition, crossAxisOffset + childCrossAxisOffset);
if (flipMainAxis)
childMainPosition -= childBetweenSpace;
else
childMainPosition += childMainAxisExtent + childBetweenSpace;
child = childParentData.nextSibling;
}
if (flipCrossAxis)
crossAxisOffset -= runBetweenSpace;
else
crossAxisOffset += runCrossAxisExtent + runBetweenSpace;
}
}
@override
bool hitTestChildren(HitTestResult result, {Offset position}) {
return defaultHitTestChildren(result, position: position);
}
@override
void paint(PaintingContext context, Offset offset) {
// TODO(ianh): move the debug flex overflow paint logic somewhere common so
// it can be reused here
if (_hasVisualOverflow)
context.pushClipRect(
needsCompositing, offset, Offset.zero & size, defaultPaint);
else
defaultPaint(context, offset);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(EnumProperty<Axis>('direction', direction));
properties.add(EnumProperty<WrapAlignment>('alignment', alignment));
properties.add(DoubleProperty('spacing', spacing));
properties.add(EnumProperty<WrapAlignment>('runAlignment', runAlignment));
properties.add(DoubleProperty('runSpacing', runSpacing));
properties.add(DoubleProperty('crossAxisAlignment', runSpacing));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection,
defaultValue: null));
properties.add(EnumProperty<VerticalDirection>(
'verticalDirection', verticalDirection,
defaultValue: VerticalDirection.down));
}
}
class _RunMetrics {
_RunMetrics(this.mainAxisExtent, this.crossAxisExtent, this.childCount);
final double mainAxisExtent;
final double crossAxisExtent;
final int childCount;
}
/// Parent data for use with [CustomRenderWrap].
class WrapParentData extends ContainerBoxParentData<RenderBox> {
int _runIndex = 0;
}
================================================
FILE: pubspec.yaml
================================================
name: flutter_tags
description: Creating selectable and input tags (TextField) has never been easier.
version: 0.4.9+1
author: Antonino Di Natale <gyorgio88@gmail.com>
homepage: https://github.com/Dn-a/flutter_tags
environment:
sdk: ">=2.0.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
================================================
FILE: test/flutter_tags_test.dart
================================================
import 'package:flutter_test/flutter_test.dart';
void main() {}
gitextract_ehrk8p54/
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example/
│ ├── .gitignore
│ ├── .metadata
│ ├── README.md
│ ├── ios/
│ │ ├── Flutter/
│ │ │ ├── AppFrameworkInfo.plist
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── flutter_export_environment.sh
│ │ ├── Runner/
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets/
│ │ │ │ ├── AppIcon.appiconset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── LaunchImage.imageset/
│ │ │ │ ├── Contents.json
│ │ │ │ └── README.md
│ │ │ ├── Base.lproj/
│ │ │ │ ├── LaunchScreen.storyboard
│ │ │ │ └── Main.storyboard
│ │ │ ├── Info.plist
│ │ │ └── Runner-Bridging-Header.h
│ │ ├── Runner.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace/
│ │ │ │ └── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── xcschemes/
│ │ │ └── Runner.xcscheme
│ │ └── Runner.xcworkspace/
│ │ └── contents.xcworkspacedata
│ ├── lib/
│ │ └── main.dart
│ ├── pubspec.yaml
│ └── test/
│ └── widget_test.dart
├── flutter_tags.iml
├── lib/
│ ├── flutter_tags.dart
│ └── src/
│ ├── item_tags.dart
│ ├── suggestions_textfield.dart
│ ├── tags.dart
│ └── util/
│ └── custom_wrap.dart
├── pubspec.yaml
└── test/
└── flutter_tags_test.dart
SYMBOL INDEX (73 symbols across 7 files)
FILE: example/lib/main.dart
function main (line 7) | void main()
class MyApp (line 9) | class MyApp extends StatelessWidget {
method build (line 12) | Widget build(BuildContext context)
class MyHomePage (line 23) | class MyHomePage extends StatefulWidget {
method createState (line 28) | _MyHomePageState createState()
class _MyHomePageState (line 31) | class _MyHomePageState extends State<MyHomePage>
method initState (line 87) | void initState()
method build (line 100) | Widget build(BuildContext context)
method _buildItems (line 694) | List<DropdownMenuItem> _buildItems()
method _buildItems2 (line 717) | List<DropdownMenuItem> _buildItems2()
FILE: example/test/widget_test.dart
function main (line 3) | void main()
FILE: lib/src/item_tags.dart
type OnPressedCallback (line 6) | typedef OnPressedCallback = void Function(Item i);
type OnLongPressedCallback (line 9) | typedef OnLongPressedCallback = void Function(Item i);
type OnRemovedCallback (line 12) | typedef OnRemovedCallback = bool Function();
type ItemTagsCombine (line 15) | enum ItemTagsCombine {
class ItemTags (line 24) | class ItemTags extends StatefulWidget {
method createState (line 140) | _ItemTagsState createState()
class _ItemTagsState (line 143) | class _ItemTagsState extends State<ItemTags> {
method _setDataList (line 149) | void _setDataList()
method dispose (line 207) | void dispose()
method build (line 213) | Widget build(BuildContext context)
method _singleItem (line 437) | void _singleItem(DataListInherited dataSetIn, DataList dataSet)
class Item (line 447) | class Item {
method toString (line 455) | String toString()
class ItemTagsImage (line 461) | class ItemTagsImage {
class ItemTagsIcon (line 471) | class ItemTagsIcon {
class ItemTagsRemoveButton (line 479) | class ItemTagsRemoveButton {
FILE: lib/src/suggestions_textfield.dart
type OnChangedCallback (line 9) | typedef OnChangedCallback = void Function(String string);
type OnSubmittedCallback (line 12) | typedef OnSubmittedCallback = void Function(String string);
class SuggestionsTextField (line 14) | class SuggestionsTextField extends StatefulWidget {
method createState (line 24) | _SuggestionsTextFieldState createState()
class _SuggestionsTextFieldState (line 27) | class _SuggestionsTextFieldState extends State<SuggestionsTextField> {
method initState (line 40) | void initState()
method build (line 45) | Widget build(BuildContext context)
method _onSubmitted (line 128) | void _onSubmitted(String str)
method _checkOnChanged (line 152) | void _checkOnChanged(String str)
class TagsTextField (line 176) | class TagsTextField {
FILE: lib/src/tags.dart
type Widget (line 8) | typedef Widget ItemBuilder(int index);
class Tags (line 10) | class Tags extends StatefulWidget {
method createState (line 82) | TagsState createState()
class TagsState (line 85) | class TagsState extends State<Tags> {
method _getWidthContext (line 95) | void _getWidthContext()
method build (line 109) | Widget build(BuildContext context)
method _buildItems (line 154) | List<Widget> _buildItems()
method _widthCalc (line 222) | double _widthCalc()
class DataListInherited (line 234) | class DataListInherited extends InheritedWidget {
method updateShouldNotify (line 244) | bool updateShouldNotify(DataListInherited old)
method of (line 251) | DataListInherited of(BuildContext context)
class DataList (line 256) | class DataList extends ValueNotifier implements Item {
FILE: lib/src/util/custom_wrap.dart
class CustomWrap (line 6) | class CustomWrap extends MultiChildRenderObjectWidget {
method createRenderObject (line 43) | CustomRenderWrap createRenderObject(BuildContext context)
method updateRenderObject (line 59) | void updateRenderObject(BuildContext context, CustomRenderWrap renderO...
method debugFillProperties (line 74) | void debugFillProperties(DiagnosticPropertiesBuilder properties)
class CustomRenderWrap (line 91) | class CustomRenderWrap extends RenderBox
method setupParentData (line 274) | void setupParentData(RenderBox child)
method _computeIntrinsicHeightForWidth (line 279) | double _computeIntrinsicHeightForWidth(double width)
method _computeIntrinsicWidthForHeight (line 308) | double _computeIntrinsicWidthForHeight(double height)
method computeMinIntrinsicWidth (line 338) | double computeMinIntrinsicWidth(double height)
method computeMaxIntrinsicWidth (line 355) | double computeMaxIntrinsicWidth(double height)
method computeMinIntrinsicHeight (line 372) | double computeMinIntrinsicHeight(double width)
method computeMaxIntrinsicHeight (line 390) | double computeMaxIntrinsicHeight(double width)
method computeDistanceToActualBaseline (line 407) | double computeDistanceToActualBaseline(TextBaseline baseline)
method _getMainAxisExtent (line 411) | double _getMainAxisExtent(RenderBox child)
method _getCrossAxisExtent (line 421) | double _getCrossAxisExtent(RenderBox child)
method _getOffset (line 431) | Offset _getOffset(double mainAxisOffset, double crossAxisOffset)
method _getChildCrossAxisOffset (line 441) | double _getChildCrossAxisOffset(bool flipCrossAxis, double runCrossAxi...
method performLayout (line 458) | void performLayout()
method hitTestChildren (line 655) | bool hitTestChildren(HitTestResult result, {Offset position})
method paint (line 660) | void paint(PaintingContext context, Offset offset)
method debugFillProperties (line 671) | void debugFillProperties(DiagnosticPropertiesBuilder properties)
class _RunMetrics (line 687) | class _RunMetrics {
class WrapParentData (line 696) | class WrapParentData extends ContainerBoxParentData<RenderBox> {
FILE: test/flutter_tags_test.dart
function main (line 3) | void main()
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (172K chars).
[
{
"path": ".gitignore",
"chars": 228,
"preview": ".DS_Store\n.dart_tool/\n\n.packages\n.pub/\n\nbuild/\nios/.generated/\nios/Flutter/Generated.xcconfig\nios/Runner/GeneratedPlugin"
},
{
"path": ".metadata",
"chars": 307,
"preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
},
{
"path": "CHANGELOG.md",
"chars": 4363,
"preview": "## [0.4.9+1] - 2020-11-11.\n\n* `[Fixed]` - Issue #66.\n* `[Fixed]` - `DataList` null id.\n\n## [0.4.9] - 2020-09-15.\n\n* `[Ad"
},
{
"path": "LICENSE",
"chars": 1083,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2018 Antonino Di Natale\n\nPermission is hereby granted, free of charge, to any perso"
},
{
"path": "README.md",
"chars": 6499,
"preview": "# flutter_tags\n[](https://pub.dartlang.org/packages/f"
},
{
"path": "example/.gitignore",
"chars": 1294,
"preview": "# Miscellaneous\n*.class\n*.lock\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*."
},
{
"path": "example/.metadata",
"chars": 303,
"preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
},
{
"path": "example/README.md",
"chars": 27633,
"preview": "# Example Flutter Tags\n\nAn example of how you could implement it.\n\n## Getting Started - Selectable Tags\n```dart\nimport '"
},
{
"path": "example/ios/Flutter/AppFrameworkInfo.plist",
"chars": 773,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "example/ios/Flutter/Debug.xcconfig",
"chars": 30,
"preview": "#include \"Generated.xcconfig\"\n"
},
{
"path": "example/ios/Flutter/Release.xcconfig",
"chars": 30,
"preview": "#include \"Generated.xcconfig\"\n"
},
{
"path": "example/ios/Flutter/flutter_export_environment.sh",
"chars": 641,
"preview": "#!/bin/sh\n# This is a generated file; do not edit or check into version control.\nexport \"FLUTTER_ROOT=C:\\flutter\"\nexport"
},
{
"path": "example/ios/Runner/AppDelegate.swift",
"chars": 403,
"preview": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n override func applicatio"
},
{
"path": "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2519,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"20x20\",\n \"idiom\" : \"iphone\",\n \"filename\" : \"Icon-App-20x20@2x.png\",\n "
},
{
"path": "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
"chars": 391,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"LaunchImage.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
"chars": 336,
"preview": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in"
},
{
"path": "example/ios/Runner/Base.lproj/LaunchScreen.storyboard",
"chars": 2377,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "example/ios/Runner/Base.lproj/Main.storyboard",
"chars": 1605,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "example/ios/Runner/Info.plist",
"chars": 1518,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "example/ios/Runner/Runner-Bridging-Header.h",
"chars": 37,
"preview": "#import \"GeneratedPluginRegistrant.h\""
},
{
"path": "example/ios/Runner.xcodeproj/project.pbxproj",
"chars": 21251,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3331,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0910\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "example/ios/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "example/lib/main.dart",
"chars": 26929,
"preview": "import 'dart:convert';\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\n\nimport 'package:"
},
{
"path": "example/pubspec.yaml",
"chars": 2315,
"preview": "name: example_flutter_tags\ndescription: A new Flutter application.\n\n# The following defines the version and build number"
},
{
"path": "example/test/widget_test.dart",
"chars": 56,
"preview": "import 'package:flutter/material.dart';\n\nvoid main() {}\n"
},
{
"path": "flutter_tags.iml",
"chars": 1742,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n <component name=\"FacetManager\">\n <fa"
},
{
"path": "lib/flutter_tags.dart",
"chars": 117,
"preview": "library flutter_tags;\n\nexport 'src/suggestions_textfield.dart';\nexport 'src/item_tags.dart';\nexport 'src/tags.dart';\n"
},
{
"path": "lib/src/item_tags.dart",
"chars": 15434,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:flutter_tags/src/tags.dar"
},
{
"path": "lib/src/suggestions_textfield.dart",
"chars": 7083,
"preview": "import 'package:flutter/material.dart';\n\n// InputSuggestions version 0.0.1\n// currently yield inline suggestions\n// I wi"
},
{
"path": "lib/src/tags.dart",
"chars": 8057,
"preview": "import 'package:flutter/material.dart';\n\nimport '../flutter_tags.dart';\nimport 'util/custom_wrap.dart';\nimport 'package:"
},
{
"path": "lib/src/util/custom_wrap.dart",
"chars": 23068,
"preview": "import 'dart:math' as math;\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/widgets.dart';\n\n/// Custom "
},
{
"path": "pubspec.yaml",
"chars": 348,
"preview": "name: flutter_tags\ndescription: Creating selectable and input tags (TextField) has never been easier.\nversion: 0.4.9+1\na"
},
{
"path": "test/flutter_tags_test.dart",
"chars": 65,
"preview": "import 'package:flutter_test/flutter_test.dart';\n\nvoid main() {}\n"
}
]
About this extraction
This page contains the full source code of the Dn-a/flutter_tags GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (158.7 KB), approximately 37.3k tokens, and a symbol index with 73 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.