Picker Wheel Widget Question

Hi @AppOwlDev,

Well, there are two ways I can think to achieve this: one being fairly intensive, the other using a little simple trickery.

  1. Dig into the widget library (which is open source) and add a new function that detects tapping on the row. This would be the superior method, but unless you’re familiar with the widget library and have tinkered with its mechanics before, you might get in too deep.

  2. Place an invisible but touch-sensitive (.isHitTestable=true) vector rectangle (display.newRect()) exactly over the middle row of the picker. Add a “tap” listener to it (not “touch”) and then, in that handling function, be sure to not"return true" so that the tap can still propagate through to the picker itself. On this event, you know that the user tapped on the middle row (or so it appears to the user) and then you can use the typical :getValues() call on the picker to gather the info from the currently selected row.

Hope this helps,

Brent

Hi Brent, that helps a lot, thanks!

How does the “Return True” part factor in? I’ve never really fully understood when not to use it. Is there a blog posting or tutorial that explains exactly what it does?

Hi @AppOwlDev,

Fortunately yes, there is a guide on how “return true” is important in respect to taps/touches. See the section “Understanding Hit Events”.

http://docs.coronalabs.com/guide/events/detectEvents/index.html#understanding-hit-events

Take care,

Brent

Hi Brent,

Thanks for the link, very helpful.

So i’m trying to use one of your suggestions and I can’t seem to get it to work.

I have created a pickerWheel and then created a simple rectangle display object the same size and positioned it over top of the pickerwheel. I gave the rectangle a “Touch” listener with a simple print command in the “ended” phase for testing. I also added isHitTestable = true and I have NOT added return true.

The problem is that while the touch event goes right through the rectangle to the picker widget below, allowing the user to mive the wheel (yay!) it does not register the touch event for the rectangle itself (boo…), it’s as if the rectangle doesn’t exist. If I add the return true, it only registers the rectangle touch event (As it’s supposed to).

Now if I change the listener type to Tap instead, it works perfectly. But that isn’t helpful since a user is going to move his/her finger up and down to move the picker widget, therefor not registering as a “tap”.

local function wheelTouch(event) local phase = event.phase if phase == "ended" then print("touched") end end local columnData = { { startIndex = 3, labels = { "#0 - 0.06", "#1 - 0.073", "#2 - 0.086", "#3 - 0.099", "#4 - 0.112", "#5 - 0.125", "#6 - 0.138", "#8 - 0.164", "#10 - 0.19", "#12 - 0.215" } } } diaWheel = widget.newPickerWheel { columns = columnData, } diaWheel.anchorX = 0 diaWheel.anchorY = 0.5 diaWheel.x = -50 diaWheel.y = display.contentCenterY local touchBox = display.newRect( 0, 0, diaWheel.contentWidth, diaWheel.contentHeight ) touchBox.anchorY = 0.5 touchBox.anchorX = 0 touchBox.x = diaWheel.x touchBox.y = diaWheel.y touchBox.isHitTestable = true touchBox:addEventListener( "touch", wheelTouch ) touchBox.alpha = 0 screenGroup:insert( 1, diaWheel ) screenGroup:insert( 2, touchBox )

Hi @AppOwlDev,

I think your touch rectangle is behind your picker wheel because of how you’ve inserted and used the indexing (1, 2, etc.). If you set the fill color of the rectangle to red ( “touchBox:setFillColor(1,0,0)” ) and set its alpha to non-0, do you see it in front of the wheel? If not, then it’s behind, and naturally it would not detect the touch because the picker “consumes” it.

If you insert it without those index numbers, but in the same order you’re doing (in lines) then it should reside in front. But if you want to be sure, bring it to the front using “touchBox:toFront()” AFTER you insert it into “screenGroup”.

Brent

Hi Brent,

My numbering is correct, the touchBox is in front of the picker widget. I changed it to bright red to double check. I also just used the :toFront() command to triple make sure, and it still doesn’t work.

Here is a test program you can run to see:

local composer = require( "composer" ) local scene = composer.newScene() local widget = require ( "widget" ) local function testFunction(event) if event.phase == "ended" then print("was touched!") end end function scene:create( event ) local sceneGroup = self.view local columnData = { { startIndex = 3, labels = { "Monday", "Tuesday", "Wednesday", "Thursday", "TGIF" } } } local testWheel = widget.newPickerWheel { columns = columnData, } testWheel.x = display.contentCenterX testWheel.y = display.contentCenterY sceneGroup:insert( testWheel ) local testBox = display.newRect( sceneGroup, 0, 0, testWheel.contentWidth, testWheel.contentHeight ) testBox.x = testWheel.x testBox.y = testWheel.y testBox:setFillColor( 1, 0, 0 ) sceneGroup:insert( testBox ) testBox:addEventListener( "touch", testFunction ) testBox.isHitTestable = true testBox.alpha = 0.5 end function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then end end function scene:destroy( event ) local sceneGroup = self.view end scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) return scene

Hi @AppOwlDev,

Hmmm, I tested this and you’re correct. The “began” phase is registered on the rectangle, but the “ended” phase is not. Apparently the picker consumes that and the rectangle never knows that you lifted off it.

Before I continue, I should note that my original suggestion was to use a smaller rectangle that only covers the middle row of the picker. You have it covering the entire wheel, but my intention was not so.

Now, stepping back earlier into this thread, I think a “tap” listener on that rectangle gives you the functionality you want, for these reasons:

  1. If the user touches the middle row and then moves the touch, the “tap” is ignored. This is important because the user would very likely do that to select a different option (you couldn’t expect them to always touch outside the middle row to move the wheel).

  2. If the user touches or taps outside of the middle row (so, not on the rectangle), the wheel will behave as expected, and they can tap an exterior row to move it to the middle.

  3. When the user taps the middle row, you get the expected behavior of them choosing that value. The tap is registered and you can proceed with :getValues().

Let me know if there’s a case I’m not thinking of…

Brent

Hi Brent,

That would work… except I forgot to mention I looking at it for a slightly different function now. What I would like is for an outside source (Let’s say a newText) to update with the getValues() value of the pickerWheel as the pickerWheel is being used.

So what I thought of is for the touchBox eventListener to (After a very slight delay) call the getValue() method in the “ended” phase, after the user lifts their finger off the testBox and Picker presumably with their choice.

I would think the tap event would still work for that. Just update the newText item when a tap is registered on the rectangle…

When I get home I can try again. But I don’t think that helps in your first example:

  1. If the user touches the middle row and then moves the touch, the “tap” is ignored. This is important because the user would very likely do that to select a different option (you couldn’t expect them to always touch outside the middle row to move the wheel).

If they touch then move their finger to move the wheel, and then lift off, the “tap” event will not register and the newText will not update. This is actually a different pickerWheel than my original post was about (I just decided to go with a separate button for that one).

I don’t want the user to have to tap or press the pickerWheel a second time like it’s a button. I want the newText to update automagically as the user moves the pickerWheel, or after the user lifts their finger from moving the pickerWheel.

Shouldn’t the removal of Return True accomplish that? Or is this a bug?

Well, this is getting into some fairly advanced (and unusual) usage of the picker wheel. I think you’d almost have to detect the “moved” phase of the rectangle, or else do a constant Runtime listener which checks the values and detects if it has changed from the previous value (the wheel has been shifted one notch).

Brent