Flutter如何自定义应用程序内键盘(flutter,开发技术)

时间:2024-05-05 14:24:15 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

效果:

Flutter如何自定义应用程序内键盘

Flutter如何自定义应用程序内键盘

创建关键小部件

Flutter的优点是,通过组合更简单的小部件,可以轻松构建键盘等复杂布局。首先,您将创建几个简单的按键小部件。

文本键

我已经圈出了由您首先制作的TextKey小部件制作的键。

Flutter如何自定义应用程序内键盘

显示文本键(包括空格键)的自定义写意红色圆圈

将以下TextKey小部件添加到您的项目中:

classTextKeyextendsStatelessWidget{constTextKey({Keykey,@requiredthis.text,this.onTextInput,this.flex=1,}):super(key:key);finalStringtext;finalValueSetter<String>onTextInput;finalintflex;@overrideWidgetbuild(BuildContextcontext){returnExpanded(flex:flex,child:Padding(padding:constEdgeInsets.all(1.0),child:Material(color:Colors.blue.shade300,child:InkWell(onTap:(){onTextInput?.call(text);},child:Container(child:Center(child:Text(text)),),),),),);}}

以下是有趣的部分:

  • flex属性允许您的按键均匀分布在一行之间,甚至占据行的更大比例(如上图中的空格键)。

  • 按下按键后,它将以anonTextInput回调的形式将其值传递给键盘。

Backspace键

您还需要一个与TextKey小部件具有不同外观和功能的退格键。

Flutter如何自定义应用程序内键盘

退格键

将以下小部件添加到您的项目中:

