您的位置:首页 > 健康 > 美食 > Flutter-->自定义Widget(类比Android自定义View)

Flutter-->自定义Widget(类比Android自定义View)

2024/12/24 11:05:35 来源:https://blog.csdn.net/angcyo/article/details/141611014  浏览:    关键词:Flutter-->自定义Widget(类比Android自定义View)

Android自定义View

简单复习一下Android中自定义View的流程:

创建一个类CustomView继承自View然后实现如下方法:

  • onDraw方法: 进行绘制操作, 确定自身的内容
  • onMeasure方法: 进行测量操作, 确定自身的大小, 位置由parent决定
  • onTouchEvent方法: 进行手势处理
class CustomView(context: Context, attrs: AttributeSet?) : View(context, attrs) {override fun onTouchEvent(event: MotionEvent?): Boolean {//进行手势处理return super.onTouchEvent(event)}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {//进行测量操作, 确定自身的大小, 位置由parent决定}override fun onDraw(canvas: Canvas) {//进行绘制操作, 确定自身的内容}}

自定义属性通过xml配置:

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="CustomView"><attr name="custom_attr" format="boolean" /></declare-styleable>
</resources>

这样一个自定义View就实现了…

Flutter自定义Widget

那么在Flutter中, 怎么自定义Widget呢? 准确来说, 应该是自定义RenderObject.

这里请忽略CustomPaint小部件…

class CustomRenderObject extends RenderBox {bool hitTestSelf(Offset position) {return true;}void handleEvent(PointerEvent event, BoxHitTestEntry entry) {//进行手势处理, 这里需要注意的是,//如果想要`handleEvent`方法被回调, 那么`hitTestSelf`必须返回true}void performLayout() {//进行测量操作, 确定自身的大小, 位置由parent决定}void paint(PaintingContext context, Offset offset) {//进行绘制操作, 确定自身的内容}
}
class CustomWidget extends LeafRenderObjectWidget {const CustomWidget({super.key});RenderObject createRenderObject(BuildContext context) {return CustomRenderObject();}
}

这里的CustomWidget相对于Android中自定义View的配置属性.

注意

如果想要handleEvent回调, 那么hitTestSelf方法必须返回true, 否则不会触发.

总结

AndroidFlutter
绘制入口View.onDrawRenderObject.paint
测量入口View.onMeasureRenderObject.performLayout
手势入口View.onTouchEventRenderObject.handleEvent
属性配置xmlWidget
绘制相关CanvasPaintingContext.canvas
绘制图像Canvas.drawBitmapCanvas.drawImage
绘制图形Canvas.drawPathCanvas.drawPath
绘制文本Canvas.drawTextTextPainter.paint
触发重新绘制View.invalidateRenderObject.markNeedsPaint
触发重新布局View.requestLayoutRenderObject.markNeedsLayout

完整示例代码:

class CustomWidget extends LeafRenderObjectWidget {const CustomWidget({super.key});RenderObject createRenderObject(BuildContext context) {return CustomRenderObject();}
}/// [RenderSliver]
class CustomRenderObject extends RenderBox {Offset localPosition = Offset.zero;bool hitTestSelf(Offset position) {return true;}void handleEvent(PointerEvent event, BoxHitTestEntry entry) {//进行手势处理, 这里需要注意的是,//如果想要`handleEvent`方法被回调, 那么`hitTestSelf`必须返回truelocalPosition = event.localPosition;markNeedsPaint();//markNeedsLayout();}void performLayout() {//进行测量操作, 确定自身的大小, 位置由parent决定size = constraints.constrain(const Size(100, 100));}void paint(PaintingContext context, Offset offset) {//进行绘制操作, 确定自身的内容//context.canvas.drawImage(image, offset, paint);//context.canvas.drawPath(path, paint);//TextPainter()..layout()..paint(canvas, offset);context.canvas.drawRect(paintBounds.shift(offset),Paint()..style = PaintingStyle.stroke..color = Colors.purpleAccent,);context.canvas.drawCircle(localPosition + offset,10,Paint()..style = PaintingStyle.fill..color = Colors.purpleAccent,);TextPainter(text: TextSpan(text: localPosition.toString(),style: const TextStyle(color: Colors.purpleAccent,fontSize: 8,),),textDirection: TextDirection.ltr)..layout()..paint(context.canvas, offset);}
}

这里介绍一下LeafRenderObjectWidget SingleChildRenderObjectWidgetMultiChildRenderObjectWidget的区别:

类名说明
LeafRenderObjectWidget不接受任何子Widget
SingleChildRenderObjectWidget接受一个子Widget
MultiChildRenderObjectWidget接受一组子Widget

附加

RenderObject有2个关键的子类RenderBoxRenderSliver

RenderBox对应的是BoxConstraints约束, 也叫盒子约束;
RenderSliver对应的是SliverConstraints约束, 也叫条子约束;

BoxConstraints

const BoxConstraints({this.minWidth = 0.0,this.maxWidth = double.infinity,this.minHeight = 0.0,this.maxHeight = double.infinity,
});

盒子约束, 就是简单的约束大小使用. 这个在Flutter非常常见, 也是用得最多的一种约束.只要宽高即可.

SliverConstraints

const SliverConstraints({required this.axisDirection,required this.growthDirection,required this.userScrollDirection,required this.scrollOffset,required this.precedingScrollExtent,required this.overlap,required this.remainingPaintExtent,required this.crossAxisExtent,required this.crossAxisDirection,required this.viewportMainAxisExtent,required this.remainingCacheExtent,required this.cacheOrigin,
});

条子约束就比较复杂, 通常在ListView GridView可滚动的小部件中用得最多, 这是Flutter中用来协调滚动事件非常重要的约束, 这你就不展开了…

源码地址

还有一篇类比Android自定义ViewGroup的文章即将发布…


群内有各(pian)种(ni)各(jin)样(qun)的大佬,等你来撩.

联系作者

点此QQ对话 该死的空格 点此快速加群
在这里插入图片描述

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com