我有一个textfield
(见图片),当用户选择一个地址时,它将被复制到textfield
中。问题是,即使textfield
失去焦点,也是因为您看不到文本的开头。在此示例中,街道编号在左侧并被切除。我希望textfield
在失去焦点或通过编程设置文本时显示文本的最左侧,而不是右侧。我猜光标在最后。但是当失去焦点时,没有光标,下面的textfield
就会有焦点。
我正在使用AutoComplete软件包。但是这是代码。
library auto_complete_text_view;
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
typedef void OnTapCallback(String value);
class AutoCompleteTextView extends StatefulWidget
with AutoCompleteTextInterface {
final double maxHeight;
final TextEditingController controller;
//AutoCompleteTextField properties
final tfCursorColor;
final tfCursorWidth;
final tfStyle;
final tfTextDecoration;
final tfTextAlign;
//Suggestiondrop Down properties
final suggestionStyle;
final suggestionTextAlign;
final onTapCallback;
final Function getSuggestionsMethod;
final Function focusGained;
final Function focusLost;
final int suggestionsApiFetchDelay;
final Function onValueChanged;
AutoCompleteTextView(
{@required this.controller,
this.onTapCallback,
this.maxHeight = 0,
this.tfCursorColor = Colors.white,
this.tfCursorWidth = 2.0,
this.tfStyle = const TextStyle(color: Colors.black),
this.tfTextDecoration = const InputDecoration(),
this.tfTextAlign = TextAlign.left,
this.suggestionStyle = const TextStyle(color: Colors.black),
this.suggestionTextAlign = TextAlign.left,
@required this.getSuggestionsMethod,
this.focusGained,
this.suggestionsApiFetchDelay = 0,
this.focusLost,
this.onValueChanged});
@override
_AutoCompleteTextViewState createState() => _AutoCompleteTextViewState();
//This funciton is called when a user clicks on a suggestion
@override
void onTappedSuggestion(String suggestion) {
onTapCallback(suggestion);
}
}
class _AutoCompleteTextViewState extends State<AutoCompleteTextView> {
ScrollController scrollController = ScrollController();
FocusNode _focusNode = FocusNode();
OverlayEntry _overlayEntry;
LayerLink _layerLink = LayerLink();
final suggestionsStreamController = new BehaviorSubject<List<String>>();
List<String> suggestionShowList = List<String>();
Timer _debounce;
bool isSearching = true;
@override
void initState() {
super.initState();
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context).insert(this._overlayEntry);
(widget.focusGained != null) ? widget.focusGained() : () {};
} else {
this._overlayEntry.remove();
(widget.focusLost != null) ? widget.focusLost() : () {};
}
});
widget.controller.addListener(_onSearchChanged);
}
_onSearchChanged() {
if (_debounce?.isActive ?? false) _debounce.cancel();
_debounce =
Timer(Duration(milliseconds: widget.suggestionsApiFetchDelay), () {
if (isSearching == true) {
_getSuggestions(widget.controller.text);
}
});
}
_getSuggestions(String data) async {
if (data.length > 0 && data != null) {
List<String> list = await widget.getSuggestionsMethod(data);
suggestionsStreamController.sink.add(list);
}
}
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
return OverlayEntry(
builder: (context) => Positioned(
width: size.width,
child: CompositedTransformFollower(
link: this._layerLink,
showWhenUnlinked: false,
offset: Offset(0.0, size.height + 5.0),
child: Material(
elevation: 4.0,
child: StreamBuilder<Object>(
stream: suggestionsStreamController.stream,
builder: (context, suggestionData) {
if (suggestionData.hasData &&
widget.controller.text.isNotEmpty) {
suggestionShowList = suggestionData.data;
return ConstrainedBox(
constraints: new BoxConstraints(
maxHeight: 0,
),
child: ListView.builder(
controller: scrollController,
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: suggestionShowList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
suggestionShowList[index],
style: widget.suggestionStyle,
textAlign: widget.suggestionTextAlign,
),
onTap: () {
isSearching = false;
widget.controller.text =
suggestionShowList[index];
suggestionsStreamController.sink.add([]);
widget.onTappedSuggestion(
widget.controller.text);
},
);
}),
);
} else {
return Container();
}
}),
),
),
));
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: TextField(
controller: widget.controller,
decoration: widget.tfTextDecoration,
style: widget.tfStyle,
cursorColor: widget.tfCursorColor,
cursorWidth: widget.tfCursorWidth,
textAlign: widget.tfTextAlign,
focusNode: this._focusNode,
onChanged: (text) {
if (text.trim().isNotEmpty) {
(widget.onValueChanged != null)
? widget.onValueChanged(text)
: () {};
isSearching = true;
scrollController.animateTo(
0.0,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
} else {
isSearching = false;
suggestionsStreamController.sink.add([]);
}
},
),
);
}
@override
void dispose() {
suggestionsStreamController.close();
scrollController.dispose();
widget.controller.dispose();
super.dispose();
}
}
abstract class AutoCompleteTextInterface {
void onTappedSuggestion(String suggestion);
}
答案 0 :(得分:0)
使用ScrollController
,可以使最左侧的文本可见。
final scrollController = ScrollController();
。scrollController.jumpTo(0.0);
。 TextField
中添加scrollController:
属性,然后从步骤1开始将其值设置为scrollController
。TextField
中添加onEditingComplete:
属性,并将其值设置为在步骤2中创建的方法。针对上述要点制作了一个小代码示例:pastebin
注意:
onEditingComplete
回调,在不同情况下,您可能需要使用另一个回调。