今天开发微信通讯录好友添加备注中的电话添加功能,发现很多细节。处理起来比较麻烦,所以特意记录一下。
这里有很多细节点
1. 页面滑动隐藏键盘
2. 每点击添加输入框要定位到输入框上面一点。
3. 点击删除电话号码会出现一个删除按钮让用户确认。
4. 编辑时输入框右侧有一个清空按钮
5. 添加五个手机号后,下方要提示“最多可以添加5个号码”
通过实践对上面五点做出分析。
第1和第2 通过代码实践这里是冲突的。因为定位之后页面滑动会导致键盘隐藏。 所以考虑目前先使用点击空白区域隐藏键盘的方法(这里不知道微信是怎么实现的,可能使用办法监测到 列表是人为滑动的还是通过Api控制的。但是我还没有发现)。然后定位问题就可以解决了。
第3.点击删除电话号码会出现一个删除按钮让用户确认。 第三点没有找到合适的插件,需要自己写一个组件实现。
第4.系统自导的TextField也不支持改功能需要自定义组件
第5条很简单。只需要在用户添加了五个TextField后去掉添加按钮,添加这段文字即可。
以下为代码实践。
1. 页面滑动隐藏键盘(改为点击空白区域隐藏)
GestureDetector(
onTap:(){
///主要语句
FocusManager.instance.primaryFocus?.unfocus();
},
child: list
);
2.每点击添加输入框要定位到输入框上面一点。
这里首先要获取输入框的Widget在页面的中Y轴位置。
代码如下:
1.声明一个Key
var _addPhoneWigetKey = GlobalKey();
2.使用这个key
Container(
key: _addPhoneWigetKey,
)
3.通过这个key获取Container的位置以及高度。
///获取Widget在页面中的Y
double getY(BuildContext? buildContext) {
if (buildContext == null) {
return 0;
}
final RenderBox? box = buildContext.findRenderObject() as RenderBox?;
final topLeftPosition = box?.localToGlobal(Offset.zero);
return topLeftPosition?.dy ?? 0;
}
///获取Widget的高度
double getHeight(BuildContext? buildContext){
return buildContext?.size?.height ?? kFit(160);
}
double widgetY = 0;
double widgetHeight = 0;
///使用上面两个函数
void subInitState() {
widgetY = getY(_addPhoneWigetKey.currentContext);
widgetHeight = getHeight(_addPhoneWigetKey.currentContext);
print('subInitState $widgetY');
}
4.最重要的一步在合适的时机调用 subInitState
@override
Widget build(BuildContext context) {
///在这里调用
WidgetsBinding.instance?.addPostFrameCallback((_) => subInitState());
return Scaffold(
appBar: _getAppbar(),
body: Container(
color: WXColor.tabbarBackgroundColor,
child: _getListView(),
),
);
}
ScrollController _scrollController = ScrollController();
var list = ListView(
controller: _scrollController,
);
_scrollController.jumpTo(widgetY);
代码写完了。编译之后确实可以跳转到列表的指定位置,但是,当页面刚好一页时我想要跳转到指定位置,他会来回跳,(而且在键盘未弹出的时候也有这个问题)。
通过实践。只需要两个操作即可让TextField自动浮动在键盘上。 1.如果是滑动的列表
return Scaffold(
resizeToAvoidBottomInset: true,//默认就是true
),
);
如果是非滑动列表
ontainer(
color: WXColor.tabbarBackgroundColor,
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom
),
)
MediaQuery.of(context).viewInsets.bottom是获取键盘高度
搞定。
3. 点击删除电话号码会出现一个删除按钮让用户确认。
这个需要自定义Widget以及滑动效果比较麻烦放到最后。
4. 编辑时输入框右侧有一个清空按钮
具体思路就是使用 FocusNode检测输入框的变化(是否聚焦了)。
如果输入框被选中(聚焦后)&& 输入框时候有文字,就展示右侧文字清空按钮。否则就隐藏。
以下是全部代码。
import 'package:flutter/material.dart';
import 'package:wechat_flutter_practice/Head/WXHead.dart';
class AddPhoneTF extends StatefulWidget {
AddPhoneTF({required this.autofocus, required this.index, required this.phone,required this.onChanged,required this.onDelete, Key? key}) : super(key: key);
bool autofocus;
int index;
String phone;
Function(String) onChanged;
Function() onDelete;
@override
State<AddPhoneTF> createState() => _AddPhoneTFState();
}
class _AddPhoneTFState extends State<AddPhoneTF> {
FocusNode _tffocus = FocusNode();
@override
void initState() {
// TODO: implement initState
super.initState();
_tffocus.addListener(_onFocusChange);
}
_onFocusChange(){
print('_tffocus.canRequestFocus${_tffocus.hasFocus}');
// setState(() {
//
// });
}
Widget? suffixIcon(){
if (_tffocus.hasFocus && widget.phone != ''){
return InkWell(
onTap: (){
print('clock suffixIcon');
widget.onChanged('');
setState(() {
widget.phone = '';
});
},
child: Icon(Icons.highlight_remove, color: WXColor.nodeAppBarItemTextColor, size: kFit(50),),
);
}else {
return null;
}
}
@override
Widget build(BuildContext context) {
TextEditingController? controller;
if (widget.phone != ''){
controller = TextEditingController.fromValue(TextEditingValue(
text: widget.phone,
selection: TextSelection.fromPosition(TextPosition(
affinity: TextAffinity.downstream,
offset: widget.phone.length))));
}else{
controller = TextEditingController.fromValue(TextEditingValue(
text: ''
)
);
}
return Container(
// color: Colors.red,
height: kFit(160),
width: screenUtilSingle.screenHeight - kFit(140),
margin: EdgeInsets.only(left: kFit(50)),
child: TextField(
keyboardType: TextInputType.number,
autofocus: widget.autofocus,
controller: controller,
style: TextStyle(color: WXColor.wechatTitleColor),
focusNode: _tffocus,
onChanged: (String text){
print('AddPhoneTF==$text');
widget.onChanged(text);
setState(() {
widget.phone = text;
});
},
decoration: InputDecoration(
icon: InkWell(
onTap: (){
List<WXSheetItemEntity> alerts = [
WXSheetItemEntity(
title: Text(S.of(context).wechat_label_delete, style: TextStyle(color: Colors.red, fontSize: kFit(55))),
key: 'Delete'),
];
WXShowBottomSheet(context: context, alerts: alerts, onTap: (key){
if (key == 'Delete'){
widget.onDelete();
}
});
print('点击了删除');
},
child: Icon(Icons.remove_circle_outline, color: Color.fromRGBO(245, 42, 53, 1)),
),
suffixIcon: suffixIcon(),
border: InputBorder.none,
hintText: S.of(context).ContactsAddingAPhoneNumber,
hintStyle: TextStyle(
color: WXColor.nodeContentViewColor2,
)
),
),
);
}
}
5. 添加五个手机号后,下方要提示“最多可以添加5个号码”
这个就比较简单了,只是一个页面输入框数量判断,如果已经有五个输入框那么久隐藏添加按钮,并展示底部“最多可以添加5个号码”提示文字。