New Quest... SplitView & Programmatically updating widgets demo

In the spirit of sharing and firing off yet another “Let’s work together to build a [fill in the blank]” quest, here’s a simple SplitView implementation using a tableView on the left and a scrollView on the right.

You can have a number of splitView variations obviously but I thought lets start with a simple one. This one assumes you are on an iPad and in landscape orientation so please set your simulator to run in that configuration. In real life a SplitView would need to accommodate the orientation change as well. See attached image for what this is supposed to look like when you run the code. 

I also used this demo as an opportunity to put all widgets from tab4 in CL’s WidgetDemo sample code into action. Each time you select a Player on the list the settings values are updated on the right. This is a good way to see how widgets can be updated from values in a file or db etc. Saving back of changed states is not implemented for the purposes of this demo.

I am hoping this can act as a starting point in a new cooperative effort to build a piece of code we can re-use/re-cycle as needed while building our business apps. Thanks for your time in looking at it and improving it. Please post back if you have updates. 

Remarks : In the course of building this demo I came across the following bugs / shortcomings. Filing these as separate bug reports with CL and hope these can be addressed in the near future. 

  1. All widgets behave well when inserted into a scrollView except newSegmentedControl. This widget never gets the click/tap event and update its visuals when inside a scrollView. You will see this one when you try to click the newSegmentedControl on the right. Case # 29097 previously reported by Joe528
  2. obj:setValue() method is not yet implemented for newSegmentedControl() Case # 29143
  3. Grouped Radio Buttons in a display group should update all buttons when setValue is used on one Case # 29138
  4. newStepper:setValue does not update newStepper.value Case # 29142
  5. newSwitch in style = “onOff” has a major bug where the whole switch moved on x-axis left & right when you programmatically change its state using object:setState(). You will see this one when you run the code and select a player on the left. Case # 29144

Happy holidays to all CL Staff and CL Developer friends. Keep well. 

