2014 年 8 月 19 日
教程:构建滑动菜单
有时,应用程序需要显示超出可用显示空间的菜单项或其他信息。一些示例包括商业应用程序中的库存系统或游戏中的增强道具列表。
幸运的是,Corona 使这相当容易。您只需要一个 widget.newScrollView()、一些要插入视图中的项目、一个启动滑块的方法和一个处理触摸对象的功能。
基本代码
这是本教程所需的基本代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
local widget = require( "widget" ) local scrollView local icons = {} local function iconListener( event ) local id = event.target.id if ( event.phase == "moved" ) then local dx = math.abs( event.x - event.xStart ) if ( dx > 5 ) then scrollView:takeFocus( event ) end elseif ( event.phase == "ended" ) then --如果触摸了某个对象,则执行操作 print( "object", id, "was touched" ) timer.performWithDelay( 10, function() if scrollView then scrollView:removeSelf() scrollView = nil end end ) end return true end local function showSlidingMenu( event ) if ( "ended" == event.phase ) then scrollView = widget.newScrollView { width = 460, height = 100, scrollWidth = 1200, scrollHeight = 100, verticalScrollDisabled = true } scrollView.x = display.contentCenterX scrollView.y = display.contentCenterY local scrollViewBackground = display.newRect( 600, 50, 1200, 100 ) scrollViewBackground:setFillColor( 0, 0, 0.2 ) scrollView:insert( scrollViewBackground ) --生成图标 for i = 1, 20 do icons[i] = display.newCircle( i * 56, 50, 22 ) icons[i]:setFillColor( math.random(), math.random(), math.random() ) scrollView:insert( icons[i] ) icons[i].id = i icons[i]:addEventListener( "touch", iconListener ) end end return true end |
处理滚动
因为我们需要接受滑动条中对象(图标)的触摸事件,所以它们每个都必须有一个触摸处理程序。但是,如果用户在滚动时触摸其中一个图标,我们通常希望滚动继续进行,而不是触发完成的触摸响应。
为了实现这一点,我们会在触摸处理函数中监视 "moved"
阶段。如果用户触摸开始的点几乎没有移动,我们就不将触摸“传递”给滚动视图。但是,如果用户将触摸点拖过一定距离,我们可以认为需要滚动滑动视图,并通过 scrollView:takeFocus() 将焦点赋予滚动视图。
计算应该被视为滚动视图移动的距离很简单:它只是当前触摸位置 (event.x
) 和用户触摸开始的位置 (event.xStart
) 之间差的绝对值。
1 |
local dx = math.abs( event.x - event.xStart ) |
如果此值(赋值给局部变量 dx
)超过 5
,我们将焦点传递给滚动视图
1 2 3 4 |
if ( dx > 5 ) then scrollView:takeFocus( event ) end |
在本教程中,滚动视图被限制为水平滚动 (verticalScrollDisabled=true
)。因此,我们只测试 x 轴上的移动。但是,如果使用垂直限制的滚动视图 (horizontalScrollDisabled=true
),则很容易测试 y 轴上的移动。
1 2 3 4 |
local dy = math.abs( event.y - event.yStart ) if ( dy > 5 ) then scrollView:takeFocus( event ) end |
对于可以向两个方向移动的滚动视图,我们可以检查两个轴上的移动
1 2 3 4 5 |
local dx = math.abs( event.x - event.xStart ) local dy = math.abs( event.y - event.yStart ) if ( dx > 5 or dy > 5 ) then scrollView:takeFocus( event ) end |
在所有这些示例中,前提是用户的触摸从起始位置移动了超过 5 个像素,此时我们将焦点传递给滚动视图并允许它继续滚动。根据应用程序内容的大小和设备屏幕的大小,5 个像素可能感觉不“自然”,因此可能需要稍微调整此值。
处理图标触摸
如果图标获得一个 "ended"
阶段,我们可以假设它接收了一个完整的触摸周期,并且焦点永远没有传递给滚动视图。在此条件块中,我们执行任何适当的操作——在这种情况下,我们在很短的定时器延迟后解除(移除)滑动条
1 |
timer.performWithDelay( 10, function() scrollView:removeSelf(); scrollView = nil; end ) |
滑动条设置
滚动视图的设置很简单:我们只需配置一个 widget.newScrollView() 并将对象插入其中。此外,我们在每个对象上添加一个触摸处理程序,该处理程序引用上面概述的 iconListener
触摸处理函数。
总结
此模块的应用范围很广。它可以用来显示其他人可以购买的其他应用程序列表。它也可以用来显示玩家选择的各种世界,类似于愤怒的小鸟。事实上,当与之前关于关卡选择的教程结合使用时,此滑动条可以容纳用于在该视图中将关卡 1-20 作为一个图标,将关卡 21-40 作为另一个图标等的选项。然后,每个图标可以启动该世界的关卡选择器。你的想象力是唯一的限制!
Erich Grüttner Díaz
发表于 18:39,8 月 19 日正是我需要的!
非常感谢,Rob!
Mo
发表于 21:32,8 月 19 日哇!太棒了,Rob!谢谢你。顺便问一下,这个教程的代码是否可以直接运行?我快速试了一下,屏幕上什么都没有。可能是我急着运行它了。我需要坐下来好好研究一下。
无论如何,非常感谢你。这是我一直羡慕那些有它的应用程序的功能之一,而且我一直无法弄清楚如何正确地做到这一点。
干杯。
Mo
SImpleex
发表于 03:06,8 月 20 日只需添加
Runtime:addEventListener(“touch”, showSlidingMenu)
在最后
apathy_docko
发表于 16:02,6 月 4 日你需要在监听器后面加一个空格
所以,过去是 Runtime:addEventListener (“touch”, showSliding Menu)
Rob Miracle
发表于 05:13,8 月 20 日你需要提供某种调用函数的方法,无论是按钮、在 composer:show() 函数中自动发生的事情,还是其他你想要调用的方法。或许只需添加一个 widget.newButtion() 并使用该函数作为按钮的 onEvent 处理程序。
Rob
ali
发表于 08:45,8 月 21 日你好,非常感谢分享本教程。我对 Corona 比较陌生(编码方面也是如此)。我不太确定我需要做些什么才能使其工作。有没有办法将它与你在上面评论中建议的 widget.newButtion() 一起运行的代码包括在内?我会非常感谢!Ali
Rob Miracle
发表于 20:20,8 月 21 日文档中的第一个示例代码
https://docs.solar2d.cn/api/library/widget/newButton.html
就能做到你想要的。只需将 “handleButtonEvent” 更改为 “showSlidingMenu”
ali
发表于 10:07,8 月 22 日感谢你的回复,Rob。我仍然无法让它工作。有没有可能下载演示项目?
lhwang
发表于 04:11,12 月 17 日只需粘贴这部分
local button1 = widget.newButton
{
left = 100,
top = 200,
id = “button1”,
label = “Default”,
fontSize = 50,
onEvent = showSlidingMenu
}
在上面的代码的最后一行,它就会工作。
(来自 api library – widget new Button 的代码)
Vibhu Bhola
发表于 00:25,8 月 20 日太棒了!非常感谢分享,Rob。
John
发表于 08:20,8 月 20 日哇,我们前几天才在我们的应用程序中加入了这种类型的菜单……只不过我们使用了静态背景,只是将背景和滚动视图分组在一起。
MO
发表于 17:37,8 月 20 日哎呀!!对不起大家。那天我太累了。谢谢,它工作得很好。我想知道如何更改代码以使其在滚动时捕捉到某个位置。我经常在游戏中看到,当我左右滑动时,项目会捕捉到位。
无论如何,从现在开始,这个小代码会经常被使用。谢谢你!
Mo.
BenCoder
发表于 16:07,1 月 20 日有没有人知道当我点击圆圈时如何加载场景?谢谢
Mo
发布于 8月21日 10:01你好,Ali,
就像 Simplex 建议的那样,只需将此代码添加到末尾即可
Runtime:addEventListener(“touch”, showSlidingMenu)
你需要触摸屏幕才能看到它(在模拟器上有效)
这太棒了!!!
Mo
ali
发布于 8月22日 04:27嗨,Mo,谢谢你的回复!我把事件监听器放在最后了,但还是不行 :/ 不确定为什么对我不起作用,我完全复制粘贴了代码并添加了运行时监听器,所以它应该可以正常工作,对吧?
Rob Miracle
发布于 8月22日 14:11此时,我建议你把这个问题发到论坛上,在那里你可以贴出你的代码。博客评论不太适合处理代码。
ROb
未解码
发布于 8月24日 21:40Ali,即使这一行看起来是一样的,也请尝试使用这一行
Runtime:addEventListener(“touch”,showSlidingMenu)
Dim
发布于 9月18日 06:32谢谢Rob,解释得很好。
和Mo一样,我也很想看到它吸附。我尝试了一些使用过渡到设置点和/或 scrollToPosition 的方法,但始终无法使其看起来完美且没有错误。如果碰巧你想进一步推进本教程,那就太棒了。
干杯。
lhwang
发布于 12月17日 23:13你好,这个菜单是水平菜单,想知道如何把它变成垂直菜单(就像 Facebook 侧边栏菜单一样)?
尝试了很多次但还是没有成功 🙁
非常感谢任何帮助。
lhwang
发布于 12月18日 12:34好的,我终于可以把它变成垂直菜单了,只需更改宽度和高度的值,水平变成垂直就可以了。
非常感谢本教程,它节省了我的时间!😀
lhwang
发布于 12月18日 12:35笔误 - *much
Nick
发布于 3月11日 03:22嗨,Rob,
首先,感谢你的教程。对我入门很有帮助。
我已经尝试了一段时间的代码,研究如何使用滚动视图作为菜单系统。然而,在我的试验中,我无法使滚动达到 scrollWidth 的全部宽度。不知何故,“菜单”只能达到大约 2.70 x display.contentWidth。而不是全部的 3 x display.contentWidth。
是否有最大宽度或其他原因导致这种情况?我是不是遗漏了什么,还是这是一个错误。我正在 mac 上运行 build 2511
谢谢
Nick
这是我的代码
local widget = require( "widget" )
local scrollView
local icons = {}
local numMenuScreens = 3
local circleRadius = 200
local cW = display.contentWidth
local cH = display.contentHeight
local function iconListener( event )
local id = event.target.id
local object = event.target
if ( event.phase == "moved" ) then
local dx = math.abs( event.x - event.xStart )
if ( dx > 5 ) then
scrollView:takeFocus( event )
end
elseif ( event.phase == "ended" ) then
--如果触摸了对象,则执行操作
end
return true
end
local function myShowSlidingMenu( )
-- if ( "ended" == event.phase ) then
scrollView = widget.newScrollView
{
width = cW,
height = cH,
scrollWidth = cW * numMenuScreens,
scrollHeight = 100,
verticalScrollDisabled = true, -- 仅水平滚动
isBounceEnabled = false
}
scrollView.x = display.contentCenterX
scrollView.y = display.contentCenterY
--生成图标
for i = 1, numMenuScreens do
icons[i] = display.newCircle( (i - 0.5 ) * cW, display.contentCenterY, circleRadius )
print( "调试注释:icons[i].x" , icons[i].x )
icons[i]:setFillColor( math.random(), math.random(), math.random() )
scrollView:insert( icons[i] )
icons[i].id = i
icons[i]:addEventListener( "touch", iconListener )
end
-- end
return true
end
myShowSlidingMenu()
print( "调试注释:contentWidth" , cW ,"x3" , cW*3)
Nick
发布于 3月11日 04:03local widget = require( “widget” )
local scrollView
local icons = {}
local numMenuScreens = 3
local circleRadius = 200
local cW = display.contentWidth
local cH = display.contentHeight
local function iconListener( event )
local id = event.target.id
local object = event.target
if ( event.phase == “moved” ) then
local dx = math.abs( event.x – event.xStart )
if ( dx > 5 ) then
scrollView:takeFocus( event )
end
elseif ( event.phase == “ended” ) then
--如果触摸了对象,则执行操作
end
return true
end
local function myShowSlidingMenu( )
— if ( “ended” == event.phase ) then
scrollView = widget.newScrollView
{
width = cW,
height = cH,
scrollWidth = cW * numMenuScreens,
scrollHeight = 100,
verticalScrollDisabled = true, — 仅水平滚动
isBounceEnabled = false
}
scrollView.x = display.contentCenterX
scrollView.y = display.contentCenterY
--生成图标
for i = 1, numMenuScreens do
icons[i] = display.newCircle( (i – 0.5 ) * cW, display.contentCenterY, circleRadius )
print( “调试注释:icons[i].x” , icons[i].x )
icons[i]:setFillColor( math.random(), math.random(), math.random() )
scrollView:insert( icons[i] )
icons[i].id = i
icons[i]:addEventListener( “touch”, iconListener )
end
— end
return true
end
myShowSlidingMenu()
print( “调试注释:contentWidth” , cW ,”x3″ , cW*3)
Rob Miracle
发布于 3月11日 14:58请将此发布到论坛中?评论不适合发布代码片段。
谢谢
Rob
Nick
发布于 3月11日 16:21谢谢Rob,我已经在这里重新发布了
http://forums.coronalabs.com/topic/39165-scrollwidth-and-scrollheight-in-scrollview-not-working/?p=286907
jose
发布于 5月17日 11:54嗨,抱歉打扰了,我想看看他们是否可以帮助我解决如何使图像适应不同的设备,因为当您更改为不同的设备时,图像或按钮会隐藏某人的一部分,我可以解释如何调整它们。
Rob Miracle
发布于 5月17日 20:08这是一个更适合在论坛中讨论的主题。请在那里提问:http://forums.coronalabs.com