1.简述
在移动端的触摸场景案例参考非常少,对于触摸的各种手势操作不好参考,然鹅这种需求对于各种应用或是需求最平常不过的了 ,这里仅针对UE4的开发提供几种思路: 我们先来看下官方的推荐操作: 1、根据设备DPI缩放规则的自动缩放 DPI缩放适应 2、使用 Drag & Drop Operation DragAndDrop 可以看出,官方对这类操作已经做了不少友好的封装供我们使用,可以参考以上应用到自己的项目中。 以下示例演示了脚本语言对UI拖动/缩放功能的控制
2.代码示例
废话不多说,上代码~
注意:以下所有伪代码仅作参考,可以使用蓝图、C++、或任意脚本语言完全重写实现,重点理会思路
function YourPanel:OnTouchStarted(InGeometry, InGestureEvent)
return self:MouseButtonDown(InGeometry, InGestureEvent)
end
function YourPanel:OnTouchMoved(InGeometry, InGestureEvent)
return self:MouseMove(InGeometry, InGestureEvent)
end
function YourPanel:OnTouchEnded(InGeometry, InGestureEvent)
return self:MouseButtonUp(InGeometry, InGestureEvent)
end
subpage为该页面的子页面,可以理解为实际拖拽和缩放的对象 PixelSeries 为自定义的放大比例因子
function YourPanel:MouseButtonDown(InGeometry, InGestureEvent)
local PointerIndex = UE4.UKismetInputLibrary.PointerEvent_GetPointerIndex(InGestureEvent)
local control = UE4.UGameplayStatics.GetPlayerController(self:GetOwningPlayerPawn(), 0)
local scale = UE4.UWidgetLayoutLibrary.GetViewportScale(control)
local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
curPos = CanvasSlot:GetPosition()
self.startPos = curPos
m_MoveFlag = true
if #self.m_LastPosTable < 2 then
local ScreenSpacePosition = UE4.UKismetInputLibrary.PointerEvent_GetScreenSpacePosition(InGestureEvent)
local thisPos = UE4.USlateBlueprintLibrary.AbsoluteToLocal(InGeometry, ScreenSpacePosition)
self.m_LastPosTable[PointerIndex + 1] = thisPos
if #self.m_LastPosTable == 1 then
CanLimitRange = true
self.m_IsTap = true
self.m_HasTriggered = false
self.m_DragStartPos = thisPos
local ScreenSpacePosition = UE4.UKismetInputLibrary.PointerEvent_GetScreenSpacePosition(InGestureEvent)
Offset = UE4.USlateBlueprintLibrary.AbsoluteToLocal(InGeometry, ScreenSpacePosition)
elseif #self.m_LastPosTable == 2 then
CanLimitRange = false
Offset = FVector2D(0, 0)
local otherPos = FVector2D(0, 0)
for i = 1, #self.m_LastPosTable do
if i ~= PointerIndex + 1 then
otherPos = self.m_LastPosTable[i]
end
self.m_ZoomStartLength = UE4.UKismetMathLibrary.Vector_Distance2D(thisPos, otherPos) / scale
self.m_IsTap = false
self.m_OriginPoint = (thisPos + otherPos) / 2
self:CalcZoomRatio()
self.startPixelSeries = self.subpage.PixelSeries
end
end
local Handled = UE4.UWidgetBlueprintLibrary.Handled()
return UE4.UWidgetBlueprintLibrary.CaptureMouse(Handled, self)
end
return UE4.UWidgetBlueprintLibrary.UnHandled()
end
function YourPanel:MouseMove(InGeometry, InGestureEvent)
if m_MoveFlag then
m_MoveFlag = false
local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
local scale = UE4.UWidgetLayoutLibrary.GetViewportScale(self)
local ScreenSpacePosition = UE4.UKismetInputLibrary.PointerEvent_GetScreenSpacePosition(InGestureEvent)
local PointerIndex = UE4.UKismetInputLibrary.PointerEvent_GetPointerIndex(InGestureEvent)
local thisPos = UE4.USlateBlueprintLibrary.AbsoluteToLocal(InGeometry, ScreenSpacePosition)
local changepos = (thisPos - Offset)
if self.m_LastPosTable[PointerIndex + 1] ~= nil then
if #self.m_LastPosTable == 1 then
local lastPos = self.m_LastPosTable[PointerIndex + 1]
if UpdatePosFlag == true then
curPos = self.startPos + changepos
self.m_LastPosTable[PointerIndex + 1] = thisPos
CanvasSlot:SetPosition(curPos)
end
elseif #self.m_LastPosTable == 2 then
if false then
CanLimitRange = false
local otherPos
for i = 1, #self.m_LastPosTable do
if i ~= PointerIndex + 1 then
otherPos = self.m_LastPosTable[i]
end
end
local MoveDist = UE4.UKismetMathLibrary.Vector_Distance2D(thisPos, otherPos) / scale
if self.m_ZoomStartLength <= MoveDist then
newPixelSeries = (MoveDist - self.m_ZoomStartLength) / 20
self.subpage.PixelSeries = self.startPixelSeries + newPixelSeries
if self.subpage.PixelSeries > 80 then
self.subpage.PixelSeries = 80
end
else
newPixelSeries = (self.m_ZoomStartLength - MoveDist) / 20
self.subpage.PixelSeries = self.startPixelSeries - newPixelSeries
if self.subpage.PixelSeries < 30 then
self.subpage.PixelSeries = 30
end
end
self.subpage:AdjustSize()
self:SetZoomPos()
self.m_LastPosTable[PointerIndex + 1] = thisPos
end
end
m_MoveFlag = true
local Handled = UE4.UWidgetBlueprintLibrary.Handled()
return Handled
end
end
local UnHandled = UE4.UWidgetBlueprintLibrary.UnHandled()
return UnHandled
end
function YourPanel:MouseButtonUp(InGeometry, InGestureEvent)
self.m_IsTap = false
local PointerIndex = UE4.UKismetInputLibrary.PointerEvent_GetPointerIndex(InGestureEvent)
if UpdatePosFlag == true then
UpdatePosFlag = false
self.UpdatePosTimerHandle =
UE4.UKismetSystemLibrary.K2_SetTimerDelegate({self, self.OnUpdatePosFlag}, 0.05, true)
end
if self.m_LastPosTable[PointerIndex + 1] ~= nil then
table.remove(self.m_LastPosTable, PointerIndex + 1)
if #self.m_LastPosTable == 0 then
if CanLimitRange then
self:LimitRange()
end
elseif #self.m_LastPosTable == 1 then
self.m_DragStartPos = self.m_LastPosTable[1]
else
self.m_LastPosTable = {}
end
local Handled = UE4.UWidgetBlueprintLibrary.Handled()
return UE4.UWidgetBlueprintLibrary.ReleaseMouseCapture(Handled)
end
return UE4.UWidgetBlueprintLibrary.UnHandled()
end
接下来处理缩放比例和位置,以下示例控件锚点为左上,在缩放时还需要实时移动子控件的位置,以达成跟随手势位置缩放的效果:
function YourPanel:CalcZoomRatio()
self.m_OriginPoint = self.m_OriginPoint + FVector2D(math.abs(curPos.X), math.abs(curPos.Y))
self.m_LeftPointPoint = FVector2D(BackgroundPlateOffset, BackgroundPlateOffset)
self.m_RelativePos = self.m_OriginPoint - self.m_LeftPointPoint
local W = self.subpage.SizeX
local H = self.subpage.SizeY
self.m_RelativePosRatio = FVector2D(self.m_RelativePos.X / W, self.m_RelativePos.Y / H)
end
function YourPanel:SetZoomPos()
local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
local newW = self.subpage.SizeX
local newH = self.subpage.SizeY
self.m_newRelativePos = FVector2D(newW * self.m_RelativePosRatio.X, newH * self.m_RelativePosRatio.Y)
local newPos = curPos - self.m_newRelativePos + self.m_RelativePos
CanvasSlot:SetPosition(newPos)
end
至此完成了基本的拖拽/缩放,细节还可以根据实际情况进行调整,也可以后续加入滑动、边界限制等功能 这里举例使用定时器,对限制位置和松开手的位置两个变量进行线性插值的运算来模拟回弹效果
function YourPanel:LimitRange()
local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
curPos = CanvasSlot:GetPosition()
local viewport_geometry = UWidgetLayoutLibrary.GetViewportWidgetGeometry(self:GetOwningPlayerPawn())
viewportlocalsize = UE4.USlateBlueprintLibrary.GetLocalSize(viewport_geometry)
if (curPos.X + self.subpage.SizeX < viewportlocalsize.X / 2 ) then
m_SavePrePos.X = curPos.X
m_SaveTarPos.X = -self.subpage.SizeX + viewportlocalsize.X / 2
if m_UpdateTimerFlag_X == true then
m_UpdateTimerFlag_X = false
self.TimerHandle_X =
UE4.UKismetSystemLibrary.K2_SetTimerDelegate({self, self.OnUpdateEdgeLerpTimer_X}, 0.02, true)
end
end
if (curPos.Y + self.subpage.SizeY < 0) then
m_SavePrePos.Y = curPos.Y
m_SaveTarPos.Y = -self.subpage.SizeY
if m_UpdateTimerFlag_Y == true then
m_UpdateTimerFlag_Y = false
self.TimerHandle_Y =
UE4.UKismetSystemLibrary.K2_SetTimerDelegate({self, self.OnUpdateEdgeLerpTimer_Y}, 0.02, true)
end
end
CanvasSlot:SetPosition(curPos)
end
function YourPanel:OnUpdateEdgeLerpTimer_X()
Updatetime_X = Updatetime_X + 0.1
curPos.X = UE4.UKismetMathLibrary.Lerp(m_SavePrePos.X, m_SaveTarPos.X, Updatetime_X)
self:UpdateEdgeLerp()
if (Updatetime_X > 1) then
Updatetime_X = 0
m_UpdateTimerFlag_X = true
UE4.UKismetSystemLibrary.K2_ClearAndInvalidateTimerHandle(self, self.TimerHandle_X)
end
end
function YourPanel:OnUpdateEdgeLerpTimer_Y()
Updatetime_Y = Updatetime_Y + 0.1
curPos.Y = UE4.UKismetMathLibrary.Lerp(m_SavePrePos.Y, m_SaveTarPos.Y, Updatetime_Y)
self:UpdateEdgeLerp()
if (Updatetime_Y > 1) then
Updatetime_Y = 0
m_UpdateTimerFlag_Y = true
UE4.UKismetSystemLibrary.K2_ClearAndInvalidateTimerHandle(self, self.TimerHandle_Y)
end
end
function YourPanel:UpdateEdgeLerp()
local CanvasSlot = UE4.UWidgetLayoutLibrary.SlotAsCanvasSlot(self.subpage)
CanvasSlot:SetPosition(FVector2D(curPos.X, curPos.Y))
end
|