当前位置: 首页 > news >正文

实战网站开发忻州专业网站建设

实战网站开发,忻州专业网站建设,上海代理注册公司,火车wordpressFlutter 代码如何实现一个带有富文本显示和交互的页面。 前置知识点学习 RealRichText RealRichText 和 ImageSpan 不是 Flutter 框架中内置的组件#xff0c;而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 RichText 更丰富的功能#xff0c;比如在富文本…Flutter 代码如何实现一个带有富文本显示和交互的页面。 前置知识点学习 RealRichText RealRichText 和 ImageSpan 不是 Flutter 框架中内置的组件而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 RichText 更丰富的功能比如在富文本中插入图片、处理点击事件等。由于这些组件在标准 Flutter 中不存在我将解释如何可能实现类似的功能。 TextSpan TextSpan 是 Flutter 中用于构建富文本的基本组件之一。它允许你在同一个文本组件中混合和匹配不同的文本样式和手势识别功能。TextSpan 通常与 RichText 组件一起使用以显示复杂的文本布局。 TextSpan 的基本结构 TextSpan 是一个不可变的、递归的数据结构可以包含其他 TextSpan从而允许嵌套不同的文本样式。 TextSpan({TextStyle? style,String? text,ListInlineSpan? children,GestureRecognizer? recognizer,String? semanticsLabel, }) 关键属性 style: 指定文本的样式例如字体大小、颜色、粗细等。 类型为 TextStyle。 text: 要显示的文本字符串。 text 和 children 之间是互斥的如果需要在一个 TextSpan 中显示多个文本片段通常使用 children。 children: 一个 InlineSpan通常为 TextSpan的列表用于嵌套子文本。 允许创建复杂的文本结构如不同样式的文本段落。 recognizer: 用于处理文本的手势识别例如点击事件。 通常使用 TapGestureRecognizer 来处理点击事件。 semanticsLabel: 为文本提供一个可供屏幕阅读器使用的标签帮助无障碍访问。 使用示例 下面是一个简单的例子展示如何使用 TextSpan 来创建一个包含多种样式和交互的文本。 import package:flutter/gestures.dart; import package:flutter/material.dart;class RichTextExample extends StatelessWidget {const RichTextExample({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Rich Text Example)),body: Center(child: RichText(text: TextSpan(text: Hello ,style: const TextStyle(color: Colors.black, fontSize: 18),children: TextSpan[const TextSpan(text: bold, style: TextStyle(fontWeight: FontWeight.bold)),const TextSpan(text: and ,),const TextSpan(text: italic,style: TextStyle(fontStyle: FontStyle.italic),),TextSpan(text: clickable ,style: const TextStyle(color: Colors.blue),recognizer: TapGestureRecognizer()..onTap () {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(Clickable text clicked!)),);},),const TextSpan(text: text.,),],),),),);} }ImageSpan ImageSpan 是一种在富文本中嵌入图片的技术。在 Flutter 中虽然没有直接提供一个名为 ImageSpan 的组件但你可以通过使用 WidgetSpan 来实现类似的功能。WidgetSpan 允许你在 RichText 中插入任意的 Flutter 小部件包括图片。 使用 WidgetSpan 实现 ImageSpan 的功能 WidgetSpan 是 InlineSpan 的子类可以在 TextSpan 列表中使用来嵌入小部件。通过这种方式你可以在文本段落中插入图片或者其他小部件。 示例代码 import package:flutter/material.dart;class RichTextWithImageExample extends StatelessWidget {const RichTextWithImageExample({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Rich Text with Image Example)),body: Center(child: RichText(text: TextSpan(style: const TextStyle(color: Colors.black, fontSize: 18),children: InlineSpan[const TextSpan(text: This is an example of ),WidgetSpan(child: Image.asset(static/demo.png,width: 24,height: 24,)),const TextSpan(text: in a rich text widget.),]),),),);} }解释 RichText 和 TextSpan: RichText 用于显示复杂的文本布局TextSpan 用于定义文本的样式和内容。 WidgetSpan: WidgetSpan 可以嵌入任何小部件。在这个例子中它用于插入一个图片。 child 属性接受一个 Widget这里使用 Image.asset 来加载本地图片。 图片资源: 确保图片路径正确并在 pubspec.yaml 中声明图片资源。 例如 flutter:assets:- assets/demo.png 使用场景 图文混排: 当需要在同一个文本段落中展示图片和文本比如图标、表情符号或其他装饰性元素。 动态内容: 在文章或聊天应用中以富文本形式展示内容图片作为内嵌元素。 自定义格式: 创建带有图片的复杂格式文本比如新闻应用中的插图或注释。 通过 WidgetSpan你可以在 Flutter 的文本组件中灵活地插入图片和其他小部件实现更复杂的文本布局和丰富的用户界面体验。 TapGestureRecognizer TapGestureRecognizer 是 Flutter 中用于检测点击手势的一个手势识别器。它通常用于处理文本中的点击事件特别是在 TextSpan 中使得文本中的某些部分可以响应用户的点击操作。 基本使用 TapGestureRecognizer 是 GestureRecognizer 的一个子类它专门用于处理点击tap事件。通常情况下它与 RichText 和 TextSpan 结合使用以实现文本的可点击功能。 如何使用 TapGestureRecognizer 以下是一个简单示例展示如何在 TextSpan 中使用 TapGestureRecognizer使得文本的一部分可以被点击并响应事件 import package:flutter/gestures.dart; import package:flutter/material.dart; class TapGestureExample extends StatelessWidget {const TapGestureExample({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Tap Gesture Recognizer Example)),body: Center(child: RichText(text: TextSpan(text: Click ,style: const TextStyle(color: Colors.black, fontSize: 18),children: TextSpan[TextSpan(text: here,style: const TextStyle(color: Colors.blue, decoration: TextDecoration.underline),recognizer: TapGestureRecognizer()..onTap () {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(Text clicked!)),);},),const TextSpan(text: to see the effect.,),],),),),);} } 解释 RichText 和 TextSpan: RichText 用于显示富文本。通过 TextSpan你可以定义不同的文本样式和内容。 TapGestureRecognizer: 创建一个 TapGestureRecognizer 实例并将其分配给 TextSpan 的 recognizer 属性。 使用 ..onTap级联操作符来定义 onTap 回调函数当用户点击该文本时调用。 响应点击: 在 onTap 回调中使用 ScaffoldMessenger 显示一个 SnackBar以反馈用户的点击操作。 注意事项 释放资源: 如果在有状态的小部件中使用 TapGestureRecognizer请确保在 dispose 方法中调用 dispose 方法来释放手势识别器以避免内存泄漏。 多手势识别: TapGestureRecognizer 可以与其他类型的手势识别器一起使用。使用 GestureDetector 可以创建更复杂的手势识别场景。 用户体验: 确保可点击的文本有视觉上的提示如颜色变化或下划线以便用户能够清楚地识别哪些文本是可交互的。 通过 TapGestureRecognizer你可以为文本添加交互功能使得应用的用户界面更加动态和响应用户操作。 富文本代码实现学习 import package:flutter/gestures.dart; import package:flutter/material.dart; import package:gsy_flutter_demo/widget/rich/real_rich_text.dart;class RichTextDemoPage extends StatefulWidget {const RichTextDemoPage({super.key});override_RichTextDemoState createState() _RichTextDemoState(); }class _RichTextDemoState extends StateRichTextDemoPage {overrideWidget build(BuildContext mainContext) {return Scaffold(appBar: AppBar(title: const Text(RichTextDemoPage),),body: Container(margin: const EdgeInsets.all(10),child: Builder(builder: (context) {return Center(child: RealRichText([TextSpan(text: A Text Link,style: const TextStyle(color: Colors.red, fontSize: 14),recognizer: TapGestureRecognizer()..onTap () {show(context, Link Clicked.);},),ImageSpan(const AssetImage(static/demo.png),imageWidth: 24,imageHeight: 24,),ImageSpan(const AssetImage(static/demo.png),imageWidth: 24,imageHeight: 24,margin: const EdgeInsets.symmetric(horizontal: 10)),const TextSpan(text: 哈哈哈,style: TextStyle(color: Colors.yellow, fontSize: 14),),TextSpan(text: Somebody,style: const TextStyle(color: Colors.black,fontSize: 14,fontWeight: FontWeight.bold),recognizer: TapGestureRecognizer()..onTap () {show(context, Link Clicked.);},),TextSpan(text: #RealRichText# ,style: const TextStyle(color: Colors.blue, fontSize: 14),recognizer: TapGestureRecognizer()..onTap () {show(context, Link Clicked.);},),const TextSpan(text: showing a bigger image,style: TextStyle(color: Colors.black, fontSize: 14),),ImageSpan(const AssetImage(static/demo.png),imageWidth: 24,imageHeight: 24,margin: const EdgeInsets.symmetric(horizontal: 5)),const TextSpan(text: and seems working perfect……,style: TextStyle(color: Colors.black, fontSize: 14),),]),);}),),);}show(context, text) {ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(text),action: SnackBarAction(label: ACTION,onPressed: () {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(You pressed snackbar\s action.),));},),));} }三方flutter库中的富文本实现源码 import dart:ui as ui show Image;import package:flutter/material.dart; import package:flutter/rendering.dart;/// According to the related Flutter Issues(#2022) , /// Inline-Image-In-Text is a long-time(2 years) missing feature since RichText(or the underlying Paragraph) does only support pure text. /// But we can solve this problem in a simple/tricky way: /// /// 1. Regarde the images as a particular blank TextSpan, /// convert images width and height to textspans letterSpacing and fontSize. /// the origin paragraph will do the layout operation and leave the desired image space for us. /// 2. Override the paint function /// calculate the right offset via the getOffsetForCaret() api to draw the image over the space. /// /// The only thing you have to do is converting your origin text to a TextSpan/ImageSpan List first. /// /// {tool sample} /// /// dart /// RealRichText([ /// TextSpan( /// text: showing a bigger image, /// style: TextStyle(color: Colors.black, fontSize: 14), /// ), /// ImageSpan( /// AssetImage(packages/real_rich_text/images/emoji_10.png), /// width: 40, /// height: 40, /// ), /// TextSpan( /// text: and seems working perfect……, /// style: TextStyle(color: Colors.black, fontSize: 14), /// ), /// ]) /// /// {end-tool} /// class RealRichText extends Text {final ListTextSpan textSpanList;const RealRichText(this.textSpanList, {super.key,TextStyle? style,TextAlign textAlign TextAlign.start,TextDirection? textDirection,bool softWrap true,TextOverflow overflow TextOverflow.clip,TextScaler? textScaler,int? maxLines,Locale? locale,}) : super(,style: style,textAlign: textAlign,textDirection: textDirection,softWrap: softWrap,overflow: overflow,textScaler: textScaler,maxLines: maxLines,locale: locale);ListTextSpan extractAllNestedChildren(TextSpan textSpan) {if (textSpan.children null || textSpan.children!.isEmpty) {return [textSpan];}ListTextSpan childrenSpan [];for (var child in textSpan.children!) {childrenSpan.addAll(extractAllNestedChildren(child as TextSpan));}return childrenSpan;}overrideWidget build(BuildContext context) {final DefaultTextStyle defaultTextStyle DefaultTextStyle.of(context);TextStyle? effectiveTextStyle style;if (style null || style!.inherit) {effectiveTextStyle defaultTextStyle.style.merge(style);}if (MediaQuery.boldTextOf(context)) {effectiveTextStyle effectiveTextStyle!.merge(const TextStyle(fontWeight: FontWeight.bold));}TextSpan textSpan TextSpan(style: effectiveTextStyle,text: ,children: extractAllNestedChildren(TextSpan(style: effectiveTextStyle,text: ,children: textSpanList,)));// pass the context to ImageSpan to create a ImageConfigurationfor (var f in textSpan.children!) {if (f is ImageSpan) {f.updateImageConfiguration(context);}}Widget result _RichTextWrapper(textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,textDirection: textDirection,// RichText uses Directionality.of to obtain a default if this is null.locale: locale,// RichText uses Localizations.localeOf to obtain a default if this is nullsoftWrap: softWrap ?? defaultTextStyle.softWrap,overflow: overflow ?? defaultTextStyle.overflow,textScaler: textScaler ?? MediaQuery.textScalerOf(context),maxLines: maxLines ?? defaultTextStyle.maxLines,text: textSpan);if (semanticsLabel ! null) {result Semantics(textDirection: textDirection,label: semanticsLabel,child: ExcludeSemantics(child: result,));}return result;} }/// Since flutter engine does not support inline-image for now, we have to support this feature via a tricky solution: /// convert image to a particular TextSpan whose text always be \u200B(a zero-width-space). /// set letterSpacing by the required image width /// set fontSize by the required image height class ImageSpan extends TextSpan {final double imageWidth;final double imageHeight;final EdgeInsets? margin;final ImageProvider imageProvider;final ImageResolver imageResolver;ImageSpan(this.imageProvider, {this.imageWidth 14.0,this.imageHeight 14.0,this.margin,super.recognizer,}) : imageResolver ImageResolver(imageProvider),super(style: TextStyle(color: Colors.transparent,letterSpacing:imageWidth (margin null ? 0 : margin.horizontal),height: 1,fontSize: (imageHeight / 1.15) (margin null ? 0 : margin.vertical)),text: \u200B,children: []);void updateImageConfiguration(BuildContext context) {imageResolver.updateImageConfiguration(context, imageWidth, imageHeight);}double get width imageWidth (margin null ? 0 : margin!.horizontal);double get height imageHeight (margin null ? 0 : margin!.vertical); }typedef ImageResolverListener void Function(ImageInfo imageInfo, bool synchronousCall);class ImageResolver {final ImageProvider imageProvider;ImageStream? _imageStream;ImageConfiguration? _imageConfiguration;ui.Image? image;ImageResolverListener? _listener;ImageResolver(this.imageProvider);/// set the ImageConfiguration from outsidevoid updateImageConfiguration(BuildContext context, double width, double height) {_imageConfiguration createLocalImageConfiguration(context,size: Size(width, height),);}ImageStreamListener? imageStreamListener;void resolve(ImageResolverListener listener) {assert(_imageConfiguration ! null);final ImageStream? oldImageStream _imageStream;_imageStream imageProvider.resolve(_imageConfiguration!);assert(_imageStream ! null);_listener listener;if (_imageStream!.key ! oldImageStream?.key) {if (imageStreamListener ! null) {oldImageStream?.removeListener(imageStreamListener!);}imageStreamListener ?? ImageStreamListener(_handleImageChanged);_imageStream!.addListener(imageStreamListener!);}}void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall) {image imageInfo.image;_listener?.call(imageInfo, synchronousCall);}void addListening() {if (_listener ! null) {imageStreamListener ?? ImageStreamListener(_handleImageChanged);_imageStream?.addListener(imageStreamListener!);}}void stopListening() {if (imageStreamListener ! null) {_imageStream?.removeListener(imageStreamListener!);}} }/// Just a subclass of RichText for overriding createRenderObject /// to return a [_RealRichRenderParagraph] object /// /// No more special purpose. class _RichTextWrapper extends RichText {_RichTextWrapper({required TextSpan super.text,super.textAlign,super.textDirection,super.softWrap,super.overflow,super.textScaler,super.maxLines,super.locale,}) : assert(maxLines null || maxLines 0);overrideRenderParagraph createRenderObject(BuildContext context) {assert(textDirection ! null || debugCheckHasDirectionality(context));return _RealRichRenderParagraph(text as TextSpan,textAlign: textAlign,textDirection: textDirection ?? Directionality.of(context),softWrap: softWrap,overflow: overflow,textScaler: textScaler,maxLines: maxLines,locale: locale ?? Localizations.localeOf(context),);} }/// paint the image on the top of those ImageSpans blank space class _RealRichRenderParagraph extends RenderParagraph {_RealRichRenderParagraph(TextSpan super.text,{required super.textAlign,required super.textDirection,required super.softWrap,required super.overflow,required super.textScaler,super.maxLines,super.locale});overridevoid paint(PaintingContext context, Offset offset) {super.paint(context, offset);// Here it is!paintImageSpan(context, offset);}overridevoid attach(covariant Object owner) {super.attach(owner as PipelineOwner);for (var textSpan in (text as TextSpan).children!) {if (textSpan is ImageSpan) {textSpan.imageResolver.addListening();}}}overridevoid detach() {super.detach();for (var textSpan in (text as TextSpan).children!) {if (textSpan is ImageSpan) {textSpan.imageResolver.stopListening();}}}overridevoid performLayout() {super.performLayout();debugPrint(size $size);}/// this method draws inline-image over blank text space.void paintImageSpan(PaintingContext context, Offset offset) {final Canvas canvas context.canvas;final Rect bounds offset size;debugPrint(_RealRichRenderParagraph offset$offset bounds$bounds);canvas.save();int textOffset 0;for (TextSpan textSpanin (text as TextSpan).children as IterableTextSpan) {if (textSpan is ImageSpan) {// this is the top-center point of the ImageSpanOffset offsetForCaret getOffsetForCaret(TextPosition(offset: textOffset),bounds,);// found this is a overflowed image. ignore itif (textOffset ! 0 offsetForCaret.dx 0 offsetForCaret.dy 0) {return;}// this is the top-left point of the ImageSpan.// Usually, offsetForCaret indicates the top-center offset// except the first text which is always (0, 0)Offset topLeftOffset Offset(offset.dx offsetForCaret.dx -(textOffset 0 ? 0 : textSpan.width / 2),offset.dy offsetForCaret.dy);debugPrint(_RealRichRenderParagraph ImageSpan, textOffset $textOffset, offsetForCaret$offsetForCaret, topLeftOffset$topLeftOffset);// if image is not ready: wait for async ImageInfoif (textSpan.imageResolver.image null) {textSpan.imageResolver.resolve((imageInfo, synchronousCall) {if (synchronousCall) {paintImage(canvas: canvas,rect: topLeftOffset Size(textSpan.width, textSpan.height),image: textSpan.imageResolver.image!,fit: BoxFit.scaleDown,alignment: Alignment.center);} else {if (owner null || !owner!.debugDoingPaint) {markNeedsPaint();}}});textOffset textSpan.toPlainText().length;continue;}// else: just paint it. bottomCenter Alignment seems better...paintImage(canvas: canvas,rect: topLeftOffset Size(textSpan.width, textSpan.height),image: textSpan.imageResolver.image!,fit: BoxFit.scaleDown,alignment: Alignment.center);}textOffset textSpan.toPlainText().length;}canvas.restore();} }
http://www.w-s-a.com/news/522599/