local widget = require "widget" -- Set a default theme / Uncomment one of the following to see how this demo -- looks like and works on each theme widget.setTheme( "widget\_theme\_ios7" ) --widget.setTheme( "widget\_theme\_ios" ) --widget.setTheme( "widget\_theme\_android" ) -- Some sample data to populate the tableView on the left - No save to file etc -- implemented for the purpose of this demo local settings = { {caption = "Settings 1", isCategory=true}, {caption = "Player 1", isCategory=false, segmentedValue=2, hSliderVal=30, vSliderVal=10, newStepperVal= 4, newProgressViewVal = .5, checkboxButtonVal = {isOn=false}, onOffSwitchVal = {isOn=true}, radioButton1Val = {isOn=false}}, {caption = "Player 2", isCategory=false, segmentedValue=4, hSliderVal=60, vSliderVal=30, newStepperVal= 40, newProgressViewVal = .1, checkboxButtonVal = {isOn=true}, onOffSwitchVal = {isOn=false}, radioButton1Val = {isOn=true}}, {caption = "Settings 2", isCategory=true}, {caption = "Player 1", isCategory=false, segmentedValue=1, hSliderVal=50, vSliderVal=100, newStepperVal= 34, newProgressViewVal = .2, checkboxButtonVal = {isOn=true}, onOffSwitchVal = {isOn=true}, radioButton1Val = {isOn=true}}, {caption = "Player 2", isCategory=false, segmentedValue=5, hSliderVal=90, vSliderVal=10, newStepperVal= 45, newProgressViewVal = .6, checkboxButtonVal = {isOn=false}, onOffSwitchVal = {isOn=false}, radioButton1Val = {isOn=false}}, {caption = "Settings 3", isCategory=true}, {caption = "Player 1", isCategory=false, segmentedValue=1, hSliderVal=70, vSliderVal=40, newStepperVal= 2, newProgressViewVal = .8, checkboxButtonVal = {isOn=true}, onOffSwitchVal = {isOn=false}, radioButton1Val = {isOn=false}}, {caption = "Player 2", isCategory=false, segmentedValue=3, hSliderVal=20, vSliderVal=70, newStepperVal= 0, newProgressViewVal = .9, checkboxButtonVal = {isOn=false}, onOffSwitchVal = {isOn=true}, radioButton1Val = {isOn=true}} } local statusBarVisible = true -- change this to false if you wish statusBar to be hidden. local statusBarHeight = display.topStatusBarContentHeight if not statusBarVisible then statusBarHeight = 0 display.setStatusBar( display.HiddenStatusBar ) end local titleBarHeight = 44 -- Feel free to change this value to change your TitleBar Height local tabBarHeight = 50 -- Feel free to change this value to change your TabBar Height local splitViewHeight = display.contentHeight - titleBarHeight - tabBarHeight - statusBarHeight local splitLeftWidth = display.contentWidth / 4 -- or you could use a value such as 200 here local titleBarStrokeWidth = 2 local splitRightWidth = display.contentWidth - splitLeftWidth - (titleBarStrokeWidth / 2) local titleBarFillColor = {247/255, 247/255, 247/255} local titleBarStrokeColor = {192/255, 192/255, 196/255} local titleBarLeftLabel = "Players" local titleBarRightLabel = "Settings - Details" local titleBarTextFont = native.systemFont local titleBarTextFontSize = 16 local titleBarLeft = display.newRect(0, statusBarHeight, splitLeftWidth, titleBarHeight) titleBarLeft.anchorX, titleBarLeft.anchorY = 0, 0 titleBarLeft.strokeWidth = titleBarStrokeWidth titleBarLeft:setFillColor(unpack(titleBarFillColor)) titleBarLeft:setStrokeColor(unpack(titleBarStrokeColor)) local titleBarLeftText = display.newText( titleBarLeftLabel, 0, statusBarHeight, titleBarTextFont, titleBarTextFontSize ) titleBarLeftText:setFillColor( 0, 0, 0 ) titleBarLeftText.anchorX = 0.5 titleBarLeftText.anchorY = 0.5 titleBarLeftText.x = splitLeftWidth / 2 titleBarLeftText.y = statusBarHeight + (titleBarHeight / 2) local titleBarRight = display.newRect(splitLeftWidth + (titleBarStrokeWidth/2), statusBarHeight, splitRightWidth, titleBarHeight) titleBarRight.anchorX, titleBarRight.anchorY = 0, 0 titleBarRight.strokeWidth = titleBarStrokeWidth titleBarRight:setFillColor(unpack(titleBarFillColor)) titleBarRight:setStrokeColor(unpack(titleBarStrokeColor)) local titleBarRightText = display.newText( titleBarRightLabel, 0, statusBarHeight, titleBarTextFont, titleBarTextFontSize) titleBarRightText:setFillColor( 0, 0, 0 ) titleBarRightText.anchorX = 0.5 titleBarRightText.anchorY = 0.5 titleBarRightText.x = splitLeftWidth + (splitRightWidth / 2) titleBarRightText.y = statusBarHeight + (titleBarHeight / 2) local splitSeparatorLine = display.newLine( splitLeftWidth, 0, splitLeftWidth, display.contentHeight - tabBarHeight ) --splitSeparatorLine:setFillColor( 0, 0, 0 ) splitSeparatorLine:setStrokeColor(unpack(titleBarStrokeColor)) splitSeparatorLine.strokeWidth = titleBarStrokeWidth local scrollView = widget.newScrollView { left = splitLeftWidth + 1, top = titleBarHeight + statusBarHeight, width = splitRightWidth, height = splitViewHeight, } scrollView.anchorX = 0 scrollView.anchorY = 0 scrollView.x = splitLeftWidth + 1 scrollView.y = titleBarHeight + statusBarHeight + 1 -- Status text box local statusBox = display.newRect( 70, 290, 210, 120 ) statusBox.anchorX = 0 statusBox.anchorY = 0 statusBox:setFillColor( 0, 0, 0 ) statusBox.alpha = 0.4 scrollView:insert( statusBox ) -- Status text local statusText = display.newText( "Interact with a widget to begin!", 80, 300, 200, 0, native.systemFont, 20 ) statusText.anchorX = 0 statusText.anchorY = 0 statusText.x = statusBox.x + 5 statusText.y = statusBox.y + 5 scrollView:insert( statusText ) --------------------------------------------------------------------------------------------- -- widget.newSegmentedControl() --------------------------------------------------------------------------------------------- -- The listener for our segmented control local function segmentedControlListener( event ) local target = event.target print("here") -- Update the status box text statusText.text = "Segmented Control\nSegment Pressed: " .. target.segmentLabel end local segments = { "The", "Corona", "SDK", "Widget", "Demo!" } -- Create a default segmented control (using widget.setTheme) local segmentedControl = widget.newSegmentedControl { left = 10, top = 60, segments = segments, defaultSegment = 3, onPress = segmentedControlListener, } scrollView:insert( segmentedControl ) --------------------------------------------------------------------------------------------- -- widget.newSlider() --------------------------------------------------------------------------------------------- -- The listener for our slider's local function sliderListener( event ) -- Update the status box text statusText.text = event.target.id .. "\nCurrent Percent:\n" .. event.value .. "%" end -- Create a horizontal slider local horizontalSlider = widget.newSlider { left = 150, top = 232, width = 150, id = "Horizontal Slider", listener = sliderListener, } scrollView:insert( horizontalSlider ) -- Create a vertical slider local verticalSlider = widget.newSlider { left = 10, top = 270, height = 150, id = "Vertical Slider", orientation = "vertical", listener = sliderListener, } scrollView:insert( verticalSlider ) --------------------------------------------------------------------------------------------- -- widget.newSpinner() --------------------------------------------------------------------------------------------- -- Create a spinner widget local spinner = widget.newSpinner { left = 274, top = 55, } scrollView:insert( spinner ) -- Start the spinner animating spinner:start() --------------------------------------------------------------------------------------------- -- widget.newStepper() --------------------------------------------------------------------------------------------- -- Create some text for the stepper local currentValue = display.newText( "Value: 00", 165, 105, native.systemFont, 20 ) currentValue.anchorX = 0 currentValue.anchorY = 0 currentValue:setFillColor( 0 ) scrollView:insert( currentValue ) -- The listener for our stepper local function stepperListener( event ) local phase = event.phase -- Update the text to reflect the stepper's current value currentValue.text = "Value: " .. string.format( "%02d", event.value ) end -- Create a stepper local newStepper = widget.newStepper { left = 50, top = 105, initialValue = 0, minimumValue = 0, maximumValue = 50, onPress = stepperListener, } scrollView:insert( newStepper ) print (newStepper.value) --------------------------------------------------------------------------------------------- -- widget.newProgressView() --------------------------------------------------------------------------------------------- local newProgressView = widget.newProgressView { left = 20, top = 240, width = 100, isAnimated = true, } scrollView:insert( newProgressView ) -- Set the progress to 100% newProgressView:setProgress( 1.0 ) --------------------------------------------------------------------------------------------- -- widget.newSwitch() --------------------------------------------------------------------------------------------- -- Create a group for the radio button set local radioGroup = display.newGroup() -- The listener for our radio switch local function radioSwitchListener( event ) local switch = event.target --print( "Switch with ID '"..switch.id.."' is on: "..tostring(switch.isOn) ) -- Update the status box text statusText.text = "Switch with ID '" ..switch.id.. "' \nis on: " end -- Create some text to label the radio button with local radioButtonText = display.newText( "Use?", 40, 150, native.systemFont, 16 ) radioButtonText.anchorX = 0 radioButtonText.anchorY = 0 radioButtonText:setFillColor( 0 ) scrollView:insert( radioButtonText ) -- Create a default radio button (using widget.setTheme) local radioButton1 = widget.newSwitch { left = 25, top = 180, style = "radio", id = "Radio Button 1", initialSwitchState = true, onPress = radioSwitchListener, } radioGroup:insert( radioButton1 ) local radioButton2 = widget.newSwitch { left = 55, top = 180, style = "radio", id = "Radio Button 2", initialSwitchState = false, onPress = radioSwitchListener, } radioGroup:insert( radioButton2 ) scrollView:insert( radioGroup ) -- Create some text to label the checkbox with local checkboxText = display.newText( "Sound?", 110, 150, native.systemFont, 16 ) checkboxText.anchorX = 0 checkboxText.anchorY = 0 checkboxText:setFillColor( 0 ) scrollView:insert( checkboxText ) -- The listener for our checkbox switch local function checkboxSwitchListener( event ) -- Update the status box text statusText.text = "Checkbox Switch\nIs on?: " .. tostring( event.target.isOn ) end -- Create a default checkbox button (using widget.setTheme) local checkboxButton = widget.newSwitch { left = 120, top = 180, style = "checkbox", id = "Checkbox button", onPress = checkboxSwitchListener, } scrollView:insert( checkboxButton ) -- Create some text to label the on/off switch with local switchText = display.newText( "Music?", 200, 150, native.systemFont, 16 ) switchText.anchorX = 0 switchText.anchorY = 0 switchText:setFillColor( 0 ) scrollView:insert( switchText ) -- The listener for our on/off switch local function onOffSwitchListener( event ) -- Update the status box text statusText.text = "On/Off Switch\nIs on?: " .. tostring( event.target.isOn ) end -- Create a default on/off switch (using widget.setTheme) local onOffSwitch = widget.newSwitch { left = 190, top = 180, initialSwitchState = true, onPress = onOffSwitchListener, onRelease = onOffSwitchListener, } scrollView:insert( onOffSwitch ) --[[]]-- local function onRowRender(event) local row = event.row local txt = display.newText(row,settings[row.index].caption, row.contentWidth / 2,row.contentHeight / 2,"HelveticaNeue-Light", 16); txt:setFillColor(0,0,0,1) return true end local function onRowTouch(event) local phase = event.phase local row = event.target if "press" == phase then print( "Pressed row: " .. row.index ) elseif "release" == phase then print( "Tapped and/or Released row: " .. row.index ) -- Update the status box text statusText.text = settings[row.index].caption .. " selected" local segmentNum = settings[row.index].segmentedValue --obj:setValue() method is not yet implemented for segmentedControl so we have to use a workaround --I will leave the next line as commented out code until obj:setValue() method is available for segmentedControl --segmentedControl:setValue(settings[row.index].segmentedValue) if 1 == segmentNum then segmentedControl:setLeftSegmentActive() elseif #segments == segmentNum then segmentedControl:setRightSegmentActive() else segmentedControl:setMiddleSegmentActive( segmentNum ) end segmentedControl.\_segmentNumber = segmentNum; horizontalSlider:setValue(settings[row.index].hSliderVal) verticalSlider:setValue(settings[row.index].vSliderVal) newStepper:setValue(settings[row.index].newStepperVal) currentValue.text = "Value: " .. string.format( "%02d", newStepper.\_view.\_currentValue ) newProgressView:setProgress(settings[row.index].newProgressViewVal ) checkboxButton:setState( settings[row.index].checkboxButtonVal ) onOffSwitch:setState( settings[row.index].onOffSwitchVal ) radioButton1:setState( settings[row.index].radioButton1Val ) radioButton2:setState( {isOn = not radioButton1.isOn} ) end end local tableView = widget.newTableView({ left = 0, top = titleBarHeight + statusBarHeight, width = splitLeftWidth - 1, height = splitViewHeight, shouldHideBackground = true, onRowTouch = onRowTouch, onRowRender = onRowRender, }) for i = 1, #settings do local data = settings[i] tableView:insertRow{ rowHeight = data.isCategory and 40 or 30, isCategory = data.isCategory, rowColor = data.isCategory and { default={ 0.8, 0.8, 0.8, 0.8 } } or { default={ 1, 1, 1 }, over={ 1, 0.5, 0, 0.2 } }, } end

