PDA

Просмотр полной версии : Вопросы по реализации менюшки


Фенёк
04.04.2012, 13:57
Привет всем, это опять я, с новичковыми вопросами )

Нужно реализвать менюшку как в приложении используй байндинг, кастом рендерер и скинирование.

Я так понял, что рабочую область нужно разбить на два компонента и разместить их друг под другом.

Собственно первый вопрос: как правильно их друг под другом разместить не задавая жестко координаты? Сейчас в качестве контейнера воспользовался VBox'ом, интересует, насколько это адекватное решение.

Далее я так понял, что нижняя часть менюшки представляет собой Panel c Label и TextInput, а вот что собой представляет верхушка? Panel? DataGrid?

Байндинг, насколько я успел понять необходи для того, чтобы связать между собой картинки/цены c переменными.

Кастомный АйтемРендерер по видимости используется для вставки картинок в компоненты.

Что собой представляет скинирование так и не смог усвоить, если кто-нибудь даст краткое определение в контексте флекса, был бы очень признателен.

Astraport
04.04.2012, 16:18
Верхушку лучше сделать TileGroup без горизонтального скролла. Ну и итемрендерер - это каждая ячейка с картинкой, рамкой и всем прочим. Ну и очень много скинирования предстоит.

Genzo
04.04.2012, 16:30
Я бы создал компонент наследника Canvas/Group (смотря что используете), в нем Image, 2 Label'а и еще компонент, который выводит цену, и добавлял бы в V/H Group

Фенёк
04.04.2012, 20:01
Вобщем короче паника ) Пока что слепил вот такого монстра

<s:Panel title = 'Магазин' width ='410' height = '410' horizontalCenter="0" verticalCenter="0">
<s:Group>
<s:TileGroup requestedRowCount = '5' requestedColumnCount = '2' verticalGap = '1' horizontalGap = '1'>
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
<s:BorderContainer width = '200' />
</s:TileGroup>
</s:Group>
</s:Panel>


Вобщем еще ряд вопросов появился. Во первых я смотрю, что с четвертой версии флекса убрали выравнивание внутри основного контейнера приложаения, но в документации не написано куда его переложили. Собственно отсюда вопрос номер раз: где теперь нужно искать (хотя бы в каком пространстве имен) выравнивание элементов внутри приложения?

Дальше, вот собственно в коде засовываю я в панельку Бордер контейнеры, лезут они за его края, а панельке и хоть бы хны, лезут, да и пускай лезут. Есть ли свойство, которое ограничивало бы показ элементов в панельке аналогичным maxWidth/maxHeight?

Еще один вопрос который меня крайне беспокоит — почему БордерКонтейнеру нельзя назначить ширину/высоту в зависимости от размеров родителя? Мне находится это влечайшей гнусностью да и вообще просто воплощением несправедливости )

Еще один вопрос, ответ на который е смог сыскать в документации как назначить порядок в котором будут складываться элементы в ТайлГроуп? То есть ведь должна же быть штука позволяющая мне выбирать будт ли элементы заполняться слева направо или сверху вниз.

sstotenkopf
04.04.2012, 20:23
Почитайте про list и itemrenderer, я же давал вам ссылки

Фенёк
05.04.2012, 19:51
Дошел до такого состояния:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
initialize = 'initData()'>

<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection

[Bindable]
private var dp:ArrayCollection

[Embed(source = '../images/ok.png')]
public var okImg:Class;

[Embed(source = '../images/cancel.png')]
public var cancelImg:Class;

private function initData():void
{
dp = new ArrayCollection([

{image:new okImg(), title:'Its Okay', autor:'Me'},
{image:new cancelImg(), title:'CANCEL IT!', autor:'Someone Else'}

]);
}

]]>
</fx:Script>

<s:List width="410" height="100" dataProvider = '{dp}'>
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:HGroup>
<s:Label text = 'Название книги: {data.title} Автор: {data.autor}'/>
<s:Image source = '{data.image}'/>
</s:HGroup>
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:WindowedApplication>


Работает, складывается.

Вопрос следующий — как разместить в листе на две колонки? как потом их перелистывать кнопками? Как организовать поиск по подстроке?

