Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Adobe AIR Development

Reply
Developer
jtegen
Posts: 6,541
Registered: ‎10-27-2010
My Device: HTC One, PlayBook, LE Z10, DE Q10
My Carrier: Verizon

Renderer for DropDown working

Has anyone been able to create and apply a custom renderer to the DropDown control, both list and setting?  Here is my renderer:

 

package renderer
{
	//import qnx.ui.listClasses.DropDownCellRenderer;
	import qnx.ui.listClasses.AlternatingCellRenderer;
	
	public class ColorListRenderer extends AlternatingCellRenderer
	{
		public function ColorListRenderer()
		{
			super();
		}
		
		override protected function draw():void
		{
			this.graphics.clear();
			this.graphics.beginFill( 0xFF0000, 1 );
			this.graphics.drawRect( 0, 0, 10, 10 );
			this.graphics.endFill();
		}
	}
}

 And I set the control to:

 

this

 

.clock_color.setListSkin( renderer.ColorListRenderer );

I only get part of the highlight to show instead of the new box colored.

 

Please use plain text.
Developer
JRab
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Renderer for DropDown working

[ Edited ]

hey jtegen,

 

Edit: i just re-read and realized you were asking specifically for dropdown menu skinning... ill look into that and have an answer in a few... but for now here's what i thought u were taking about lol

 

i think i may have something... been looking at this for hours haha... but from what i found is that you hafta create your own custom skin. then do a cellrenderer class and then apply it to your list. heres my code for custom cells:

 

Custom Skin Class:

 

 

package com.rabcore
{
	import flash.display.Sprite;
	import flash.text.engine.SpaceJustifier;
	
	import qnx.ui.skins.SkinAssets;
	import qnx.ui.skins.SkinStates;
	import qnx.ui.skins.UISkin;


	public class MyCustomSkin extends UISkin
	{
		/**@private**/
		protected var upSkin:Sprite;
		/**@private**/
		protected var selectedSkin:Sprite;
		/**@private**/
		protected var disabledSkin:Sprite;
		/**@private**/
		protected var downSkin:Sprite;
		
		protected var upOddSkin:Sprite;

		public function MyCustomSkin()
		{
			super();
		}
		
		override protected function initializeStates():void 
		{
			
			upSkin = new Sprite();
			upSkin.graphics.beginFill(0xFF0000);
			upSkin.graphics.drawRect(0,0,200,200);
			upSkin.graphics.endFill();
			
			upOddSkin = new Sprite();
			upOddSkin.graphics.beginFill(0x342D7E);
			upOddSkin.graphics.drawRect(0,0,200,200);
			upOddSkin.graphics.endFill();
			
			downSkin = new Sprite();
			downSkin.graphics.beginFill(0x333333);
			downSkin.graphics.drawRect(0,0,200,200);
			downSkin.graphics.endFill();
			
			disabledSkin = new Sprite();
			disabledSkin.graphics.beginFill(0xCC0000);
			disabledSkin.graphics.drawRect(0,0,200,200);
			disabledSkin.graphics.endFill();
			
			selectedSkin = new Sprite();
			selectedSkin.graphics.beginFill(0x000000);
			selectedSkin.graphics.drawRect(0,0,200,200);
			selectedSkin.graphics.endFill();
			
			
			setSkinState(SkinStates.UP, upSkin );
			setSkinState(SkinStates.UP_ODD, upOddSkin );
			setSkinState(SkinStates.SELECTED,selectedSkin );
			setSkinState( SkinStates.DISABLED, disabledSkin );
			setSkinState( SkinStates.DOWN, downSkin );
			showSkin( upSkin );
			
		}

	}
}

 

 

