Skip to content

Commit

Permalink
Fix: #204 Interactive text editable menu was not being displayed.
Browse files Browse the repository at this point in the history
  • Loading branch information
maheshj01 committed Jan 26, 2025
1 parent b491a1a commit f2dfa98
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 106 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### [1.2.3] - January 26, 2025
- Fix: [Issue: #204](https://github.com/maheshj01/searchfield/issues/204) Interactive text editable menu was not being displayed.

### [1.2.2] - December 24, 2024

- Fix: [Issue: #197](https://github.com/maheshj01/searchfield/pull/197) Remove Null Checker
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# [searchfield: ^1.2.2](https://pub.dev/packages/searchfield)
# [searchfield: ^1.2.3](https://pub.dev/packages/searchfield)

<a href="https://github.com/maheshj01/searchfield" rel="noopener" target="_blank"><img src="https://img.shields.io/badge/platform-flutter-ff69b4.svg" alt="Flutter Platform Badge"></a>
<a href="https://pub.dev/packages/searchfield"><img src="https://img.shields.io/pub/v/searchfield.svg" alt="Pub"></a>
Expand Down
5 changes: 1 addition & 4 deletions example/lib/country_search.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ class _CountrySearchState extends State<CountrySearch> {
@override
void dispose() {
_searchController.dispose();
focus.dispose();
super.dispose();
}

Expand All @@ -29,7 +28,6 @@ class _CountrySearchState extends State<CountrySearch> {

final _formKey = GlobalKey<FormState>();

final focus = FocusNode();
List<Country> countries = [];
Country _selectedCountry = Country.init();

Expand Down Expand Up @@ -59,7 +57,6 @@ class _CountrySearchState extends State<CountrySearch> {
child: Form(
key: _formKey,
child: SearchField(
focusNode: focus,
suggestions: countries
.map((country) =>
SearchFieldListItem(country.name, item: country))
Expand All @@ -83,8 +80,8 @@ class _CountrySearchState extends State<CountrySearch> {
setState(() {
_selectedCountry = x.item!;
});
print("selected:${x.item}");
_formKey.currentState!.validate();
focus.unfocus();
},
),
),
Expand Down
206 changes: 107 additions & 99 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// import 'package:example/pagination.dart';
import 'package:example/country_search.dart';
import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';

Expand All @@ -24,7 +25,7 @@ class MyApp extends StatelessWidget {
useMaterial3: true,
brightness: Brightness.dark,
),
home: SearchFieldSample(),
home: CountrySearch(title: 'SearchField Demo'),
debugShowCheckedModeBanner: false,
);
}
Expand Down Expand Up @@ -81,103 +82,10 @@ class _SearchFieldSampleState extends State<SearchFieldSample> {
appBar: AppBar(title: Text('Searchfield Demo')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 20,
children: [
SearchField(
suggestionDirection: SuggestionDirection.flex,
onSearchTextChanged: (query) {
final filter = suggestions
.where((element) =>
element.toLowerCase().contains(query.toLowerCase()))
.toList();
return filter
.map((e) =>
SearchFieldListItem<String>(e, child: searchChild(e)))
.toList();
},
selectedValue: selectedValue,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
if (value == null || !suggestions.contains(value.trim())) {
return 'Enter a valid country name';
}
return null;
},
onSubmit: (x) {},
autofocus: false,
key: const Key('searchfield'),
hint: 'Search by country name',
itemHeight: 50,
scrollbarDecoration: ScrollbarDecoration(
thickness: 12,
radius: Radius.circular(6),
trackColor: Colors.grey,
trackBorderColor: Colors.red,
thumbColor: Colors.orange,
),
suggestionStyle:
const TextStyle(fontSize: 18, color: Colors.black),
suggestionItemDecoration: BoxDecoration(
// color: Colors.grey[100],
// borderRadius: BorderRadius.circular(10),
border: Border(
bottom: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
searchInputDecoration: SearchInputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(24),
borderSide: const BorderSide(
width: 1,
color: Colors.orange,
style: BorderStyle.solid,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(24),
borderSide: const BorderSide(
width: 1,
color: Colors.black,
style: BorderStyle.solid,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
),
),
suggestionsDecoration: SuggestionDecoration(
// border: Border.all(color: Colors.orange),
elevation: 8.0,
selectionColor: Colors.grey.shade100,
hoverColor: Colors.purple.shade100,
gradient: LinearGradient(
colors: [
Color(0xfffc466b),
Color.fromARGB(255, 103, 128, 255)
],
stops: [0.25, 0.75],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
)),
suggestions: suggestions
.map((e) =>
SearchFieldListItem<String>(e, child: searchChild(e)))
.toList(),
suggestionState: Suggestion.expand,
onSuggestionTap: (SearchFieldListItem<String> x) {
setState(() {
selectedValue = x;
});
},
),
SizedBox(height: 20),
SearchField(
hint: 'Basic SearchField',
dynamicHeight: true,
Expand All @@ -186,14 +94,114 @@ class _SearchFieldSampleState extends State<SearchFieldSample> {
setState(() {
selectedValue = item;
});
print(item.item);
},
selectedValue: selectedValue,
suggestions:
suggestions.map(SearchFieldListItem<String>.new).toList(),
suggestions: suggestions
.map(
(x) => SearchFieldListItem<String>(
x,
item: x,
child: searchChild(x),
),
)
.toList(),
suggestionState: Suggestion.expand,
),
TextField(
decoration: InputDecoration(
hintText: 'Basic TextField',
),
),
OverlayInput(),
],
),
));
}
}

class OverlayInput extends StatefulWidget {
OverlayInput({Key? key}) : super(key: key);
@override
State<OverlayInput> createState() => _OverlayInputState();
}

class _OverlayInputState extends State<OverlayInput> {
final ScrollController _scrollController = ScrollController();

Widget _list() {
return Container(
height: 5 * 40,
child: Scrollbar(
controller: _scrollController,
thumbVisibility: true,
child: ListView.builder(
controller: _scrollController,
padding: EdgeInsets.zero,
itemCount: 20,
itemBuilder: (context, index) => ListTile(
title: Text('item $index'),
))),
);
}

final LayerLink _layerLink = LayerLink();

OverlayEntry _createOverlay() {
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
final offset = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(
builder: (context) => Positioned(
left: offset.dx,
width: size.width,
child: CompositedTransformFollower(
offset: Offset(0, 50),
link: _layerLink,
child: Material(color: Colors.red, child: _list())),
));
}

late OverlayEntry _overlayEntry;
final _searchFocusNode = FocusNode();
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
_overlayEntry = _createOverlay();
});

