forked from lxm_flutter/FlutterUnit
收录Autocomplete组件
This commit is contained in:
Binary file not shown.
@@ -20,7 +20,10 @@ class EventLoadCategory extends CategoryEvent{
|
||||
class EventToggleWidget extends CategoryEvent{
|
||||
final int widgetId;
|
||||
final int categoryId;
|
||||
const EventToggleWidget({required this.widgetId, required this.categoryId});
|
||||
const EventToggleWidget({
|
||||
required this.widgetId,
|
||||
required this.categoryId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [widgetId,categoryId];
|
||||
@@ -42,8 +45,11 @@ class EventAddCategory extends CategoryEvent{
|
||||
final String? info;
|
||||
final String? color;
|
||||
|
||||
const EventAddCategory(
|
||||
{required this.name, required this.info, required this.color});
|
||||
const EventAddCategory({
|
||||
required this.name,
|
||||
required this.info,
|
||||
required this.color,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [name, info, color];
|
||||
@@ -58,13 +64,14 @@ class EventUpdateCategory extends CategoryEvent {
|
||||
final int? priority;
|
||||
final String? image;
|
||||
|
||||
const EventUpdateCategory(
|
||||
{required this.name,
|
||||
required this.info,
|
||||
required this.color,
|
||||
this.priority,
|
||||
this.image,
|
||||
required this.id});
|
||||
const EventUpdateCategory({
|
||||
required this.name,
|
||||
required this.info,
|
||||
required this.color,
|
||||
this.priority,
|
||||
this.image,
|
||||
required this.id,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [name, info, color, priority, image, id];
|
||||
|
||||
@@ -19,7 +19,11 @@ class DetailWithData extends DetailState {
|
||||
final List<WidgetModel> links;
|
||||
final List<NodeModel> nodes;
|
||||
|
||||
const DetailWithData({required this.widgetModel,required this.nodes,required this.links});
|
||||
const DetailWithData({
|
||||
required this.widgetModel,
|
||||
required this.nodes,
|
||||
required this.links,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [widgetModel,nodes];
|
||||
|
||||
@@ -24,7 +24,6 @@ class _AppSearchBarState extends State<AppSearchBar> {
|
||||
height: 35,
|
||||
child: TextField(
|
||||
autofocus: true,
|
||||
//自动聚焦,闪游标
|
||||
controller: _controller,
|
||||
maxLines: 1,
|
||||
decoration: const InputDecoration(
|
||||
@@ -39,8 +38,8 @@ class _AppSearchBarState extends State<AppSearchBar> {
|
||||
hintStyle: TextStyle(fontSize: 14)),
|
||||
onChanged: _doSearch,
|
||||
onSubmitted: (str) {
|
||||
//提交后
|
||||
FocusScope.of(context).requestFocus(FocusNode()); //收起键盘
|
||||
//提交后,收起键盘
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
},
|
||||
)),
|
||||
_buildClearIcon()
|
||||
|
||||
@@ -7,7 +7,6 @@ class NotSearchPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color color = Theme.of(context).primaryColor;
|
||||
|
||||
return Container(
|
||||
height: 300,
|
||||
alignment: Alignment.center,
|
||||
|
||||
@@ -51,6 +51,16 @@ class _TolyAppBarState extends State<TolyAppBar>
|
||||
'Other'
|
||||
];
|
||||
|
||||
static const List<String> semantics = [
|
||||
'无状态组件',
|
||||
'有状态组件',
|
||||
'单子组件',
|
||||
'多子组件',
|
||||
'滑动组件',
|
||||
'代理组件',
|
||||
'其他组件'
|
||||
];
|
||||
|
||||
late AnimationController _controller;
|
||||
late Animation<double> circleAnim;
|
||||
late Animation<double> heightAnim;
|
||||
@@ -113,7 +123,7 @@ class _TolyAppBarState extends State<TolyAppBar>
|
||||
Widget _buildChild(int color) {
|
||||
ThemeData themeData = Theme.of(context);
|
||||
bool isDark = themeData.brightness == Brightness.dark;
|
||||
|
||||
int index = colors.indexOf(color);
|
||||
return Container(
|
||||
alignment: const Alignment(0, 0.4),
|
||||
decoration: BoxDecoration(boxShadow: [
|
||||
@@ -128,8 +138,9 @@ class _TolyAppBarState extends State<TolyAppBar>
|
||||
height: widget.maxHeight + 20,
|
||||
width: _width,
|
||||
child: Text(
|
||||
info[colors.indexOf(color)],
|
||||
info[index],
|
||||
style: _kTabTextStyle,
|
||||
semanticsLabel: '您当前点击了:${semantics[index]}',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ import 'package:flutter/cupertino.dart';
|
||||
// "widgetId": 143,
|
||||
// "name": 'CupertinoContextMenu基本使用',
|
||||
// "priority": 1,
|
||||
// "subtitle":
|
||||
// "【child】 : 子组件 【Widget】\n"
|
||||
// "subtitle": "【child】 : 子组件 【Widget】\n"
|
||||
// "【actions】 : 行为组件集 【List<Widget>】\n"
|
||||
// "【previewBuilder】 : 动画构造器 【ContextMenuPreviewBuilder】",
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
/// create by 张风捷特烈 on 2022-04-18
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
// {
|
||||
// "widgetId": 356,
|
||||
// "name": 'Autocomplete基本使用',
|
||||
// "priority": 1,
|
||||
// "subtitle": "【optionsBuilder】 : 选项构造器 【AutocompleteOptionsBuilder<T>】\n"
|
||||
// "【onSelected】 : 选择时回调 【AutocompleteOnSelected<T>】",
|
||||
// }
|
||||
class AutocompleteDemo extends StatelessWidget {
|
||||
const AutocompleteDemo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Autocomplete<String>(
|
||||
optionsBuilder: buildOptions,
|
||||
onSelected: onSelected,
|
||||
);
|
||||
}
|
||||
|
||||
void onSelected(String selection) {
|
||||
debugPrint('当前选择了 $selection');
|
||||
}
|
||||
|
||||
Future<Iterable<String>> buildOptions(
|
||||
TextEditingValue textEditingValue,
|
||||
) async {
|
||||
if (textEditingValue.text == '') {
|
||||
return const Iterable<String>.empty();
|
||||
}
|
||||
return searchByArgs(textEditingValue.text);
|
||||
}
|
||||
|
||||
Future<Iterable<String>> searchByArgs(String args) async{
|
||||
// 模拟网络请求
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
const List<String> data = [
|
||||
'toly', 'toly49', 'toly42', 'toly56',
|
||||
'card', 'ls', 'alex', 'fan sha',
|
||||
];
|
||||
return data.where((String name) => name.contains(args));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// create by 张风捷特烈 on 2022-04-18
|
||||
/// contact me by email 1981462002@qq.com
|
||||
/// 说明:
|
||||
// {
|
||||
// "widgetId": 356,
|
||||
// "name": 'Autocomplete的泛型',
|
||||
// "priority": 2,
|
||||
// "subtitle": "【optionsViewBuilder】 : 面板构造器 【AutocompleteOptionsViewBuilder<T>】\n"
|
||||
// "【fieldViewBuilder】 : 输入构造器 【AutocompleteFieldViewBuilder】\n"
|
||||
// "【displayStringForOption】 : 文字展示 【AutocompleteOptionToString】\n",
|
||||
// }
|
||||
class AutocompleteType extends StatefulWidget {
|
||||
const AutocompleteType({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AutocompleteType> createState() => _AutocompleteTypeState();
|
||||
}
|
||||
|
||||
class _AutocompleteTypeState extends State<AutocompleteType> {
|
||||
late TextEditingController _controller;
|
||||
User? user;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 300,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: buildAutocomplete(),
|
||||
),
|
||||
body: Center(
|
||||
child: Text(
|
||||
user != null ? user!.name : '未选择',
|
||||
style: const TextStyle(fontSize: 40),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildAutocomplete() {
|
||||
return Autocomplete<User>(
|
||||
optionsBuilder: buildOptions,
|
||||
onSelected: onSelected,
|
||||
optionsViewBuilder: _buildOptionsView,
|
||||
fieldViewBuilder: _buildFieldView,
|
||||
displayStringForOption: (user) => user.name,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// _controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onSelected(User selection) {
|
||||
debugPrint('当前选择了 $selection');
|
||||
setState(() {
|
||||
user = selection;
|
||||
});
|
||||
}
|
||||
|
||||
Future<Iterable<User>> buildOptions(
|
||||
TextEditingValue textEditingValue,
|
||||
) async {
|
||||
if (textEditingValue.text == '') {
|
||||
return const Iterable<User>.empty();
|
||||
}
|
||||
return searchByArgs(textEditingValue.text);
|
||||
}
|
||||
|
||||
Future<Iterable<User>> searchByArgs(String args) async {
|
||||
// 模拟网络请求
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
const List<User> data = [
|
||||
User('toly', true, 'icon_5.webp'),
|
||||
User('toly49', false, 'icon_6.webp'),
|
||||
User('toly42', true, 'icon_7.webp'),
|
||||
User('toly56', false, 'icon_8.webp'),
|
||||
User('card', true, 'icon_5.webp'),
|
||||
User('ls', true, 'icon_6.webp'),
|
||||
User('alex', true, 'icon_7.webp'),
|
||||
User('fan sha', false, 'icon_8.webp'),
|
||||
];
|
||||
return data.where((User user) => user.name.contains(args));
|
||||
}
|
||||
|
||||
Widget _buildFieldView(
|
||||
BuildContext context,
|
||||
TextEditingController textEditingController,
|
||||
FocusNode focusNode,
|
||||
VoidCallback onFieldSubmitted) {
|
||||
_controller = textEditingController;
|
||||
return SizedBox(
|
||||
height: 34,
|
||||
child: TextFormField(
|
||||
controller: textEditingController,
|
||||
decoration: const InputDecoration(
|
||||
filled: true,
|
||||
fillColor: Color(0xffF7F8FA),
|
||||
prefixIcon: Icon(Icons.search),
|
||||
contentPadding: EdgeInsets.only(top: 1),
|
||||
border: UnderlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.all(Radius.circular(19)),
|
||||
),
|
||||
hintText: "输入用户名 (toly)",
|
||||
hintStyle: TextStyle(fontSize: 13)),
|
||||
focusNode: focusNode,
|
||||
onFieldSubmitted: (String value) {
|
||||
onFieldSubmitted();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOptionsView(BuildContext context,
|
||||
AutocompleteOnSelected<User> onSelected, Iterable<User> options) {
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Material(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: 150),
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemBuilder: (_, index) {
|
||||
final User option = options.elementAt(index);
|
||||
return _UserItem(
|
||||
onSelected: onSelected,
|
||||
user: option,
|
||||
args: _controller.text,
|
||||
);
|
||||
},
|
||||
itemCount: options.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _UserItem extends StatelessWidget {
|
||||
final AutocompleteOnSelected<User>? onSelected;
|
||||
final String args;
|
||||
final User user;
|
||||
|
||||
const _UserItem({
|
||||
Key? key,
|
||||
this.onSelected,
|
||||
required this.user,
|
||||
required this.args,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => onSelected?.call(user),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
foregroundColor: Colors.transparent,
|
||||
backgroundImage:
|
||||
AssetImage('assets/images/head_icon/${user.image}'),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text.rich(formSpan(user.name, args)),
|
||||
Text(
|
||||
'性别: ${user.man ? '男' : '女'}',
|
||||
style: const TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final TextStyle lightTextStyle = const TextStyle(
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
|
||||
InlineSpan formSpan(String src, String pattern) {
|
||||
List<TextSpan> span = [];
|
||||
List<String> parts = src.split(pattern);
|
||||
if (parts.length > 1) {
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
span.add(TextSpan(text: parts[i]));
|
||||
if (i != parts.length - 1) {
|
||||
span.add(TextSpan(text: pattern, style: lightTextStyle));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
span.add(TextSpan(text: src));
|
||||
}
|
||||
return TextSpan(children: span);
|
||||
}
|
||||
}
|
||||
|
||||
class User {
|
||||
final String name;
|
||||
final bool man;
|
||||
final String image;
|
||||
|
||||
const User(this.name, this.man, this.image);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'User{name: $name, man: $man, image: $image}';
|
||||
}
|
||||
}
|
||||
@@ -194,4 +194,7 @@ export '../StatelessWidget/PageStorage/node1_base.dart';
|
||||
export '../StatelessWidget/NotificationListener/node1_base.dart';
|
||||
export '../StatelessWidget/NotificationListener/node2_update.dart';
|
||||
|
||||
export '../StatelessWidget/Autocomplete/node1_base.dart';
|
||||
export '../StatelessWidget/Autocomplete/node2_type.dart';
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ class WidgetsMap {
|
||||
const CupertinoSegmentedControlDemo(),
|
||||
const CupertinoSegmentedControlColor()
|
||||
];
|
||||
|
||||
case "Autocomplete":
|
||||
return [
|
||||
const AutocompleteDemo(),
|
||||
const AutocompleteType()
|
||||
];
|
||||
case "CompositedTransformTarget":
|
||||
return [
|
||||
const CompositedTransformTargetDemo(),
|
||||
@@ -33,16 +39,20 @@ class WidgetsMap {
|
||||
case "CompositedTransformFollower":
|
||||
return [
|
||||
const CompositedTransformFollowerDemo(),
|
||||
]; case "PrimaryScrollController":
|
||||
];
|
||||
case "PrimaryScrollController":
|
||||
return [
|
||||
const PrimaryScrollControllerDemo(),
|
||||
];case "CupertinoFullscreenDialogTransition":
|
||||
];
|
||||
case "CupertinoFullscreenDialogTransition":
|
||||
return [
|
||||
const CupertinoFullscreenDialogTransitionDemo(),
|
||||
];case "CupertinoPageTransition":
|
||||
];
|
||||
case "CupertinoPageTransition":
|
||||
return [
|
||||
const CupertinoPageTransitionDemo(),
|
||||
];case "HtmlElementView":
|
||||
];
|
||||
case "HtmlElementView":
|
||||
return [
|
||||
const HtmlElementViewDemo(),
|
||||
];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: flutter_unit
|
||||
description: A new Flutter application.
|
||||
|
||||
version: 2.0.0
|
||||
version: 2.0.1
|
||||
author: 张风捷特烈 <1981462002@qq.com>
|
||||
homepage: https://juejin.cn/user/149189281194766/posts
|
||||
|
||||
|
||||
Reference in New Issue
Block a user