(got most of it from this link: http://www.blackberry.com/developers/docs/airapi/1.0.0/qnx/ui/skins/package-detail.html)

 

Custom CellRenderer class:

 

 

package com.rabcore
{
	
	import qnx.ui.listClasses.AlternatingCellRenderer;
	
	
	public class MyCellRenderer extends AlternatingCellRenderer
	{
		public function MyCellRenderer()
		{
			super();
			setSkin(MyCustomSkin);
		}
		

	}
}

 

 

and this is my main class:

 

 

package
{
	import flash.display.Sprite;
	
	import qnx.ui.data.DataProvider;
	import qnx.ui.listClasses.CellRenderer;
	import qnx.ui.listClasses.List;
	
	import com.rabcore.MyCustomSkin;
	import com.rabcore.MyCellRenderer;
	
	
	
	// The following metadata specifies the size and properties of the canvas that
	// this application should occupy on the BlackBerry PlayBook screen.
	[SWF(width="1024", height="600", backgroundColor="#cccccc", frameRate="30")]
	public class MaxG extends Sprite
	{
		public function MaxG()
		{
			var listOfThings:List = new List();
			
			var dp:DataProvider = new DataProvider();
			
			var arr:Array = new Array();		
			
			arr.push({label: "A long label."});
			arr.push({label: "A very long label."});
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			

			listOfThings.width = 300;
			listOfThings.columnWidth = 300;
			listOfThings.rowHeight = 40;
			listOfThings.height = arr.length * 40;
			listOfThings.scrollable = false;
			
			listOfThings.setSkin(MyCellRenderer);
			
			
			dp.setItems(arr);
			
			listOfThings.dataProvider = dp; 
			
			addChild(listOfThings);


			
		}
	}
}

 

 

so to sum it up to get customized lists:

 

make a skin > apply the skin to a custom cell renderer > apply it to the list

 

ps sorry for the ugly colors and sloppy coding.. was rushing and testing.. im impatient =]

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Please use plain text.
Developer
JRab
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Renderer for DropDown working

hey back again,

 

so the same concept still applies just change the list data type to DropDown instead of List and change the listOfThings.setSkin(MyCellRenderer) to listOfThings.setListSkin(MyCellRenderer):

 

Main Class (Updated):

 

 

package
{
	import flash.display.Sprite;
	
	import qnx.ui.data.DataProvider;
	import qnx.ui.listClasses.CellRenderer;
	import qnx.ui.listClasses.DropDown;
	
	import com.rabcore.MyCustomSkin;
	import com.rabcore.MyCellRenderer;
	
	
	
	// The following metadata specifies the size and properties of the canvas that
	// this application should occupy on the BlackBerry PlayBook screen.
	[SWF(width="1024", height="600", backgroundColor="#cccccc", frameRate="30")]
	public class MaxG extends Sprite
	{
		public function MaxG()
		{
			var listOfThings:DropDown = new DropDown();
			
			var dp:DataProvider = new DataProvider();
			
			var arr:Array = new Array();		
			
			arr.push({label: "A long label."});
			arr.push({label: "A very long label."});
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			arr.push({label: "An extremeley long label."});	
			

			listOfThings.width = 300;
			listOfThings.rowHeight = 40;
			
			
			listOfThings.setListSkin(MyCellRenderer);
			
			
			dp.setItems(arr);
			
			listOfThings.dataProvider = dp; 
			
			addChild(listOfThings);


			
		}
	}
}

 

still ugly colors but main concept is there. hope that helps!

 

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Please use plain text.
Developer
jtegen
Posts: 6,541
Registered: ‎10-27-2010
My Device: HTC One, PlayBook, LE Z10, DE Q10
My Carrier: Verizon

Re: Renderer for DropDown working

The works, but maybe not what I am looking for.

 

The data provider is driving the color of each item in the list.

I have a drop down color choices (say: red, green, blue, and orange). I want the background or each row in the drop down be that color to choose from. The skin approach looks static (vs dynamic based on the the data field of the data provider) and does appear to be able to reference the renderer that does have access to the data Object of each item in the list.

Here is my data provider:

this.clock_color.dataProvider = new DataProvider( [
{color:0x00FF00,label:'green'},
{color:0x42A1F5,label:'blue'},
{color:0xFC8403,label:'orange'},
{color:0xC3C6C9,label:'silver'}] );