_searchFocusNode.addListener(() {
if (!_searchFocusNode.hasFocus) {
_overlayEntry.remove();
}
});
super.initState();
}

@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: _layerLink,
child: TextFormField(
focusNode: _searchFocusNode,
onTapOutside: (x) {
_overlayEntry.remove();
},
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
),
onTap: () {
Overlay.of(context).insert(_overlayEntry);
},
onChanged: (query) {},
),
);
}
}
9 changes: 8 additions & 1 deletion lib/src/searchfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,14 @@ class _SearchFieldState<T> extends State<SearchField<T>> {
link: _layerLink,
child: TextFormField(
key: key,
contextMenuBuilder: widget.contextMenuBuilder,
contextMenuBuilder: (context, state) {
if (widget.contextMenuBuilder != null) {
return widget.contextMenuBuilder!(context, state);
} else {
return AdaptiveTextSelectionToolbar.editableText(
editableTextState: state);
}
},
enabled: widget.enabled,
textAlign: widget.textAlign,
autofocus: widget.autofocus,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: searchfield
description: A highly customizable, simple and easy to use AutoComplete widget for your Flutter app
version: 1.2.2
version: 1.2.3
homepage: https://github.com/maheshj01/searchfield
repository: https://github.com/maheshj01/searchfield
issue_tracker: https://github.com/maheshj01/searchfield/issues
Expand Down

0 comments on commit f2dfa98

Please sign in to comment.