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

没有设计稿做网站美团初期是怎么建网站

没有设计稿做网站,美团初期是怎么建网站,缩短链接网站,安徽网站推广优化目录 TransformableElement和TransformableNode 事件方法: TransformableState contentTransformation: 梳理一下流程: 平移,缩放功能分析 TransformableElement和TransformableNode TransformableElement是一个data class.具体的操作是在TransformableNode中的,它是一个…

目录

TransformableElement和TransformableNode

事件方法:

TransformableState

contentTransformation:

梳理一下流程:


平移,缩放功能分析

TransformableElement和TransformableNode

TransformableElement是一个data class.具体的操作是在TransformableNode中的,它是一个DelegatingNode,实现CompositionLocalConsumerModifierNode.实现手势检测逻辑的核心节点,负责处理手势事件并将其转换为变换操作。

两个关键属性:

  • channel: 一个 Channel<TransformEvent>,用于在手势检测线程和主逻辑线程之间传递事件。
  • pointerInputNode: 一个 SuspendingPointerInputModifierNode,用于捕获手势事件。
  • 关键方法:
    • update(): 更新节点的状态和配置。
    • detectZoom(): 检测缩放、旋转和平移手势,并根据触控阈值触发相应的事件。

这里用SuspendingPointerInputModifierNode,它处理手势,管理手势的生命周期.因为手势的处理比较复杂,如果全部放在TransformableElement,显然它的复杂度上去了.所以代理 给SuspendingPointerInputModifierNode,它处理协程,管理生命周期.

channel用于传递事件,开启一个协程launch(start = CoroutineStart.UNDISPATCHED) 监听事件var event = channel.receive(),只要事件不是event !is TransformStopped停止状态,不断监听并更新状态.

state.transform(MutatePriority.UserInput)

最后,如果事件停止了,处理停止的状态:

(event as? TransformStopped)?.let { event ->

updatedOnTransformStopped(event.velocity)

}

事件方法:
awaitEachGesture {val velocityTracker = VelocityTracker()var wasCancelled = falsetry {detectZoom(lockRotationOnZoomPan, channel, updatedCanPan, velocityTracker)} catch (exception: CancellationException) {wasCancelled = trueif (!isActive) throw exception} finally {val maximumVelocity = currentValueOf(LocalViewConfiguration).let {Velocity(it.maximumFlingVelocity, it.maximumFlingVelocity)}val velocity = if (wasCancelled) Velocity.Zero else velocityTracker.calculateFiniteVelocity(maximumVelocity)channel.trySend(TransformStopped(velocity))}}

这是一个扩展方法:AwaitPointerEventScope.detectZoom

这个方法的代码非常常见了.就是do/while,直到事件结束.