Thanks Kerem, This will help a lot when working on my iPad screens. Can you also try to put a newEditField in there and see how it behaves

Sure will do. I wanted to keep this demo operable with the CL released code so you might notice that I did not even take advantage of some issues you fixed already. Goal is for anyone to be able to take this and run with it and hopefully return some improvements and ideas. Will test the newEditField and let you know how it goes though.

Thanks, Ksan!

I just ran into bug 29144, it occurs if a user changes a switch state within a scrollview, and then scrolls.  I logged another bug report before I ran across this thread, but hoping for a quick resolution (already have a live app with this bug :frowning:  Anyway, just adding more keywords for others searching :slight_smile:

Sorry to hear your live app is affected by this bug. What is your bug#? I can add it to the tracking spreadsheet as well. Thanks for your report. 

Oops, should have added that, here you go:  29399

Thanks!!

Thats a nasty bug that makes your app look like unprofessional cr*p. i was under the firm impression that it was going to be fixed asap

Let’s hope Alex is back at work this week and has nothing else on his plate for a while…

Kerem, I am not sure its under Alex’s umbrella. Regardless, its a complete show stopper. I checked the release notes of the recent builds and it really doesnt look like it has been fixed.

Not to beat a dead horse, but it’s really bad in IOS 6.  The unwanted X axis shift is 50 pixels or more :frowning:

Not a dead horse at all - its as bad with the Android theme as well.

Not fixed as of 2122. It’s not too bad if you decide to make a game called … Chase the wiggling button. Aimed at 3 year olds. How about it.

Hehe :slight_smile: thats right down the alley of the “guess what you clicked on the segmented control” game

All bugs and jokes aside, anyone tried the SplitView yet? I’m looking for some feedback and improvement. If nothing else this will help newcomers see how to update widgets programmatically etc.

@ksan: i always have things on my plate :slight_smile:

I’m looking at the scrollview issues now.

Alex

Alex, we have a 3 course meal and then some waiting for you. Please push all other distractions aside! Let’s start the year with a Big Bang. Thanks for all your efforts. All the best!!!

Thanks Kerem, This will help a lot when working on my iPad screens. Can you also try to put a newEditField in there and see how it behaves

Sure will do. I wanted to keep this demo operable with the CL released code so you might notice that I did not even take advantage of some issues you fixed already. Goal is for anyone to be able to take this and run with it and hopefully return some improvements and ideas. Will test the newEditField and let you know how it goes though.

Thanks, Ksan!

I just ran into bug 29144, it occurs if a user changes a switch state within a scrollview, and then scrolls.  I logged another bug report before I ran across this thread, but hoping for a quick resolution (already have a live app with this bug :frowning:  Anyway, just adding more keywords for others searching :slight_smile:

Sorry to hear your live app is affected by this bug. What is your bug#? I can add it to the tracking spreadsheet as well. Thanks for your report.