this.clock_color.rowCount = this.clock_color.dataProvider.length;
this.clock_color.setListSkin( renderer.ColorListRenderer );
this.clock_color.addEventListener(Event.SELECT, ColorSelected );

 My renderer is just:

package renderer
{
  //import qnx.ui.listClasses.DropDownCellRenderer;
  import flash.display.Sprite;
  import qnx.ui.listClasses.AlternatingCellRenderer;
	
  public class ColorListRenderer extends AlternatingCellRenderer
  {
	private var cell :Sprite;
		
	public function ColorListRenderer()
	{
		super();
		this.cell = new Sprite();
		this.addChild( this.cell );
		//this.setSkin( renderer.ColorListSkin );
	}
		
	override protected function draw():void
	{
		if( this.data == null )return;
		this.cell.y = 5;
		this.cell.graphics.clear();
		this.cell.graphics.lineStyle( 1, 0x000000, 3 );
		this.cell.graphics.beginFill( this.data.color, 1 );
		this.cell.graphics.drawRect( 3, 0, 10, this.height-7 );
		this.cell.graphics.endFill();
	}

  }
}

 

And this is what I get:

DropDownRenderer.jpg

 

Other than making the color wider and trying to figure out why the highlist area gets truncated, there are two issues here:

 

1) The color being drawn in the renderer for a particular row does not match the data provider.  They are opposite.  But the selectedItem is correct.  I will probably work around to draw the opposite index from the parent unless someone can tell me an alternate way.

 

2) The button renderer cannot use the same renderer as the drop down list.  Seems kind of inefficient.  Any ideas?

 

3) It appears the renderer can not alter the label attribute's location.  In this case, it would be nice to place it above the color background or shift it over to the right.

Please use plain text.
Developer
JRab
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Renderer for DropDown working

hey jtegen,

 

i've been messing around with it for a while... i think the answer lies in the draw function. although we are overriding it, we are probably not hitting all of the functionality of the orginal draw function called by the AlternateCellRenderer class. ill keep looking at it though.

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Please use plain text.
Developer
JRab
Posts: 2,462
Registered: ‎11-04-2010
My Device: Bold 9700

Re: Renderer for DropDown working

[ Edited ]

hey jtegen,

 

finally got it.

 

here's the code for my main class (nothing is different minus the added color attribute to the data and i also added some more colors to test out the effect):

 

 

package
{
	import flash.display.Sprite;
	
	import qnx.ui.data.DataProvider;
	import qnx.ui.listClasses.DropDown;
	
	import com.rabcore.MyCustomSkin;
	import com.rabcore.MyCellRenderer;
	
	
	
	// The following metadata specifies the size and properties of the canvas that
	// this application should occupy on the BlackBerry PlayBook screen.
	[SWF(width="1024", height="600", backgroundColor="#cccccc", frameRate="30")]
	public class MaxG extends Sprite
	{
		public function MaxG()
		{
			var listOfThings:DropDown = new DropDown();
			
			var dp:DataProvider = new DataProvider();
			
			var arr:Array = new Array([{color:0x00FF00,label:'green'},
				{color:0x42A1F5,label:'blue'},
				{color:0xFC8403,label:'orange'},
				{color:0xFF0000,label:'red'},
				{color:0xFFFF00,label:'yellow'},
				{color:0xC3C6C9,label:'silver'}] );
			
			
			
			dp.setItems(arr[0]);
			
			listOfThings.dataProvider = dp; 
			
			listOfThings.width = 300;
			listOfThings.rowHeight = 40;
			listOfThings.rowCount = dp.length;
			
			
			listOfThings.setListSkin(MyCellRenderer);
			addChild(listOfThings);
			
			
			
		}
	}
}

 

here is my code from my custom cell renderer class (a lot of modification to this from my previous post):

 

 

