Skip to content

Instantly share code, notes, and snippets.

@sayhicoelho
Last active May 2, 2020 22:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sayhicoelho/cda5f71879d0d6186ee4b13b9e16ae63 to your computer and use it in GitHub Desktop.
Save sayhicoelho/cda5f71879d0d6186ee4b13b9e16ae63 to your computer and use it in GitHub Desktop.
Flutter Searchable Input
import 'package:flutter/material.dart';
import './custom_searchable_dialog.dart';
import './custom_text_field.dart';
class CustomSearchableItem<T> {
final String label;
final T value;
CustomSearchableItem({
@required this.label,
@required this.value,
});
@override
String toString() => 'CustomSearchableItem(label: $label, value: $value)';
}
class CustomSearchable<T> extends StatefulWidget {
final Function(CustomSearchableItem<T>) onChanged;
final CustomSearchableItem<T> value;
final List<CustomSearchableItem<T>> items;
final String label;
final String hintText;
final String searchHint;
final bool enabled;
CustomSearchable({
Key key,
@required this.onChanged,
@required this.value,
@required this.items,
@required this.label,
this.hintText = 'Selecione',
this.searchHint = 'Pesquisar',
this.enabled = true,
}) : super(key: key);
@override
_CustomSearchableState createState() => _CustomSearchableState<T>();
}
class _CustomSearchableState<T> extends State<CustomSearchable<T>> {
final _controller = TextEditingController();
@override
Widget build(BuildContext context) {
if (widget.value == null) {
_controller.clear();
}
return CustomTextField(
controller: _controller,
label: widget.label,
hintText: widget.hintText,
enabled: widget.enabled,
readonly: true,
onTap: () {
showDialog(
context: context,
builder: (context) => SimpleDialog(
contentPadding: const EdgeInsets.all(0.0),
children: <Widget>[
CustomSearchableDialog<T>(
items: widget.items,
onChanged: (v) {
widget.onChanged(v);
_controller.text = v.label;
Navigator.of(context).pop();
},
searchHint: widget.searchHint,
),
],
)
);
},
);
}
}
import 'package:flutter/material.dart';
import './custom_searchable.dart';
class CustomSearchableDialog<T> extends StatefulWidget {
final Function(CustomSearchableItem<T>) onChanged;
final List<CustomSearchableItem<T>> items;
final String searchHint;
const CustomSearchableDialog({
Key key,
@required this.onChanged,
@required this.items,
@required this.searchHint,
}) : super(key: key);
@override
_CustomSearchableDialogState createState() => _CustomSearchableDialogState<T>();
}
class _CustomSearchableDialogState<T> extends State<CustomSearchableDialog<T>> {
var _searched = <CustomSearchableItem<T>>[];
@override
void initState() {
super.initState();
_searched = [...widget.items];
}
void _search(String value) {
var result = widget.items.where((item) =>
item.label.toLowerCase().contains(value.toLowerCase())).toList();
_searched.clear();
setState(() {
_searched = [...result];
});
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 16.0, top: 16.0, right: 16.0),
child: Text(widget.searchHint),
),
const SizedBox(height: 8.0,),
TextField(
onChanged: _search,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(16.0),
prefixIcon: Icon(Icons.search),
filled: false, fillColor: Colors.red
),
),
Container(
width: double.maxFinite,
height: 200.0,
child: ListView.builder(
itemCount: _searched.length,
itemBuilder: (context, index) => InkWell(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(_searched[index].label),
),
onTap: () {
widget.onChanged(_searched[index]);
},
),
shrinkWrap: true,
),
),
],
);
}
}
import 'package:flutter/material.dart';
import './config/theme.dart';
class CustomTextField extends StatelessWidget {
final TextEditingController controller;
final String label;
final bool enabled;
final bool obscureText;
final Function(String) onFieldSubmitted;
final String hintText;
final TextInputAction textInputAction;
final TextInputType keyboardType;
final FocusNode focusNode;
final Function onTap;
final Function(String) onChanged;
final bool readonly;
const CustomTextField({
Key key,
@required this.controller,
@required this.label,
this.enabled = true,
this.obscureText = false,
this.onFieldSubmitted,
this.hintText,
this.textInputAction,
this.keyboardType,
this.focusNode,
this.onTap,
this.onChanged,
this.readonly = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
const borderWidth = 1.5;
return Column(
children: <Widget>[
Text(
label.toUpperCase(),
style: TextStyle(
fontSize: 16.0,
color: enabled
? CustomTheme.PRIMARY_COLOR
: CustomTheme.PRIMARY_LIGHT_COLOR,
),
),
const SizedBox(height: 8.0,),
InkWell(
onTap: onTap != null && enabled ? () {} : null,
child: TextFormField(
controller: controller,
enabled: enabled,
obscureText: obscureText,
keyboardType: keyboardType,
textInputAction: textInputAction,
onFieldSubmitted: onFieldSubmitted,
focusNode: focusNode,
onChanged: onChanged,
readOnly: readonly,
onTap: onTap,
decoration: InputDecoration(
hintText: hintText,
contentPadding: const EdgeInsets.all(16.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.zero,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: borderWidth,
color: CustomTheme.PRIMARY_COLOR,
),
borderRadius: BorderRadius.zero,
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: borderWidth,
color: CustomTheme.PRIMARY_LIGHT_COLOR,
),
borderRadius: BorderRadius.zero,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: borderWidth,
color: CustomTheme.PRIMARY_COLOR,
),
borderRadius: BorderRadius.zero,
),
),
),
)
],
);
}
}
import 'dart:ui';
class CustomTheme {
static const PRIMARY_COLOR = Color(0xFF2957A4);
static const PRIMARY_LIGHT_COLOR = Color(0x772957A4);
static const SECONDARY_COLOR = Color(0xFF354F77);
static const LIGHT_COLOR = Color(0xFFF2F2F2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment