那里网站建设好,软件工程公司有哪些,怎么用国外的服务器做网站,毕业设计题目Flutter 实现一个容器内部元素可平移、缩放和旋转等功能#xff08;八#xff09;
Flutter: 3.35.7
前面我们实现了元素的变换操作#xff0c;单纯的变换操作只是为了后续功能的实现#xff0c;接下来我们就开始扩展容器的属性。
我们要新增容器功能的扩展#xff0c;那么…Flutter 实现一个容器内部元素可平移、缩放和旋转等功能八Flutter: 3.35.7前面我们实现了元素的变换操作单纯的变换操作只是为了后续功能的实现接下来我们就开始扩展容器的属性。我们要新增容器功能的扩展那么就要划分新的区域来实现这部分功能所以我们得重新规划和计算。有许多方式实现扩展功能区域第一种就是划分区域划分下面为属性扩展区域元素变换区域则会相应的压缩所以涉及到变换的计算有使用到容器宽高属性的都要变化第二种就是将功能区域设计成一个底部弹框覆盖在元素变换区域在元素变换过程中隐藏未变换就展示这样就不用更改不过得制定弹出时机。这里我们使用第一种感兴趣的可以自行研究第二种。常量新增配置/// 底部功能区域的高度staticconstdouble bottomHeight100;/// 变换区域的左右marginstaticconstdouble transformMargin20;重新计算宽高、重新设计布局和更改变换过程中应用到容器宽高的计算将变换计算中的_containerWidth换成_transformWidth_containerHeight换成_transformHeight/// 变换区域的宽doubleget_transformWidth{return_width-ConstantsConfig.transformMargin*2;}/// 变换区域的高doubleget_transformHeight{return_height-ConstantsConfig.bottomHeight;}/// 最终容器的宽doubleget_width{return_containerWidth0?(widget.containerWidth??double.infinity):_containerWidth;}/// 最终容器的高doubleget_height{return_containerHeight0?(widget.containerHeight??double.infinity):_containerHeight;}SizedBox(key:_multipleTransformContainerGlobalKey,width:_width,height:_height,child:_containerWidth0||_containerHeight0?null:Column(children:[// 变换区域GestureDetector(// 其他省略...child:Container(width:_transformWidth,height:_transformHeight,margin:EdgeInsets.symmetric(horizontal:ConstantsConfig.transformMargin,),color:Colors.white,child:_containerWidth0||_containerHeight0?null:Stack(// 其他省略...),),),// 底部功能区域Container(height:ConstantsConfig.bottomHeight,color:Colors.white60,),],),);运行效果顺便将使用外层的容器设置了顶部边距。后续的功能扩展就在这个小小的区域上面实现。规划完区域我们就要对变换元素做出修改总不可能一直操作一个矩形吧按照部分经验这种功能操作的大多数是图片文本所以我们以这两种来划分元素的类型为例后续如果有新的类型再增加即可。新增元素类型enumElementType{/// 图片imageType(type:image),/// 文本textType(type:text),;finalString type;constElementType({requiredthis.type});}classElementModel{// 其他省略.../// 元素的类型finalString type;/// 如果是元素是图片类型图片的pathfinalString?imagePath;/// 如果元素是文本类型文本属性finalElementTextOptions?textOptions;// 其他省略...}// 其他省略...enumTextAlignType{left(type:left,textAlign:TextAlign.left),right(type:right,textAlign:TextAlign.right),center(type:center,textAlign:TextAlign.center),justify(type:justify,textAlign:TextAlign.justify),;finalString?type;finalTextAlign textAlign;constTextAlignType({requiredthis.type,requiredthis.textAlign,});}classElementTextOptions{constElementTextOptions({requiredthis.text,this.textHeightConstantsConfig.initFontHeight,this.fontSizeConstantsConfig.initFontSize,this.fontColorColors.black,this.fontWeight,this.fontFamily,this.textAlignConstantsConfig.initFontAlign,this.letterSpacing,});/// 文本内容finalString text;/// 文本行高finaldouble textHeight;/// 文本大小finaldouble fontSize;/// 文本颜色finalColor fontColor;/// 文本字重100-10001000就是boldfinalint?fontWeight;/// 文本字体finalString?fontFamily;/// 文本对齐方式finalString?textAlign;/// 文本字间距finaldouble?letterSpacing;ElementTextOptionscopyWith({String?text,double?textHeight,double?fontSize,Color?fontColor,int?fontWeight,String?fontFamily,String?textAlign,double?letterSpacing,}){returnElementTextOptions(text:text??this.text,textHeight:textHeight??this.textHeight,fontSize:fontSize??this.fontSize,fontColor:fontColor??this.fontColor,fontWeight:fontWeight??this.fontWeight,fontFamily:fontFamily??this.fontFamily,textAlign:textAlign??this.textAlign,letterSpacing:letterSpacing??this.letterSpacing,);}}定义完属性我们就开始新增图片元素在功能区新增图片选择按钮从本地文件中选择图片所以我们得增加图片选择插件(image_picker)在获取到图片的时候再将部分必要信息填充然后将选择的图片添加到元素列表中即可// 其他省略...classImageElementAddextendsStatefulWidget{constImageElementAdd({super.key,requiredthis.transformWidth,requiredthis.transformHeight,requiredthis.addElement,});/// 变换区域的宽用于计算选择图片的初始宽度finaldouble transformWidth;/// 变换区域的高用于计算选择图片的初始高度finaldouble transformHeight;/// 新增元素方法用于将选择的图片添加到元素列表中finalFunction(ElementModel)addElement;overrideStateImageElementAddcreateState()_ImageElementAddState();}class_ImageElementAddStateextendsStateImageElementAdd{/// 选择图片Futurevoid_imagePicker()async{finalImagePicker pickerImagePicker();finalXFile?imageFileawaitpicker.pickImage(source:ImageSource.gallery);if(imageFile!null){finalimageInfoawait_loadImageFromFile(imageFile.path);widget.addElement(ElementModel(id:DateTime.now().millisecondsSinceEpoch,elementWidth:imageInfo.$1,elementHeight:imageInfo.$2,type:ElementType.imageType.type,imagePath:imageFile.path,));}}/// 从本地文件加载图片并获取宽高////// 通过[filePath]获取这张图片的宽高Future(double,double)_loadImageFromFile(String filePath)async{finalfileFile(filePath);finalbytesawaitfile.readAsBytes();finalcodecawaitui.instantiateImageCodec(bytes);finalframeawaitcodec.getNextFrame();finalimageInfoframe.image;finaldouble imageWidthimageInfo.width.toDouble();finaldouble imageHeightimageInfo.height.toDouble();finaldouble tempContainerWidthwidget.transformWidth/2;finaldouble tempContainerHeightwidget.transformHeight/2;double tempWidthimageWidth;double tempHeightimageHeight;// 以长边来设置图片的最终初始宽高if(imageWidthimageHeight){tempWidthimageWidthtempContainerWidth?tempContainerWidth:imageWidth;tempHeight(tempWidth/imageWidth)*imageHeight;}else{tempHeightimageHeighttempContainerHeight?tempContainerHeight:imageHeight;tempWidth(tempHeight/imageHeight)*imageWidth;}return(tempWidth,tempHeight);}overrideWidgetbuild(BuildContext context){returnElevatedButton(onPressed:_imagePicker,child:Text(图片选择),);}}运行效果这样我们就简单实现了图片元素的新增。接下来我们简单实现文本元素的新增。文本元素就需要考虑多些了因为涉及到文本属性的修改新增的时候将对应的属性修改放开后续也涉及到编辑所以封装成一个部件为了后续能更好的展示我们封装成一个Positioned通过控制状态来展示// 其他省略...classTextOptionsextendsStatefulWidget{constTextOptions({super.key,requiredthis.transformWidth,requiredthis.isShow,requiredthis.addElement,});/// 变换区域的宽用于计算选择文本元素的最大宽度finaldouble transformWidth;/// 文本元素属性部件是否展示finalbool isShow;/// 新增元素方法用于新增文本部件finalFunction(ElementModel)addElement;overrideStateTextOptionscreateState()_TextOptionsState();}class_TextOptionsStateextendsStateTextOptions{/// 新增文本元素void_onAddTextElement(String text){}overrideWidgetbuild(BuildContext context){returnAnimatedPositioned(duration:Duration(milliseconds:100),left:0,right:0,bottom:widget.isShow?0:-ConstantsConfig.fontOptionsWidgetHeight,child:Container(padding:EdgeInsets.all(20),color:Colors.white,height:ConstantsConfig.fontOptionsWidgetHeight,child:TextField(style:TextStyle(fontSize:15,fontWeight:FontWeight.w600,height:1.333,),decoration:InputDecoration(isCollapsed:true,contentPadding:EdgeInsets.zero,border:InputBorder.none,counter:constOffstage(),hintText:请输入,hintStyle:TextStyle(fontSize:15,fontWeight:FontWeight.w600,height:1.333,),),onSubmitted:_onAddTextElement,),),);}}// 其他省略...classTextElementAddextendsStatefulWidget{constTextElementAdd({super.key,requiredthis.onShowTextOptions,});/// 展示文本属性部件finalFunction(bool)onShowTextOptions;overrideStateTextElementAddcreateState()_TextElementAddState();}class_TextElementAddStateextendsStateTextElementAdd{void_onShowText(){widget.onShowTextOptions(true);}overrideWidgetbuild(BuildContext context){returnElevatedButton(onPressed:_onShowText,child:Text(文本,style:TextStyle(fontSize:12,),),);}}运行效果接下来就在这个基础上实现新增文本的逻辑。首先新增文本的时候我也也要得到这个字符串应该拥有的宽高。通过 flutter 提供的 TextPainter 来获取/// 计算文本的宽高////// 传入文本字符串[text]、文本的样式[style]和最大的宽度[maxWidth]来计算文本的宽高static(double,double)calculateTextSize({required String text,required TextStyle style,required double maxWidth}){if(text.isEmpty){return(0,0);}finalTextPainter textPainterTextPainter(text:TextSpan(text:text,style:style),textDirection:TextDirection.ltr,)..layout(maxWidth:maxWidth);finaltempWidthtextPainter.width;finaltempHeighttextPainter.height;// 不能小于最小值finalminSizeConstantsConfig.minSize;return(tempWidthminSize?minSize:tempWidth,tempHeightminSize?minSize:tempHeight);}获取到文本元素的宽高后就可以实现新增的逻辑了/// 新增文本元素void_onAddTextElement(String text){// 一些初始化的文本属性TextStyle styleTextStyle(fontSize:ConstantsConfig.initFontSize,height:ConstantsConfig.initFontHeight,);final(tempWidth,tempHeight)TransformUtils.calculateTextSize(text:text,style:style,maxWidth:widget.transformWidth,);widget.addElement(ElementModel(id:DateTime.now().millisecondsSinceEpoch,elementHeight:tempHeight,elementWidth:tempWidth,type:ElementType.textType.type,textOptions:ElementTextOptions(text:text),));}运行效果这样我们就简单实现了新增文本元素下面就来设计文本元素属性的修改。因为属性比较多我们可以使用tab来分开前面简单封装过一个tab感兴趣的朋友可以看看也可以使用滑动组件这里为了方便所以使用滑动组件我们以行高属性为例其他的实现类似只是结构稍微调整即可/// 设置文本的属性void_setTextOptions(ElementTextOptions textOptions){if(_currentElement?.typeElementType.textType.type){TextStyle styleTextStyle(fontSize:textOptions.fontSize,height:textOptions.textHeight,letterSpacing:textOptions.letterSpacing,fontWeight:TransformUtils.getFontWeight(textOptions.fontWeight,),);final(tempWidth,tempHeight)TransformUtils.calculateTextSize(text:textOptions.text,style:style,maxWidth:_currentElement!.elementWidth,);_currentElement_currentElement?.copyWith(// elementWidth: tempWidth,elementHeight:tempHeight,textOptions:_currentElement?.textOptions?.copyWith(text:textOptions.text,textHeight:textOptions.textHeight,fontSize:textOptions.fontSize,fontColor:textOptions.fontColor,fontWeight:textOptions.fontWeight,fontFamily:textOptions.fontFamily,textAlign:textOptions.textAlign,letterSpacing:textOptions.letterSpacing,),);_onChange();}}void_onReduceFontHeight(){if(widget.textOptions!nullwidget.textOptions!.textHeight0){widget.setTextOptions(widget.textOptions!.copyWith(textHeight:(Decimal.parse(${widget.textOptions!.textHeight})-Decimal.parse(0.1)).toDouble(),),);}}void_onAddFontHeight(){if(widget.textOptions!null){widget.setTextOptions(widget.textOptions!.copyWith(textHeight:(Decimal.parse(${widget.textOptions!.textHeight})Decimal.parse(0.1)).toDouble(),),);}}这样我们就简单实现了属性的修改样式什么的后面有时间再慢慢调整现在只是功能为主毕竟真实的开发总会有UI的。下面快速预览一下文本属性修改的完整效果字体因为难得找相关的所以就暂未实现。感兴趣的也可以关注我的微信公众号【前端学习小营地】不定时会分享一些小功能好了今天的分享到此结束了感谢阅读拜拜