The best I could figure was to have a public property and a style ... the style recieving the value from CSS and the property used to bind from the skin .. but that's kinda lame as my component api will now have a property and a style to do the same thing.
1 person found this helpful
Declare the Style as metadata on your component, and then in the Skin you can call getStyle on the hostComponent. You should be able to make this work via binding, but you could also probably do this in a function if it felt cleaner and depending on how much you want to avoid the binding overhead.
Thank you for the reply Matt,
When should hostComponent.getStyle be called by the skin ? ... I mean how do I know that a style on the host component has changed ... I couldn't find an event being dispatched by SkinnableComponent ... should I be dispatching my own event from styleChanged?
Also, aren't we trying to minimize any non declarative code that a Skin developer (designer/tool) has to write ... wouldn't this work against that .. since all skins won't need all the styles of a component I don't want to make a general base skin class for the component that inherits from SparkSkin and does getStyle for all the styles of a component .. if I don't do that then each skin needs to have some code that handles getting of host styles and then assigning them to whatever part of the skin.
1 person found this helpful
See how we've implemented the lookup in the SparkSkin base class I think.
Style lookups tend to go against the declarative nature, no question, but if you're looking on making a skin that's flexible it's unlikely you can avoid some minimum amount of code.
So I looked at SparkSkin and for baseColor it does a lookup everytime the display list is validated in updateDisplaylist .... wouldn't it be better if SkinnableComponent would dispatch an event when a style changes with info of which style changed .. SparkSkin would then listen for this event and would only do a lookup if that particular style has changed?
I could do it that way in my own inherited classes ... but it feels like something that should be there in the framework itself.
I later realized that baseColor is not coming from the host .. but even in that case shouln't there be a flag set in the styleChanged method if baseColor has changed and the lookup in updateDisplayList done only if needed.
That said the tthought to have the host throw an event when one of its styles changes and the skin reacting based on that is still valid
Yeah, I think the style probably is coming from the host, but it's via the getStyle lookup mechanism done directly since a skin is actually a child of the host component. So I was wrong in saying you call on hostComponent, calling on yourself probably just works. But your question about shouldn't we cache more seems reasonable to me, let me see if I can get Glenn to answer.
First off, you should always use getStyle() on your skin instead of hostComponent.getStyle(). We recently changed skins to pick up styles from the host component, so there is no need to go to the component for styles.
Once you've removed hostComponent.getStyle(), you can override styleChanged() to be notified of all style changes. Look at the styleChanged() implementation in some of the Halo components for details. The default implementation of styleChanged() calls invalidateDisplayList(). If you are doing all of your style processing in updateDisplayList(), you do not need to override styleChanged().
The SparkSkin class could be smarter by only applying style values that change. This would require a tracking mechanism (via styleChanged()), and "dirty" flags for the styles that are being processed. Since the style processing is a low-overhead operation (it doesn't even register on our profiled builds), we decided to keep the simpler implementation.
Got it !
Thank you, that was very helpful.
Jumping onto an old thread here .. I have a few more questions ...
What is the best approach when a particular skin needs more styles? ... styles as I understand them are like properties of a skin ... so if one skin is more complex it may need more properties than what were declared by the component as style metadata ...
For example ... I have a component with a skinpart called A .. now in my component code, anticipating that A will need a color for its fill I declare a style metadata for aColor. This ok as long as a skin defines a SolidColor fill ..but what if a skin wants to define a gradient fill ... it needs more than one color.
If styles are properties of a skin shouln't they somehow be declared by the skin and not by the component that doesn't know enough about the styles a skin may need?
Is there a different approach to do this? Am I getting this all wrong?
Thank you as always,
The more I think about this final response the more I see that really he is right.
I can see people publishing skins to share with the community. And being able to define styles that are particular to your custom skin without having to extend the core component makes all the sense in the world.
It seems that one of the core tenents of Flex 4 is the seperation of UI from architecture. But having to define the styles in a component and not in the skin seems totally backwards.
So what can we do to fix this problem? Does the SDK team see an issue here? Seems like we might be breaking something fundamental.
We're trying to jam in the solution to this now. Stay tuned for a spec hopefully next week.
So what I gathered from what Matt and Ely said in the Open Iteration Meeting .... the flex team understands that this is an issue, but this is not something that can be adressed in this release. fair enough.
But, I think that this is something very fundamental to the framework and as Simeon pointed out.. core to the intentions behind Flex 4 and hope it gets prioritiezed higher than other features.
In the current situation, given that I cannot have a lot of styling for my skinparts, since I don't know enough about how they look .. there seems no reason for them to stay programatic .. especially since I've been having other issues with them not looking exactly as my designer intended .. so now if my skin parts are not drawn in code using various primitives but are instead static assets (.swf, .png, .fxg) ... most of what I can achieve with that was achievable in Flex 3 with static assets ... hmm starts to feel like not a big enough step forward from a skinning perspective.
I've been enjoying Flex 4 a lot, but I do think that this one adition will be a big positive.
Thank you all,
Just thought I'd chime in.
One thing I've done is re-implement the StyleManager so it supports nested Selector properties. So you can do something like this:
/* style-element nesting must be dash "-" separated */
style-elements: skin, layout;
/* style-elements are what you are going to be styling, they must be defined */
style-elements: background, background-fill, background-stroke, dropDown;
background-fill-repeat: no-repeat, no-repeat;
background-fill-blend-mode: normal, screen;
color-up: "panelFillAccent base";
color-over: "panelFillAccent base";
alpha: ".8, .8";
Then the "style-elements" property tells the StyleManager parser how to find the parent/target/property, starting from the Component and working its way down the hierarchy, through the Skin, just like in MXML. So in your skin you just have DisplayObjects, IGraphicElements, IDegrafaObjects, or whatever else, with no fills/strokes/colors, and none of the new MXML state syntax (you can do that through CSS).
This also allows you to reuse common elements between skins. You can define fills in other selectors (panelLinearFill), you can store colors and such in Palettes so they're usable by name, etc.
I'll have to post up an example soon because it makes changing skins actually really fun. I'm with everyone in not enjoying having to edit the MXML Skin file when I want to change a GradientEntry alpha, and having the whole application recompile.
The nice thing with this is that you don't have to add any new Style metadata tags, which you can't anyways to components, unless you extend them which just is far from desirable. You just have your 2 or 3 shapes, and you can do the rest from CSS, totally dynamic.
Plus, this has built in transitions/animations, so you can do color tweens and whatnot. Checkout http://www.josephjewell.com for a simple project we just did using pure Flex/CSS on panels and buttons.