djyamato
06.04.2012, 05:37
Специально сделал для Вас
К сожалению, почему-то не выделяется первый элемент во время поиска, спать уже хочу - не вижу причину
Листаются страницы, ищется фраза в каждом айтеме и первый нашедшийся выделяется
Лист сам перематывается к выделенному айтему (ensureIndexIsVisible)
Обратите внимание как при помощи байндинга выводится надпись PAGE 1/3 (выше в коде переменные _pageIndex и _totalPages в тэге [Bindable])
С точки зрения архитектуры код ужасный, но я преследовал цель показать как можно это сделать, не более


<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="350"
height="420"
creationComplete="application1_creationCompleteHandler(event)">

<fx:Declarations>
<s:ArrayCollection id="myData">
<s:source>
<fx:Object label="Привет всем" image=""/>
<fx:Object label="это опять я" image=""/>
<fx:Object label="Нужно реализвать" image=""/>
<fx:Object label="менюшку как в" image=""/>
<fx:Object label="приложении" image=""/>
<fx:Object label="используй байндинг" image=""/>
<fx:Object label="кастом рендерер" image=""/>
<fx:Object label="и скинирование" image=""/>
<fx:Object label="Я так понял" image=""/>
<fx:Object label="что рабочую область" image=""/>
<fx:Object label="нужно разбить на два компонента" image=""/>
<fx:Object label="и разместить их друг под другом" image=""/>
<fx:Object label="item13" image=""/>
<fx:Object label="item14" image=""/>
<fx:Object label="item15" image=""/>
<fx:Object label="item16" image=""/>
<fx:Object label="item17" image=""/>
<fx:Object label="item22" image=""/>
<fx:Object label="item34" image=""/>
<fx:Object label="item3dsbdsbn" image=""/>
<fx:Object label="sdb" image=""/>
<fx:Object label="dsfbndsn" image=""/>
<fx:Object label="dsgndsfgn" image=""/>
<fx:Object label="gjn rtgn" image=""/>
<fx:Object label="retjh" image=""/>
<fx:Object label="dsfn d" image=""/>
<fx:Object label="dsfgnsdf n" image=""/>
<fx:Object label="tgjhnrtjn" image=""/>
<fx:Object label="stgjhnert" image=""/>
<fx:Object label="y,l" image=""/>
<fx:Object label="fghmked" image=""/>
<fx:Object label="sdghn" image=""/>
<fx:Object label="sdn" image=""/>
<fx:Object label="FINAL" image=""/>
</s:source>
</s:ArrayCollection>
</fx:Declarations>

<fx:Script>
<![CDATA[
import mx.events.FlexEvent;

import spark.events.TextOperationEvent;

[Bindable]
protected var _pageIndex:int=0;

[Bindable]
protected var _totalPages:int;

protected function button1_clickHandler(event:MouseEvent):void
{
//back
_pageIndex-=1;
if(_pageIndex<0)
{
_pageIndex=0;
}

itemsList.scroller.viewport.horizontalScrollPosition=350*_pageIndex;
}

protected function button2_clickHandler(event:MouseEvent):void
{
// forw
_pageIndex+=1;
if(_pageIndex>_totalPages-1)
{
_pageIndex=_totalPages-1;
}
itemsList.scroller.viewport.horizontalScrollPosition=350*_pageIndex;
}

protected function application1_creationCompleteHandler(event:FlexEvent):void
{
// расчет количества страниц с округлением в болшую сторону
_totalPages=Math.round(myData.length/12);
}

protected function serchTextInput_changeHandler(event:TextOperationEvent):void
{
var firstFoundItemIndex:int=getFirstFoundItemIndex();

// почему-то не выделяется первый item :(
if(firstFoundItemIndex)
{
itemsList.selectedIndex=firstFoundItemIndex;
itemsList.ensureIndexIsVisible(firstFoundItemIndex);
}
else
{
itemsList.selectedIndex=-1;
itemsList.ensureIndexIsVisible(0);
}
}

// поиск первого совпадения
protected function getFirstFoundItemIndex():int
{
var total:int=myData.length;
var i:int;

var index:int;

for(i=0;i<total;i++)
{
if(String(myData.getItemAt(i).label).search(serchTextInput.text)!=-1)
{
index=i;
break
}
}
return index;
}
]]>
</fx:Script>

