Flex Mobile : How to skin view? - actionscript-3

I would like to know if it's possible to skin view for my Flex mobile application :
My ActivityView.as
public class ActivityView extends View
My ActivityViewSkin.mxml (It skin associated)
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("com.corp.views.activity.ActivityView")]
...
It's a good way for mobile development ?
And how can I use this in this skin :
<s:navigationContent>
Thank you very much !
Anthony

no.
Spark skin is not optimized for mobile. you should use MobileSkin . (Action script only).

I have been looking for similar information, however everything I can deduce from documentation and blogs implies that MobileSkin is something you do for component-level skinning (e.g. buttons, lists, itemRenderers, etc.), things that would be used many times throughout the app.
THe other reason to think you might be able to get away with skinning your View via MXML is that all the Views I have seen code for are done so declaratively (MXML) and by skinning the View subclass using just the Skin class, you are only adding one more layer of hierarchy via the contentGroup in most skinnableContainer skins.
If you are using spark.components.View, then you are using a skin associated with as it is a SkinnableContainer. It is NOT a simple group as you might think.
I dunno, I am kinda at a loss as to where to focus my efforts. I am sure performance implications (if any) will rear their heads way later in the development stage.

From experience so far, you don't skin the View. You skin the ViewNavigatorApplication. First, create the custom skin:
public class DViewNavigatorApplicationSkin extends ViewNavigatorApplicationSkin
{
[Embed(source="assets/wine_240.jpg")]
protected var cornerImage:Class;
public function DViewNavigatorApplicationSkin()
{
super();
}
override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
{
graphics.beginFill(0x000000);
graphics.drawRect(0,0, unscaledWidth, unscaledHeight);
graphics.endFill();
var ba:BitmapAsset = new cornerImage() as BitmapAsset;
var translateMatrix:Matrix = new Matrix();
translateMatrix.tx = unscaledWidth - ba.width;
translateMatrix.ty = unscaledHeight - ba.height;
graphics.beginBitmapFill(ba.bitmapData, translateMatrix);
graphics.drawRect(unscaledWidth - ba.width + 1, unscaledHeight - ba.height + 1, ba.width, ba.height);
graphics.endFill();
}
The contents of drawBackground docks the image to the lower right-hand corner of the display. You can draw anything in this function.
Then in the theme.css:
s|ViewNavigatorApplication
{
color: #ffffff;
focusColor: #ff9999;
skinClass: ClassReference("com.domain.skins.mobile.ThemeName.DViewNavigatorApplicationSkin");
}
s|View
{
backgroundAlpha: 0;
}
You draw the background image on the application itself. You then make the View totally transparent so that you can see the background image through it.
It may be possible to skin each individual view, but so far, it seems more practical to skin the application instead.

It is kinda late to answer this question. Actually, we can use Spark Skin to skin the View component without any problem. View is just a subclass of SkinnableContainer (which is subclass of SkinnableComponent) so by default, whatever content you add directly to the MXML of View component will be added to contenGroup of SkinnableContainer.
I have added an example to skin the View using Spark Skin:
Main Application:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="160">
<fx:Script>
<![CDATA[
import com.accessdigital.core.SimpleView;
]]>
</fx:Script>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace core "com.accessdigital.core.*";
core|SimpleView{
skinClass : ClassReference("skin.view.Skin_SimpleView");
}
</fx:Style>
<s:ViewNavigator width="100%" height="100%"
firstView="{SimpleView}">
</s:ViewNavigator>
</s:Application>
View Class
public class SimpleView extends View
{
public function SimpleView()
{
super();
}
[SkinPart(required="true")]
public var myButton:Button;
override protected function createChildren():void{
super.createChildren();
var anotherButton:Button = new Button();
anotherButton.label = "Another button";
anotherButton.addEventListener(MouseEvent.CLICK, onAnotherButtonClick);
if(!actionContent){
actionContent = [];
}
actionContent.push(anotherButton);
}
protected function onAnotherButtonClick(event:MouseEvent):void
{
trace("This is another button");
}
override protected function partAdded(partName:String, instance:Object):void{
super.partAdded(partName, instance);
if(instance == myButton){
myButton.addEventListener(MouseEvent.CLICK, onButtonClick);
}
}
protected function onButtonClick(event:MouseEvent):void
{
trace("This is a simple button");
}
}
Skin File:
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<!-- host component -->
<fx:Metadata>
[HostComponent("com.accessdigital.core.SimpleView")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="disabled" />
<s:State name="normal" />
</s:states>
<!-- SkinParts
name=myButton, type=spark.components.Button, required=true
name=contentGroup, type=spark.components.Group, required=false
-->
<s:Rect width="100%" height="100%">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="#666666"/>
<s:GradientEntry color="#222222"/>
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Group id="contentGroup" width="100%" height="100%">
<s:Button id="myButton" label="My Button" horizontalCenter="0" verticalCenter="0"/>
</s:Group>
</s:Skin>
Hope it helps

Related

Itemrender of DataGroup won't release memory - flex(Adobe air)

i have a datagroup compoenent in Adobe Air application and i have used custom itemrenderer in it, i attached source code of itemRenderer as well as i attached profiling of it,
Question:
When i come back from other module to the module which have this datagroup at that time it again create Objects for itemrender and previous object of itemrender wont released.
if you have idea, please suggest me
<?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"
buttonMode="true"
click="clickHandler(event)"
mouseChildren="false"
rollOut="rollOutHandler(event)"
rollOver="rollOverHandler(event)"
removedFromStage="itemrenderer1_removedFromStageHandler(event)"
creationComplete="itemrenderer1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import coX.XXXXXXXXXXXXXXX.event.ThumbEvent;
import mx.events.FlexEvent;
protected function image_completeHandler(event:Event):void
{
ConsoleUtils.logIt(" ThumbImage.mxml :image_completeHandler - ");
image.removeEventListener(Event.COMPLETE, image_completeHandler);
fadeIn.target=image;
fadeIn.play();
}
protected function clickHandler(event:MouseEvent):void
{
owner.dispatchEvent(new ThumbEvent("itemclick", data, itemIndex));
}
protected function rollOverHandler(event:MouseEvent):void
{
owner.dispatchEvent(new ThumbEvent("itemrollover", data, itemIndex));
}
protected function rollOutHandler(event:MouseEvent):void
{
owner.dispatchEvent(new ThumbEvent("itemrollout", data, itemIndex));
}
protected function itemrenderer1_removedFromStageHandler(event:Event):void
{
this.removeEventListener(Event.REMOVED_FROM_STAGE, itemrenderer1_removedFromStageHandler);
this.removeEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
this.removeEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
this.removeEventListener(MouseEvent.CLICK, clickHandler);
this.removeAllElements();
}
protected function itemrenderer1_creationCompleteHandler(event:FlexEvent):void
{
this.removeEventListener(FlexEvent.CREATION_COMPLETE, itemrenderer1_creationCompleteHandler);
image.source="test.png";
//image.addEventListener(Event.COMPLETE, image_completeHandler);
}
]]>
</fx:Script>
<fx:Declarations>
<s:Fade id="fadeIn"
alphaFrom="0"
alphaTo="1"/>
</fx:Declarations>
<s:BitmapImage id="image"
horizontalAlign="center"
smooth="true"
smoothingQuality="high"
verticalAlign="middle"/>
</s:ItemRenderer>
Snapshot of Profiling
as you can see, in profile, i have 21 orphan objects which won't recyle and profiling shows me that at saved at line no 12 while line no 12 is creation_complete event and i have removed it.
Thanks in Advance
i have used DataGroup as parent component and i have define above itemRenderer in itemRenderer property of the DataGroup, and in dispose function i have define DataGroup.itemRenderer is null in DataGroup. so it will eligible for GC. and i see that now no instance of itemRenderer is in memory.