相关文章:

  • 适合大学生创业的网站建设类型吉林省舒兰市建设银行网站
  • 呼和浩特网站建设哪家好培训学校加盟费用
  • 网站如何做友情链接有道云笔记WordPress
  • 贵阳企业网站建设制作赤峰浩诚网站建设公司
  • asp官方网站微信模板素材
  • wordpress 留言给站长发邮件做百度推广员赚钱吗
  • 北京建站公司做网站价格专门找人做软件的网站
  • 商务网站的特点ui软件界面设计
  • 广州个性化网站开发网站索引量是什么意思
  • 公司网站制作专业公司python做后台网站的多吗
  • 桂林建站平台哪家好给别人做网站怎么收取费用
  • python做网站显示表格用visual做的网站
  • 彩票网站建设需要什么聊城网站建设首选天成网络
  • 安徽建设工程网站wordpress标签云代码
  • 推荐佛山顺德网站建设手机网站建设域名空间
  • 电子商务网站建设策划书例子企业官网用什么cms系统
  • 网站栏目设计怎么写平面设计接单报价表
  • 做网站美工要学什么网站推广的方法包括
  • 哪个网站可以做笔译兼职wordpress加表单
  • 百度站内搜索 wordpress微餐饮建站费用
  • 用什么做网站的访问量统计制作手工作品
  • 微信公众号搭建网站河南卫生基层系统网站建设
  • steam账号注册网站重庆手机版建站系统哪家好
  • 中新生态城建设局门户网站wordpress云盘视频播放
  • 大型网站开发基本流程wordpress记录用户搜索
  • 云服务器安装win系统做网站wordpress边栏扩大尺寸
  • 网站开发面试自我介绍软件下载网站如何建设
  • 可以做翻译任务的网站陕西省建设厅八大员证
  • 昆明 网站推广重庆网页优化seo公司
  • 网站排名下降怎么上去设计一套app页面多少钱