<s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>
<s:List id="itemsList"
width="100%"
height="350"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
borderVisible="false"
itemRenderer="components.itemRenderers.CustomItemRenderer"
dataProvider="{myData}">
<s:layout>
<s:TileLayout requestedRowCount="7" horizontalGap="0" verticalGap="0" orientation="columns"/>
</s:layout>
</s:List>

<s:Group width="80%">
<s:Button left="5" label="prev" click="button1_clickHandler(event)"/>
<s:HGroup width="100%"
height="100%"
horizontalAlign="center"
verticalAlign="middle">
<s:Label text="PAGE {(_pageIndex+1)+'/'+_totalPages} "/>
</s:HGroup>
<s:Button right="5" label="next" click="button2_clickHandler(event)"/>
</s:Group>

<s:TextInput id="serchTextInput"
width="80%"
change="serchTextInput_changeHandler(event)"/>
</s:Application>



itemRenderer

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="false"
width="175"
height="50"
mouseEnabled="false">
<s:states>
<s:State name="normal"/>
<s:State name="selected"/>
</s:states>

<s:Group width="100%" height="100%">
<s:Rect left="2"
right="2"
top="2"
bottom="2">
<s:stroke>
<s:SolidColorStroke color.normal="0xcccccc" color.selected="0xff0000"/>
</s:stroke>
<s:fill>
<s:SolidColor color="0xcccccc" alpha=".3"/>
</s:fill>
</s:Rect>
</s:Group>


<s:HGroup width="100%"
height="100%"
horizontalAlign="center"
verticalAlign="middle">
<s:Label text="{data.label}" textAlign="center" width="175"/>
</s:HGroup>
</s:ItemRenderer>

Фенёк
06.04.2012, 12:27
О, большущее спасибо, только сегодня с утра наконец-то прочитал про ТайлЛэйаут )

Поиск по подстроке пофиксил. Проблема была в том, что нужно было проверять на значение пришедшего индекса, а не на его существование, так как когда туда приходил нулевой индекс, функция считала, что ничего не найдено.

Итоговый вид функции такой


protected function serchTextInput_changeHandler(event:TextOperationEvent):void
{
var firstFoundItemIndex:int=getFirstFoundItemIndex();

trace(firstFoundItemIndex);

if(firstFoundItemIndex > -1)
{
//Выделяем эелемент с полученным индексом и листаемся до него
itemsList.selectedIndex=firstFoundItemIndex;
itemsList.ensureIndexIsVisible(firstFoundItemIndex);
}
else
{
//Ни один элемент не выбирается
itemsList.selectedIndex = -1;
//Переходим к элементу под индексом 0
itemsList.ensureIndexIsVisible(0);
}
}

//поиск первого совпадения
protected function getFirstFoundItemIndex():int
{

var total:int=myData.length; //Записываем длину
var i:int; //Создаем счетчик

//Начинаем перебирать...
for(i = 0; i < total; i++)
{
//Если в лэйбле айтема найден введенный текст (метод search не вернул -1)
if(String(myData.getItemAt(i).label).search(serchTextInput.text) != -1 && serchTextInput.text.length > 0)
{
return i;
}
}

//Возвращаем значение
return -1;
}


Пока что просмотрел только Мейн, сейчас буду изучать айтемРендерер.

Еще раз огромное спасибо, мне это дало значительный шаг вперед )

djyamato
07.04.2012, 00:25
не
не так
а вот так

protected function serchTextInput_changeHandler(event:TextOperationEvent):void
{
if(serchTextInput.text.length!=0)
{
var firstFoundItemIndex:Object=getFirstFoundItemIndex();
if(firstFoundItemIndex!=-1)
{
trace("exists");
itemsList.selectedIndex=int(firstFoundItemIndex);
itemsList.ensureIndexIsVisible(int(firstFoundItemIndex));
}
else
{
unselect();
}
}
else
{
unselect();
}
}

protected function unselect():void
{
itemsList.selectedIndex=-1;
itemsList.ensureIndexIsVisible(0);
}

// поиск первого совпадения
protected function getFirstFoundItemIndex():int
{
var total:int=myData.length;
var i:int;

var index:int=0;

for(i=0;i<total;i++)
{
if(String(myData.getItemAt(i).label).indexOf(serchTextInput.text)!=-1)
{
index=i;
break
}
}
return index;
}

Фенёк
08.04.2012, 18:36
Да, так пожалуй в самом деле будет аккуратнее )