classBackspaceKeyextendsStatelessWidget{constBackspaceKey({Key?key,this.onBackspace,this.flex=1,}):super(key:key);finalVoidCallback?onBackspace;finalintflex;@overrideWidgetbuild(BuildContextcontext){returnExpanded(flex:flex,child:Padding(padding:constEdgeInsets.all(1.0),child:Material(color:Colors.blue.shade300,child:InkWell(onTap:(){onBackspace?.call();},child:Container(child:Center(child:Icon(Icons.backspace),),),),),),);}

备注:

  • TextKey代码有点重复,因此一些重构是为了使其更加简介。

  • onBackspaceVoidCallback,因为不需要将任何文本传递回键盘。

将按键组成键盘

一旦有了按键,键盘就很容易布局,因为它们只是列中的行。

Flutter如何自定义应用程序内键盘

包含三行的列

这是代码。我省略了一些重复的部分,以便简洁。不过,你可以在文章的末尾找到它。

classCustomKeyboardextendsStatelessWidget{CustomKeyboard({Key?key,this.onTextInput,this.onBackspace,}):super(key:key);finalValueSetter<String>?onTextInput;finalVoidCallback?onBackspace;void_textInputHandler(Stringtext)=>onTextInput?.call(text);void_backspaceHandler()=>onBackspace?.call();@overrideWidgetbuild(BuildContextcontext){returnContainer(height:160,color:Colors.blue,child:Column(children:[buildRowOne(),buildRowTwo(),buildRowThree(),buildRowFour(),buildRowFive()],),);}ExpandedbuildRowOne(){returnExpanded(child:Row(children:[TextKey(text:'坚',onTextInput:_textInputHandler,),TextKey(text:'果',onTextInput:_textInputHandler,),TextKey(text:'祝',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowTwo(){returnExpanded(child:Row(children:[TextKey(text:'I',onTextInput:_textInputHandler,),TextKey(text:'n',onTextInput:_textInputHandler,),TextKey(text:'f',onTextInput:_textInputHandler,),TextKey(text:'o',onTextInput:_textInputHandler,),TextKey(text:'Q',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowThree(){returnExpanded(child:Row(children:[TextKey(text:'十',onTextInput:_textInputHandler,),TextKey(text:'五',onTextInput:_textInputHandler,),TextKey(text:'周',onTextInput:_textInputHandler,),TextKey(text:'年',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowFour(){returnExpanded(child:Row(children:[TextKey(text:'生',onTextInput:_textInputHandler,),TextKey(text:'日',onTextInput:_textInputHandler,),TextKey(text:'快',onTextInput:_textInputHandler,),TextKey(text:'乐',onTextInput:_textInputHandler,),TextKey(text:'!',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowFive(){returnExpanded(child:Row(children:[TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),BackspaceKey(onBackspace:_backspaceHandler,),],),);}}

有趣的部分:

  • 键盘收集按键的回调并传递它们。这样,任何使用CustomKeyboard的人都会收到回调。

  • 您可以看到第三行如何使用flex。空格键的弯曲为4,而退格的默认弯曲为1。这使得空格键占用了后空键宽度的四倍。

在应用程序中使用键盘

现在,您可以像这样使用自定义键盘小部件:

Flutter如何自定义应用程序内键盘

代码看起来是这样的:

CustomKeyboard(onTextInput:(myText){_insertText(myText);},onBackspace:(){_backspace();},),

处理文本输入

以下是_insertText方法的样子:

void_insertText(StringmyText){finaltext=_controller.text;finaltextSelection=_controller.selection;finalnewText=text.replaceRange(textSelection.start,textSelection.end,myText,);finalmyTextLength=myText.length;_controller.text=newText;_controller.selection=textSelection.copyWith(baseOffset:textSelection.start+myTextLength,extentOffset:textSelection.start+myTextLength,);}

_controllerTextFieldTextEditingController。你必须记住,可能有一个选择,所以如果有的话,请用密钥传递的文本替换它。

感谢这个,以提供帮助。*

处理退格

您会认为退格很简单,但有一些不同的情况需要考虑:

  • 有一个选择(删除选择)

  • 光标在开头(什么都不要做)

  • 其他任何事情(删除之前的角色)

以下是_backspace方法的实现:

void_backspace(){finaltext=_controller.text;finaltextSelection=_controller.selection;finalselectionLength=textSelection.end-textSelection.start;//Thereisaselection.if(selectionLength>0){finalnewText=text.replaceRange(textSelection.start,textSelection.end,'',);_controller.text=newText;_controller.selection=textSelection.copyWith(baseOffset:textSelection.start,extentOffset:textSelection.start,);return;}//Thecursorisatthebeginning.if(textSelection.start==0){return;}//DeletethepreviouscharacterfinalpreviousCodeUnit=text.codeUnitAt(textSelection.start-1);finaloffset=_isUtf16Surrogate(previousCodeUnit)?2:1;finalnewStart=textSelection.start-offset;finalnewEnd=textSelection.start;finalnewText=text.replaceRange(newStart,newEnd,'',);_controller.text=newText;_controller.selection=textSelection.copyWith(baseOffset:newStart,extentOffset:newStart,);}bool_isUtf16Surrogate(intvalue){returnvalue&0xF800==0xD800;}

即使删除之前的角色也有点棘手。如果您在有表情符号或其他代理对时只回退单个代码单元这将导致崩溃。作为上述代码中的变通办法,我检查了上一个字符是否是UFT-16代理,如果是,则后退了两个字符。(我从Flutter TextPainter源代码中获得了_isUtf16Surrogate方法。)然而,这仍然不是一个完美的解决方案,因为它不适用于像????????或????&zwj;????&zwj;????这样的字素簇,它们由多个代理对组成。不过,至少它不会

以下是象形文字和表情符号键盘作为演示:

Flutter如何自定义应用程序内键盘

????????????&zwj;????&zwj;

如果您对此有意见,请参阅此堆栈溢出问题。

防止系统键盘显示

如果您想将自定义键盘与aTextField一起使用,但系统键盘不断弹出,那会有点烦人。这毕竟是默认行为。

防止系统键盘显示的方法是将TextFieldreadOnly属性设置为true

TextField(...showCursor:true,readOnly:true,),

此外,将showCursor设置为true,使光标在您使用自定义键盘时仍然可以工作。

在系统键盘和自定义键盘之间切换

如果您想让用户选择使用系统键盘或自定义键盘,您只需为readOnly使用不同的值进行重建。

Flutter如何自定义应用程序内键盘

以下是演示应用程序中TextField的设置方式:

class_KeyboardDemoStateextendsState<KeyboardDemo>{TextEditingController_controller=TextEditingController();bool_readOnly=true;@overrideWidgetbuild(BuildContextcontext){returnScaffold(resizeToAvoidBottomInset:false,body:Column(children:[...TextField(controller:_controller,decoration:...,style:TextStyle(fontSize:24),autofocus:true,showCursor:true,readOnly:_readOnly,),IconButton(icon:Icon(Icons.keyboard),onPressed:(){setState((){_readOnly=!_readOnly;});},),

有趣的部分:

  • 当按下键盘IconButton时,更改_readOnly的值,然后重建布局。这会导致系统键盘隐藏或显示。

  • Scaffold上的resizeToAvoidBottomInset设置为false,允许系统键盘覆盖自定义键盘。另一个选项是在显示系统键盘时隐藏自定义键盘。然而,当我在实验中这样做时,我发现我必须使用单独的布尔值来隐藏自定义键盘,这样我就可以延迟显示它,直到系统键盘消失。否则,它会跳到系统键盘顶部一秒钟。

就这样!如您所见,制作自己的应用程序内键盘并不难。

完整代码

以下是我在本文中使用的演示应用程序的完整代码:

import'package:flutter/material.dart';voidmain()=>runApp(MyApp());classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(home:KeyboardDemo(),);}}classKeyboardDemoextendsStatefulWidget{@override_KeyboardDemoStatecreateState()=>_KeyboardDemoState();}class_KeyboardDemoStateextendsState<KeyboardDemo>{TextEditingController_controller=TextEditingController();bool_readOnly=true;@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text("大前端之旅的自定义键盘"),),resizeToAvoidBottomInset:false,body:Column(children:[Text("微信:xjg13690"),SizedBox(height:50),TextField(controller:_controller,decoration:InputDecoration(border:OutlineInputBorder(borderRadius:BorderRadius.circular(3),),),style:TextStyle(fontSize:24),autofocus:true,showCursor:true,readOnly:_readOnly,),IconButton(icon:Icon(Icons.keyboard),onPressed:(){setState((){_readOnly=!_readOnly;});},),Spacer(),CustomKeyboard(onTextInput:(myText){_insertText(myText);},onBackspace:(){_backspace();},),],),);}void_insertText(StringmyText){finaltext=_controller.text;finaltextSelection=_controller.selection;finalnewText=text.replaceRange(textSelection.start,textSelection.end,myText,);finalmyTextLength=myText.length;_controller.text=newText;_controller.selection=textSelection.copyWith(baseOffset:textSelection.start+myTextLength,extentOffset:textSelection.start+myTextLength,);}void_backspace(){finaltext=_controller.text;finaltextSelection=_controller.selection;finalselectionLength=textSelection.end-textSelection.start;//Thereisaselection.if(selectionLength>0){finalnewText=text.replaceRange(textSelection.start,textSelection.end,'',);_controller.text=newText;_controller.selection=textSelection.copyWith(baseOffset:textSelection.start,extentOffset:textSelection.start,);return;}//Thecursorisatthebeginning.if(textSelection.start==0){return;}//DeletethepreviouscharacterfinalpreviousCodeUnit=text.codeUnitAt(textSelection.start-1);finaloffset=_isUtf16Surrogate(previousCodeUnit)?2:1;finalnewStart=textSelection.start-offset;finalnewEnd=textSelection.start;finalnewText=text.replaceRange(newStart,newEnd,'',);_controller.text=newText;_controller.selection=textSelection.copyWith(baseOffset:newStart,extentOffset:newStart,);}bool_isUtf16Surrogate(intvalue){returnvalue&0xF800==0xD800;}@overridevoiddispose(){_controller.dispose();super.dispose();}}classCustomKeyboardextendsStatelessWidget{CustomKeyboard({Key?key,this.onTextInput,this.onBackspace,}):super(key:key);finalValueSetter<String>?onTextInput;finalVoidCallback?onBackspace;void_textInputHandler(Stringtext)=>onTextInput?.call(text);void_backspaceHandler()=>onBackspace?.call();@overrideWidgetbuild(BuildContextcontext){returnContainer(height:160,color:Colors.blue,child:Column(children:[buildRowOne(),buildRowTwo(),buildRowThree(),buildRowFour(),buildRowFive()],),);}ExpandedbuildRowOne(){returnExpanded(child:Row(children:[TextKey(text:'坚',onTextInput:_textInputHandler,),TextKey(text:'果',onTextInput:_textInputHandler,),TextKey(text:'祝',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowTwo(){returnExpanded(child:Row(children:[TextKey(text:'I',onTextInput:_textInputHandler,),TextKey(text:'n',onTextInput:_textInputHandler,),TextKey(text:'f',onTextInput:_textInputHandler,),TextKey(text:'o',onTextInput:_textInputHandler,),TextKey(text:'Q',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowThree(){returnExpanded(child:Row(children:[TextKey(text:'十',onTextInput:_textInputHandler,),TextKey(text:'五',onTextInput:_textInputHandler,),TextKey(text:'周',onTextInput:_textInputHandler,),TextKey(text:'年',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowFour(){returnExpanded(child:Row(children:[TextKey(text:'生',onTextInput:_textInputHandler,),TextKey(text:'日',onTextInput:_textInputHandler,),TextKey(text:'快',onTextInput:_textInputHandler,),TextKey(text:'乐',onTextInput:_textInputHandler,),TextKey(text:'!',onTextInput:_textInputHandler,),],),);}ExpandedbuildRowFive(){returnExpanded(child:Row(children:[TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),TextKey(text:'????',flex:2,onTextInput:_textInputHandler,),BackspaceKey(onBackspace:_backspaceHandler,),],),);}}classTextKeyextendsStatelessWidget{constTextKey({Key?key,@requiredthis.text,this.onTextInput,this.flex=1,}):super(key:key);finalString?text;finalValueSetter<String>?onTextInput;finalintflex;@overrideWidgetbuild(BuildContextcontext){returnExpanded(flex:flex,child:Padding(padding:constEdgeInsets.all(1.0),child:Material(color:Colors.blue.shade300,child:InkWell(onTap:(){onTextInput?.call(text!);},child:Container(child:Center(child:Text(text!)),),),),),);}}classBackspaceKeyextendsStatelessWidget{constBackspaceKey({Key?key,this.onBackspace,this.flex=1,}):super(key:key);finalVoidCallback?onBackspace;finalintflex;@overrideWidgetbuild(BuildContextcontext){returnExpanded(flex:flex,child:Padding(padding:constEdgeInsets.all(1.0),child:Material(color:Colors.blue.shade300,child:InkWell(onTap:(){onBackspace?.call();},child:Container(child:Center(child:Icon(Icons.backspace),),),),),),);}}
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Flutter如何自定义应用程序内键盘的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:springboot为异步任务规划自定义线程池如何实现下一篇:

10 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18