Flutter学习-微信开发之给好友添加电话号码。

434 阅读3分钟

今天开发微信通讯录好友添加备注中的电话添加功能,发现很多细节。处理起来比较麻烦,所以特意记录一下。

IMG_FA15F6A13448-1.jpeg

这里有很多细节点

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个号码”提示文字。