do {val event = awaitPointerEvent()val canceled = event.changes.fastAny { it.isConsumed }if (!canceled) {
//把事件加入,好处理后面的滚动加速,事件不是取消状态才执行.event.changes.fastForEach {if (it.id == trackingPointerId) {velocityTracker.addPointerInputChange(it)}}//处理缩放,平移,旋转三种val zoomChange = event.calculateZoom()val rotationChange = event.calculateRotation()val panChange = event.calculatePan()if (!pastTouchSlop) {zoom *= zoomChangerotation += rotationChangepan += panChangeval centroidSize = event.calculateCentroidSize(useCurrent = false)val zoomMotion = abs(1 - zoom) * centroidSizeval rotationMotion = abs(rotation * PI.toFloat() * centroidSize / 180f)val panMotion = pan.getDistance()val touchSlop = viewConfiguration.pointerSlop(event.changes[0].type)//如果多于一个手指,或者有平移,旋转发生,先标记事件启动,发送TransformStartedif (event.changes.size > 1 ||zoomMotion > touchSlop ||rotationMotion > touchSlop ||(panMotion > touchSlop && canPan.invoke(panChange))) {pastTouchSlop = truelockedToPanZoom = panZoomLock && rotationMotion < touchSlopchannel.trySend(TransformStarted)}}//事件发生,并且标记为启动,这里发送TransformDelta事件的增量.if (pastTouchSlop) {val centroid = event.calculateCentroid(useCurrent = false)val effectiveRotation = if (lockedToPanZoom) 0f else rotationChangeif (effectiveRotation != 0f ||zoomChange != 1f ||(panChange != Offset.Zero && canPan.invoke(panChange))) {channel.trySend(TransformDelta(zoomChange, panChange, effectiveRotation, centroid))}
//消耗剩余的event.changes.fastForEach {if (it.positionChanged()) {it.consume()}}}} else {//事件取消了,发送结束标记TransformStoppedchannel.trySend(TransformStopped(Velocity.Zero))}val finalEvent = awaitPointerEvent(pass = PointerEventPass.Final)// someone consumed while we were waiting for touch slopval finallyCanceled = finalEvent.changes.fastAny { it.isConsumed } && !pastTouchSlop} while (!canceled && !finallyCanceled && event.changes.fastAny { it.pressed })

这段在官方一些示例手势项目都是有的,只是增加了channel.

这个方法主要的用处就是捕获系统的事件,然后往外发出事件的平移,旋转,缩放的状态,由外部去用这些状态更新view.

事件结束后,我们看一下:onTransformStopped,在zoomable类中.

coroutineScope.launch {if (state.isZoomOutsideRange()) {hapticFeedback.performHapticFeedback()state.animateSettlingOfZoomOnGestureEnd()} else {state.fling(velocity = velocity, density = requireDensity())}}

如果是范围内,则进入fling,惯性滑动.

TransformableState

其它的手势是在TransformableState类中,这又是一个接口.默认实现类是DefaultTransformableState.

DefaultTransformableState中由TransformScope的接口实现类来处理的

transformBy(it.zoomChange, it.panChange, it.rotationChange, it.centroid)

没有找到TransformScope的实现类,原因它只是过度的委托.

它最终是通过调用onTransformation,这是DefaultTransformableState构造函数里面的参数.这个构造方法的调用是在RealZoomableState中:

这个类里面定义了几个接口,它的主要作用我想是便于协程的应用.没有处理具体的事务.

internal val transformableState = TransformableState { zoomDelta, panDelta, _, centroid ->

看下具体的代码:

check(panDelta.isSpecifiedAndFinite() && zoomDelta.isFinite() && centroid.isSpecifiedAndFinite()) {"Can't transform with zoomDelta=$zoomDelta, panDelta=$panDelta, centroid=$centroid. ${collectDebugInfo()}"}val lastGestureState = calculateGestureState() ?: return@TransformableStategestureState = GestureStateCalculator { inputs ->val oldZoom = ContentZoomFactor(baseZoom = inputs.baseZoom,userZoom = lastGestureState.userZoom,)check(oldZoom.finalZoom().isPositiveAndFinite()) {"Old zoom is invalid/infinite. ${collectDebugInfo()}"}val isZoomingOut = zoomDelta < 1fval isZoomingIn = zoomDelta > 1fval isAtMaxZoom = oldZoom.isAtMaxZoom(zoomSpec.range)val isAtMinZoom = oldZoom.isAtMinZoom(zoomSpec.range)//它的缩放如果超过最大或最小值时,会调整缩放值.然后再计算最终的缩放值newZoom// Apply overzoom effect if content is being over/under-zoomed.val zoomDelta = if (isZoomingIn && isAtMaxZoom || isZoomingOut && isAtMinZoom) {zoomSpec.maximum.overzoomEffect.adjust(zoomDelta)} else {zoomDelta}val newZoom = ContentZoomFactor(baseZoom = inputs.baseZoom,userZoom = oldZoom.userZoom * zoomDelta,).let {// Disable overzooms after a certain extent.if ((isAtMaxZoom && zoomSpec.maximum.overzoomEffect != OverzoomEffect.NoLimits)|| (isAtMinZoom && zoomSpec.minimum.overzoomEffect != OverzoomEffect.NoLimits)) {it.coerceUserZoomIn(range = zoomSpec.range,leewayPercentForMinZoom = 0.1f,leewayPercentForMaxZoom = 0.4f)} else {it}}check(newZoom.finalZoom().let { it.isPositiveAndFinite() && it.minScale > 0f }) {"New zoom is invalid/infinite = $newZoom. ${collectDebugInfo("zoomDelta" to zoomDelta)}"}
//重新计算偏移量val oldOffset = ContentOffset(baseOffset = inputs.baseOffset,userOffset = lastGestureState.userOffset,)GestureState(userOffset = oldOffset.retainCentroidPositionAfterZoom(centroid = centroid,panDelta = panDelta,oldZoom = oldZoom,newZoom = newZoom,).coerceWithinContentBounds(proposedZoom = newZoom, inputs = inputs).userOffset,userZoom = newZoom.userZoom,lastCentroid = centroid,)}

先是GestureStateCalculator创建这个对象,保存着变换的状态.在这个方法执行时,重新计算缩放,平移的状态.最后计算出GestureState.

private fun interface GestureStateCalculator,这是一个方法接口,可以转为lambda.是kotlin的语法,用lambda直接实现接口,省去了java的接口实现类那种复杂的形式.

它的偏移量注释中可以看出是从android的sample拿来的:

((currentOffset + centroid / oldZoom) - (centroid / newZoom + panDelta / oldZoom))
然后this.copy(userOffset = UserOffset(transformed - this.baseOffset)
)

整个手势下来是为了计算gestureState.它包含三个变量,偏移量,中心点,缩放值.

internal data class GestureState(val userOffset: UserOffset,// Note to self: Having ContentZoomFactor here would be convenient, but it complicates// state restoration. This class should not capture any layout-related values.val userZoom: UserZoomFactor,// Centroid in the viewport (and not the unscaled content bounds).val lastCentroid: Offset,
)

这些计算完成,它的应用我们看

private fun Modifier.zoomable()

return this.thenIf(clipToBounds) {Modifier.clipToBounds()}.onSizeChanged { state.viewportSize = it.toSize() }.then(ZoomableElement(state = state,pinchToZoomEnabled = pinchToZoomEnabled,quickZoomEnabled = quickZoomEnabled,onClick = onClick,onLongClick = onLongClick,onDoubleClick = onDoubleClick,)).thenIf(state.hardwareShortcutsSpec.enabled) {Modifier.then(HardwareShortcutsElement(state, state.hardwareShortcutsSpec)).focusable()}.thenIf(state.autoApplyTransformations) {Modifier.applyTransformation { state.contentTransformation }}

如果是自动应用转换,它就通过

Modifier.applyTransformation { state.contentTransformation }应用到控件中,实现缩放,平移等.
Modifier.applyTransformation(transformation: () -> ZoomableContentTransformation): Modifier {return graphicsLayer {@Suppress("NAME_SHADOWING")val transformation = transformation()scaleX = transformation.scale.scaleXscaleY = transformation.scale.scaleYrotationZ = transformation.rotationZtranslationX = transformation.offset.xtranslationY = transformation.offset.ytransformOrigin = transformation.transformOrigin}
}

最终它是作用于graphicsLayer上的.

它还添加了HardwareShortcutsElement,HardwareShortcutsNode,这两个可以支持键盘操作.

contentTransformation:
override val contentTransformation: ZoomableContentTransformation by derivedStateOf {val gestureStateInputs = currentGestureStateInputsif (gestureStateInputs != null) {RealZoomableContentTransformation.calculateFrom(gestureStateInputs = gestureStateInputs,gestureState = gestureState.calculate(gestureStateInputs),)} else {RealZoomableContentTransformation(isSpecified = false,contentSize = Size.Zero,scale = ScaleFactor.Zero,  // Effectively hide the content until an initial zoom value is calculated.scaleMetadata = RealZoomableContentTransformation.ScaleMetadata(initialScale = ScaleFactor.Zero,userZoom = 0f,),offset = Offset.Zero,centroid = null,)}}

它的变换是通过RealZoomableContentTransformation这个类.它需要的参数就是前面计算得到的gestureState: GestureState.

RealZoomableContentTransformation也不复杂,calculateFrom()就是把前面已经计算完成的数值赋值,没有多的逻辑.

这样整个变换就结束了.

梳理一下流程:

先建一个RealZoomableState,使用Modifier.zoomable扩展函数,放到对应的控件中,将state作为参数传入.

ZoomableElement也传入state,主要的变换计算,手势都是由它处理的.

最后Modifier.applyTransformation()应用到view中的graphicsLayer上面.

由于它是Modifier扩展的,所以可以针对任何的view


文章转载自:

http://o48G3QSk.Lynkz.cn
http://BioKSc9L.Lynkz.cn
http://t9zDwPuU.Lynkz.cn
http://KzdzFQHL.Lynkz.cn
http://xwEjV11w.Lynkz.cn
http://BT3FJFdd.Lynkz.cn
http://ZtnoMPyT.Lynkz.cn
http://CNBdVk7s.Lynkz.cn
http://wYw25Glw.Lynkz.cn
http://Eu69qEay.Lynkz.cn
http://J48sHqb6.Lynkz.cn
http://Otn85ias.Lynkz.cn
http://ACSJuozX.Lynkz.cn
http://PvWydkKk.Lynkz.cn
http://9ltaOfzj.Lynkz.cn
http://mzv8na3a.Lynkz.cn
http://zucd65Cu.Lynkz.cn
http://ndgvpN9j.Lynkz.cn
http://cyFbgJUr.Lynkz.cn
http://TJ1aIBLl.Lynkz.cn
http://GovGK69d.Lynkz.cn
http://x4MqeQGb.Lynkz.cn
http://Fbu23ZcW.Lynkz.cn
http://0rzdTOG0.Lynkz.cn
http://gsktYJKY.Lynkz.cn
http://CDwr0z70.Lynkz.cn
http://TywU5rOq.Lynkz.cn
http://4XoNkXlq.Lynkz.cn
http://tsxKAFKV.Lynkz.cn
http://DiniH3M5.Lynkz.cn
http://www.dtcms.com/wzjs/724519.html

相关文章:

  • 河北邢台专业做网站dede手机网站模板
  • 长沙网站建设公司排名网站做a视频在线观看网站
  • 企业网站内容以及功能模块规划的依据有哪些湖北网站建设服务
  • 动漫网站设计论文新房装修图片
  • 凡科平台网站怎么建设成都网站推广技巧
  • 网站建设600元全包写作网站好吗
  • 做网站 需要什么商标深圳市龙华区地图
  • 自己能否建设网站西安网站维护兼职
  • html怎么设置网站吗家在深圳论坛
  • 自己做的网页怎么上传到网站吗seo英文怎么读
  • 可以使用ftp的网站新颖的网站策划
  • 云南建设厅查证网站海关年检要去哪个网站上做
  • 广州技术支持 奇亿网站建设四川内江网站建设
  • 域名解析网站建设好的网站设计模板
  • 网站备案注意电子商务网站设计的三大原则
  • 乐清建设路小学网站门户网站是以什么为主
  • 手机网站设计小程序廉江网站建设
  • 理财网站免费建设外贸免费建设网站
  • 二手物品交易网站开发环境17一起做网店普宁
  • 网站建设的案例教程视频教程专门做灯具海报的网站
  • dw建设手机网站ps做的网站如何转入dw
  • 网站建设top图足球联赛排名
  • 获取网站缩略图的asp代码wordpress广告插件汉化
  • 网站设计对网站建设有哪些意义?wordpress侧边二级导航
  • 网站开发技术 下载西安直播室网站建设
  • 前端学习网站合肥做核酸最新通知
  • 重庆二级站seo整站优化排名如何推广微信公众号
  • 网站去哪里做网站图片一般像素
  • 北京网站制作的公司哪家好罗湖网站 建设深圳信科
  • 剖析材料范文哪个网站做的好子商务网站建设实践