package com.rabcore
{
	
	
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFormat;
	
	import qnx.ui.listClasses.DropDownCellRenderer;
	import qnx.ui.text.Label;
	
	
	public class MyCellRenderer extends DropDownCellRenderer
	{
		//set up two variables for use later
		private var doBackground:Shape;
		private var textLabel:Label;
		
		public function MyCellRenderer()
		{
			super();
			
			doBackground = new Shape();
			textLabel = new Label();
		
		}
		
		override protected function onAdded():void
		{
			//perform original function before doing anything else...
			//not doing so causes massive errors
			super.onAdded();
			
			//create new "backgrounds" for the list of options
			this.doBackground.graphics.beginFill(this.data.color, 1);
			this.doBackground.graphics.drawRect(0, 0, 300, 40);
			this.doBackground.graphics.endFill();
			
			//since the old text data will not show up due to order
			//of children you have to add your own labels
			this.textLabel.text = this.data.label;
			
			//add both of the new items to the screen
			addChild(this.doBackground);
			addChild(this.textLabel);
		}
		
		override protected function onRemoved():void
		{
			
			super.onRemoved();
			
			//undo the add child
			removeChild(this.doBackground);
			removeChild(this.textLabel);
			
		}
		

	}
}

 

 

ok so here's what it turned out to be. the draw function that we were calling is called a lot even when it has nothing to do with the current cell. then i stumbled upon the onAdded and onRemoved functoins. The onAdded function is called everytime a user clicks on the drop down to reveal its items. I used that function and added each background color and text to the list. I had to add the text manually cuz the orginal data gets buried underneath the new background. and finally he onRemoved is triggered anytime the user chooses and option from the drop down.

 

also you may note i used the DropDownCellRenderer instead of the AlternateCellRenderer. I only used it because it seemed to apply to the problem more than the others.

 

on a final note the text that we now output is unformatted but we can solve that using the textformat for the labels. hopet his fits what you were looking for!

 

preview:

 

dropdownmenu.png

J. Rab (Blog) (Twitter)
--
1. If you liked my post or found it useful please click on the thumbs up and provide a Like!
2. If my post solved your problem please click on the Accept as Solution button. Much appreciated!

Approved Apps: OnTrack | ssShots | Hangman
Please use plain text.
Developer
jtegen
Posts: 6,541
Registered: ‎10-27-2010
My Device: HTC One, PlayBook, LE Z10, DE Q10
My Carrier: Verizon

Re: Renderer for DropDown working

[ Edited ]

Great lead.  Thanks. Here is my final renderer in case others can use it:

 

package renderer
{
  import flash.display.Sprite;
  import flash.text.TextFormat;
  import qnx.ui.listClasses.DropDownCellRenderer;
	
  public class ColorListRenderer extends DropDownCellRenderer
  {
	private var cell :Sprite;
		
	///////////////////////////////////////////////////////////////
	public function ColorListRenderer()
	{
		super();
		this.cell = new Sprite();		
	}
		
	////////////////////////////////////////////////////////////////
	override protected function onAdded():void
	{
		super.onAdded();
		if( this.data == null )return;
		this.cell.graphics.clear();
		this.cell.graphics.lineStyle( 1, 0x000000, 3 );
		this.cell.graphics.beginFill( this.data.color, 1 );
		this.cell.graphics.drawRect( 3, 5, this.width-7, this.height-10 );
		this.cell.graphics.endFill();
			
		this.addChild( this.cell );
		this.setChildIndex( this.label, this.numChildren-1 );
		this.label.format = new TextFormat( null, null, 0x000000 );
	}
		
	///////////////////////////////////////////////////////////////
	override protected function onRemoved():void
	{
		super.onRemoved();
		this.removeChild( this.cell );
	}

  }
}

 

Two adjustments:

  1. I just push the current label attribute forward instead on createing a new one (setChildIndex).
  2. Inset the color box so the user can see which item is current selected.
  3. Also, kept hte label black since it turns white for the current selection, and it was hard to see against one of the colors (silver/grey)

 

Wish the renderer would act on the button and not just the drop down list, but I can live with that for now.

 

JRab: Thank you for saving me a few hours!!

 

Please use plain text.