I'm back with questions 🙂
Here is my current progress 🤦♂️
🎥 app preview Feathers
As you can see, I'm using LayoutGroup
with HorizontalLayout
with Panel
s for each lesson. I chose Panel
because it's already has a header (for stars and chekmark) and a footer (for lesson title). If it's not a good solution, just please let me know, I'll try to proceed as you mentioned in your post.
Questions:
Is there any limitations regarding to List
's LayoutGroupListItemRenderer
elements width? Do elements always have to be equal in width to each other, and is this width always taken from the width of the first element? I.e: if my "Lesson Group 1" contains only 2 lessons then width will be 100, and "Lesson Group 2" contains 5 lessons then width should be 500, but actually it's also 100 (as the first lesson group). If not, then I did it wrong, and it's quite expected 😆
I'm "generating" lessons Panel
s using cycle (depending on lessons count coming from List
data) in override protected function commitData():void
block, I guess it's wrong place to do that, but otherwise I'm unable to pass List
data to override protected function initialize():void
block. So, how to do it right?
How to pass data to Panel
's footer? Because according to my design I have to show the title of the lesson in the footer.
I'm sharing my code here to better understand my questions:
Menu.as
package screens {
import feathers.controls.Button;
import feathers.controls.Header;
import feathers.controls.List;
import feathers.controls.PanelScreen;
import feathers.controls.renderers.IListItemRenderer;
import feathers.data.XMLListCollection;
import feathers.layout.HorizontalAlign;
import feathers.layout.HorizontalLayout;
import starling.display.DisplayObject;
import starling.events.Event;
import starling.text.TextFormat;
import utils.CustomLayoutGroupItemRenderer;
public class MainMenu extends PanelScreen
{
public function MainMenu() {
super();
}
override protected function initialize():void
{
super.initialize();
var layoutOfList:HorizontalLayout = new HorizontalLayout();
layoutOfList.horizontalAlign = HorizontalAlign.JUSTIFY;
layoutOfList.padding = 10;
layoutOfList.gap = 20;
var list:List = new List();
list.setSize(stage.width, 250); //TODO: make height automatic
var xml_string = '<?xml version="1.0" encoding="utf-8" ?>\n' +
'<lessonGroup name="Lessons Group 1" lessonsCount="2" id="1">\n' +
' <lesson id="1" title="1-Intro" isOpened="1" />\n' +
' <lesson id="2" title="1-Lesson 1" isOpened="1" />\n' +
'</lessonGroup>' +
'<lessonGroup name="Lessons Group 2" lessonsCount="5" id="2">\n' +
' <lesson id="1" title="2-Intro" isOpened="1" />\n' +
' <lesson id="2" title="2-Lesson 1" isOpened="1" />\n' +
' <lesson id="3" title="2-Lesson 2" isOpened="1" />\n' +
' <lesson id="4" title="2-Lesson 3" isOpened="1" />\n' +
' <lesson id="5" title="2-Lesson 4" isOpened="1" />\n' +
'</lessonGroup>' +
'<lessonGroup name="Lessons Group 3" lessonsCount="6" id="3">\n' +
' <lesson id="1" title="3-Intro" isOpened="1" />\n' +
' <lesson id="2" title="3-Lesson 1" isOpened="1" />\n' +
' <lesson id="3" title="3-Lesson 2" isOpened="1" />\n' +
' <lesson id="4" title="3-Lesson 3" isOpened="1" />\n' +
' <lesson id="5" title="3-Lesson 4" isOpened="1" />\n' +
' <lesson id="6" title="3-Lesson 5" isOpened="1" />\n' +
'</lessonGroup>' +
'<lessonGroup name="Lessons Group 4" lessonsCount="3" id="4">\n' +
' <lesson id="1" title="4-Intro" isOpened="1" />\n' +
' <lesson id="2" title="4-Lesson 1" isOpened="1" />\n' +
' <lesson id="3" title="4-Lesson 2" isOpened="1" />\n' +
'</lessonGroup>\n'
;
list.dataProvider = new XMLListCollection( XMLList(xml_string) );
list.itemRendererFactory = function():IListItemRenderer
{
return new CustomLayoutGroupItemRenderer();
}
list.layout = layoutOfList;
list.scrollBarDisplayMode = "none";
list.y = 10; //TODO: make it automatic and depending on scale.
this.addChild(list);
this.title = "LEVEL TITLE";
this.headerFactory = this.customHeaderFactory;
trace(this.owner.rootScreenID );
}
private function customHeaderFactory():Header
{
var header:Header = new Header();
header.fontStyles = new TextFormat( "Impact", 40, 0x00CC00 );
header.titleAlign = HorizontalAlign.LEFT;
var settingsButton:Button = new Button();
settingsButton.label = "SETT\INGS";
header.rightItems = new <DisplayObject>[settingsButton];
return header;
}
}
}
CustomLayoutGroupItemRenderer.as
package utils {
import feathers.controls.Header;
import feathers.controls.Label;
import feathers.controls.LayoutGroup;
import feathers.controls.Panel;
import feathers.controls.renderers.LayoutGroupListItemRenderer;
import feathers.layout.HorizontalAlign;
import feathers.layout.HorizontalLayout;
import starling.display.Quad;
import starling.text.TextFormat;
public class CustomLayoutGroupItemRenderer extends LayoutGroupListItemRenderer
{
public function CustomLayoutGroupItemRenderer()
{
super();
}
override protected function initialize():void
{
super.initialize();
var lessonsGroupPanelLayout:HorizontalLayout = new HorizontalLayout();
this.lessonsGroupPanel = new Panel();
this.lessonsGroupPanel.layout = lessonsGroupPanelLayout;
this.lessonsGroupPanel.headerFactory = this.customHeaderFactory1;
var layoutOfThumbLesson:HorizontalLayout = new HorizontalLayout();
layoutOfThumbLesson.gap = 20;
groupOfThumbLesson.layout = layoutOfThumbLesson;
this.lessonsGroupPanel.addChild(groupOfThumbLesson);
this.addChild(this.lessonsGroupPanel);
}
protected var lessonsGroupPanel:Panel;
protected var groupOfThumbLesson:LayoutGroup = new LayoutGroup();
protected var lessonsCounterFlag:Array = new Array();
override protected function commitData():void
{
if(this.data)
{
this.lessonsGroupPanel.title = this.data.@name.toString() + " — (" + this.data.@lessonsCount.toString() +")";
//this condition is a dirty workaround for preventing re-execution of the same list element
if(lessonsCounterFlag.indexOf(int(this.data.@id.toString())) == -1)
{
for (var i:int = 0; i < int(this.data.@lessonsCount.toString()); i++) {
var lessonThumbPanel:Panel = new Panel();
lessonThumbPanel.title = this.data.lesson[i].@title;
lessonThumbPanel.width = 120;
lessonThumbPanel.height = 150;
lessonThumbPanel.headerFactory = this.customHeaderFactory2;
lessonThumbPanel.footerFactory = this.customFooterFactory2;
groupOfThumbLesson.addChild(lessonThumbPanel);
}
}
lessonsCounterFlag.push(int(this.data.@id.toString()));
}
else
{
this.lessonsGroupPanel.title = null;
}
}
private function customHeaderFactory1():Header
{
var header:Header = new Header();
header.fontStyles = new TextFormat( "Impact", 20, 0xcccc00 );
header.titleAlign = HorizontalAlign.LEFT;
var backgroundSkin:Quad = new Quad(300, 25, 0x000000); //TODO: make w&h sizes automatic (width at least)
header.backgroundSkin = backgroundSkin;
return header;
}
private function customHeaderFactory2():Header
{
var header:Header = new Header();
header.fontStyles = new TextFormat( "Calibri", 12, 0xcccccc );
header.titleAlign = HorizontalAlign.LEFT;
header.height = 16;
return header;
}
private function customFooterFactory2():LayoutGroup
{
var footer:LayoutGroup = new LayoutGroup();
footer.styleNameList.add( LayoutGroup.ALTERNATE_STYLE_NAME_TOOLBAR );
footer.height = 24;
var label:Label = new Label();
label.fontStyles = new TextFormat( "Calibri", 8, 0x00cccc );
label.text = "how to send data to footer?";
footer.addChild(label);
return footer;
}
}
}