Hide a Button in a ButtonBar

I was wondering if there is any way you hide a particular button in a ButtonBar. According to this answer (and the link provided in the second answer) Disable individual buttons in a buttonbar I need to use the getChildAt method of the ButtonBar, but when I do that I get the custom skin object and not the Button object. I was wondering how I could get access to the Button object.
Thanks!
Under the assumption that all buttons in your button bar will be rendered at the same time and you won't need scrollbars...
With a Spark ButtonBar, you can access the skin part directly to get access to a button. Conceptually something like this:
var button : Button = mySparkButtonBarInstance.dataGroup.getElementAt(SomeIndex);
button.visible = false; // or true
button.includeInLayout = false; // or true
This won't work if your ButtonBar can make use of Virtual Layouts and requires scrolling.
Edit: Here is working code demonstrating this technique:
<?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">
<fx:Script>
<![CDATA[
import mx.core.IVisualElement;
protected function button1_clickHandler(event:MouseEvent):void
{
trace(buttonBar.dataGroup.getElementAt(0));
var button :IVisualElement = buttonBar.dataGroup.getElementAt(0);
button.visible = false; // or true
button.includeInLayout = false; // or true }
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout paddingLeft="20" paddingTop="20"/>
</s:layout>
<s:ButtonBar id="buttonBar">
<mx:ArrayCollection>
<fx:String>Flash</fx:String>
<fx:String>Director</fx:String>
<fx:String>Dreamweaver</fx:String>
<fx:String>ColdFusion</fx:String>
</mx:ArrayCollection>
</s:ButtonBar>
<s:Button label="Remove" click="button1_clickHandler(event)" />
</s:WindowedApplication>

How to manually remove UI Component from Parsley/Flex context?

How to manually remove view component from Parsley context?
Lets say I have one view and main application.
I have done the following but it does not work - view remains within Parsley context.
Main Application:
<s:Application>
<parsley:ContextBuilder config="ApplicationConfig"/>
<view:SomeView id="someView"/>
<s:Button label="Enable View"
click="enableViewHandler()"/>
<s:Button label="Disable View"
click="disableViewHandler()"/>
<fx:Script>
private function enableViewHandler():void {
someView.dispatchEvent(new Event("configureView", true));
}
private function disableViewHandler():void {
someView.dispatchEvent(new Event("removeView", true));
}
</fx:Script>
</s:Application>
View Component:
<s:VGroup>
<fx:Metadata>
[Autoremove("false")]
</fx:Metadata>
</s:VGroup>
The only solution I have found is to change enableViewHandler() to Configure.view(someView).autoremove(false).execute();

Inheritance with Flex mxml files - screenshot attached

In a Flex mobile app I have 5 Views, handling OAuth logins through 5 different social networks - including Google+ and Facebook. The Views are being selected through the menu shown below:
The filenames are FB.mxml, GG.mxml, MR.mxml, OK.mxml, VK.mxml and their source code looks very similar:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
viewActivate="loadInfo(event)"
viewDeactivate="closeSWV(event)"
title="Facebook.com">
....
private function closeSWV(event:Event=null):void {
_busy.visible = _busy.includeInLayout = false;
_reload.visible = _reload.includeInLayout = true;
stage.removeEventListener(Event.RESIZE, resizeSWV);
if (! _swv)
return;
_swv.removeEventListener(Event.COMPLETE, extractAccessToken);
_swv.removeEventListener(LocationChangeEvent.LOCATION_CHANGE, extractAccessToken);
_swv.removeEventListener(IOErrorEvent.IO_ERROR, closeSWV);
_swv.removeEventListener(ErrorEvent.ERROR, closeSWV);
_swv.dispose();
_swv = null;
}
private function resizeSWV(event:Event=null):void {
if (! _swv)
return;
// align to the right-bottom corner
_swv.viewPort = new Rectangle(stage.stageWidth - Preferans.SCALE * width,
stage.stageHeight - Preferans.SCALE * height,
Preferans.SCALE * width,
Preferans.SCALE * height);
}
....
<s:VGroup>
<s:Label id="_first" fontWeight="bold" text="Your name:" />
<s:Label id="_gender" fontWeight="bold" text="Gender:" />
<s:Label id="_city" fontWeight="bold" text="City:" />
</s:VGroup>
<s:Button id="_play"
label="Play"
click="startGame(event)"
includeInLayout="false"
visible="false" />
</s:View>
My problem is: The 5 mxml files listed above have many similar methods and variables and UI elements and only few different methods and variables.
I've tried to introduce a "base class" for them all several times already and have always given up, because it is not straightforward for mxml files (versus pure AS3 classes).
Does anybody please have an idea, how to approach this?
You can define an abstract class that extends the UI component that you want to use in each row of the list. In your case, it will extend View.
package your.package{
public class SocialAccountView extends View{
// in this class you can add the generic methods
// that you want the view to have
}
}
After that, in the mxml file you can use the class you created as the main type instead of View
<your.package:SocialAccountView
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
viewActivate="loadInfo(event)"
viewDeactivate="closeSWV(event)"
title="Facebook.com">
</your.package:SocialAccountView>
With this you know that all the items in the list are of that type, and have the methods of the parent class. You can even override methods in each view.
Regarding the UI components, the maximum abstraction level (that I am aware of) you can have with them is to build an extra component and use it in all views. Something like...
Labels.mxml
<s:VGroup>
<s:Label id="_first" fontWeight="bold" text="Your name:" />
<s:Label id="_gender" fontWeight="bold" text="Gender:" />
<s:Label id="_city" fontWeight="bold" text="City:" />
</s:VGroup>
and then use it in each component like
<your.package:Labels
id="labelsComponent"/>
Hope this helps.

Flex: how to control Spark datagrid header-text alignment?

If I have 10 columns in a Spark datagrid, and some headers need to be left-justified, some headers right-justified, and some centered, what's the simplest way to accomplish this?
Assuming a custom headerRenderer is needed, are there any simple examples that can walk me through it?
Thanks in advance for any comments.
The simplest way I could find to solve this is to override the settings in the spark DefaultGridHeaderRenderer, as discussed in this link:
http://flexponential.com/2011/10/30/changing-fontweight-of-spark-datagrid-headers/
More specifically, I used the following custom headerRenderer, saved as file: myRightHeaderRenderer.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:DefaultGridHeaderRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" >
<fx:Declarations>
<s:Label id="labelDisplay"
verticalCenter="1" left="0" right="0" top="0" bottom="0"
verticalAlign="middle"
maxDisplayedLines="1"
textAlign="right"
fontWeight="bold"
showTruncationTip="true" />
</fx:Declarations>
</s:DefaultGridHeaderRenderer>
This custom header renderer right-justifies header text. To use it, simply add it to one or more columns of the Spark DataGrid as follows:
...
<fx:Array>
<s:GridColumn ... />
<s:GridColumn headerRenderer="myRightHeaderRenderer" ...>
<s:GridColumn ... />
...
</fx:Array>
...
I'm not sure how to do it, but I'm sure it can be made more flexible by parameterizing the textAlign attribute to be center, left, or right.
If you take a look at this blog post, there's a decent amount of source code available showing you how to do this.
However, I think that the blog's example is much more complex than you'll need. You will need a custom headerRenderer, as you feared, but your code should be pretty straightforward. I've only tested this lightly, so if you have any issues, let me know.
Custom Header Renderer
package
{
import spark.skins.spark.DefaultGridHeaderRenderer;
public class CustomGridHeader extends DefaultGridHeaderRenderer
{
public function CustomGridHeader()
{
super();
}
public function set headerTextAlign(value:String):void
{
labelDisplay.setStyle("textAlign",value);
labelDisplay.styleChanged("textAlign");
}
}
}
Variables Available to Your Columns...
[Bindable] private var leftFactory:ClassFactory = new ClassFactory(CustomGridHeader);
[Bindable] private var rightFactory:ClassFactory = new ClassFactory(CustomGridHeader);
[Bindable] private var centerFactory:ClassFactory = new ClassFactory(CustomGridHeader);
On initialize or preinitialize...
leftFactory.properties = {headerTextAlign: "left"};
rightFactory.properties = {headerTextAlign: "right"};
centerFactory.properties = {headerTextAlign: "center"};
For Each Column...
<s:GridColumn headerText="..." headerRenderer="{centerFactory}"/>