Feathers 2.0 preview: Listening to your feedback to improve the Feathers architecture

The first version of Feathers isn’t without its architectural headscratchers. Some extra boilerplate here, a little manual hand-holding there to make the components do what you want. You can usually get the job done, but sometimes, it takes a little more work than you’d prefer.

blueprintImage Credit: Blueprint by Will Scullin

Over the last year or so, I’ve been listening carefully to all of the feedback posted to the forums and in the issue tracker. I frequently ask myself a number of questions. Where are the common pain points? What features do people seem to ask for help with the most? What can I address right now, and what needs to wait until later?

In many cases, I can improve documentation, fix bugs, and add minor features that won’t break the existing apps that you’ve developed. Other things need to wait until a new major version of Feathers because they’ll end up breaking too many things for too many people. Sometimes, I simply need time to understand the problem better, or I need to get more feedback. I hate telling people that something can’t be done, and I wish I could always fix issues sooner instead of falling back on technical explanations for why Feathers works a certain way. However, a better architecture can’t be built overnight.

Several months back, I decided that instead of working on Feathers 1.4, it was time to make the leap to Feathers 2.0. I felt like I’d put enough thought into a number of common requests, and I felt confident with my plans for addressing them architecturally. In some cases, if I waited much longer, I’d probably never bite the bullet and get it done. It was finally time to break stuff, but (hopefully) in a good way.

The beta of Feathers 2.0 is coming in the near future, after I wrap up some final details (including writing preliminary documentation for some of these bigger changes). Until then, here’s a little preview of just a few things that you can expect to improve in the next version of Feathers.

Less updateItemAt()

When you change a property on an item in a list’s data provider, you either need to have the item dispatch an event to notify the item renderer of the change, or you need to call updateItemAt() on the ListCollection to force the item renderer to update. Most people opt for calling updateItemAt(), since it is more convenient.

One place where things get a little hairy is when you want a list to display a new ListCollection, but some of the collection’s items are duplicated from the list’s previous ListCollection. In Feathers 1.x, if you changed some properties on those duplicate items, the item renderers wouldn’t detect those changes. You would need to call updateItemAt() on the new ListCollection for each of the duplicate items, which usually involved looping through the entire collection because it was too annoying to figure out the exact index of each duplicate item:

var collectionLength:int = collection.length;
for(var i:int = 0; i < collectionLength; i++)
{
	collection.updateItemAt(i);
}

In Feathers 2.0, that won't be required. When you pass in a different ListCollection, the list will automatically force all item renderers to update, even if they're asked to display the same item. This change shouldn't affect performance either. If the duplicate items haven't actually changed, the item renderers can update more quickly than they would if they were asked to render completely different items.

To be clear, if you don't change the dataProvider property, and you change a property on an item, you still need to call updateItemAt(). ActionScript doesn't have any way to observe a property to see if its value changes. This simply helps those cases when you want to pass in a completely new ListCollection, and the list can automatically assume that it should forcibly update its item renderers.

Validate components off the display list

Previously, a Feathers component needed to have access the stage before it could initialize and validate. Sometimes, though, you want to use a component in some way without adding it to a parent. For instance, you might want to get its dimensions, or maybe you want to draw it to a render texture.

In one odd case, the order that Starling dispatches Event.ADDED_TO_STAGE events made it so that components that were added to their parent in the parent's constructor couldn't validate right away, even though they were technically added to the stage already. Most people didn't run into this issue, but it was frustrating for those that were used to a workflow where they added children in the constructor.

In Feathers 2.0, you can call validate() on a component at any time. Even if it isn't on the stage yet. If it hasn't initialized, it will do so immediately, before it validates.

var button:Button = new Button();
button.label = "Click Me";
button.validate();
trace( button.width, button.height ); // output: 130 58

A new theme architecture

Feathers 1.x had a couple of pain points when working with themes. Themes can be a little burdonsome for some developers because once you opt into the theme architecture, you need to do all skinning inside the theme to avoid having it override your properties. On the other hand, avoiding themes entirely can be painful too because you need to do all of the skinning manually with very few helpful defaults.

With Feathers 2.0, themes are more tightly integrated into the framework, allowing more flexibility in important areas. However, themes remain completely optional. If you want to skin the components by setting properties directly, I will always support your ability to handle it your way. Requiring themes would make Feathers less modular, and more rigid, and that's the opposite of my goals for the project.

Skinning subclasses with themes

Over time, I discovered that a number of ActionScript developers prefer to subclass components to create specialized versions of these components with common property values. For an overly-simplified example, you might create a SubmitButton class, and in the constructor, you might set the label property to "Submit".

public class SubmitButton extends Button
{
	public function SubmitButton()
	{
		super();
		this.label = "Submit";
		// you'd probably set more properties too
	}
}

If you were using a theme in Feathers 1.x, you'd need to inform the theme that the SubmitButton class should use the same skins as the Button class. If you make subclasses like this often, updating the theme every time becomes annoying very quickly.

On the other hand, some subclasses need to have very different skins from their superclass. For instance, the Check component is a subclass of the Button component because it behaves the same. It doesn't look like a regular button, though. If you created a custom component in this way, you'd definitely need to tell the theme how to skin it.

Another workflow usually involves calling a function to set common properties on a component. A submit button might be created by calling a static function like CommonComponents.createSubmitButton() that just creates a regular Button and sets some properties before returning:

public static function createSubmitButton():Button
{
	var button:Button = new Button();
	button.label = "Submit";
	return button;
}

With this workflow, subclasses are basically only used for significant changes that result in a component that needs different skins. In other words, the theme needs to be informed about every subclass, but subclassing doesn't happen very often.

The original theme architecture was designed with the second workflow (the one that doesn't subclass much) in mind. This architecture places a high burden on the first workflow because I figured most developers tried to avoid inheritance, like I usually do. As Feathers reached a wider audience, I eventually determined that I needed to support the first workflow better. Not everybody follows or agrees on the same best practices.

With themes being more tightly integrated into the components, I made it so that theming is inherited by subclasses by default. If needed, subclasses can opt into requiring separate skins. Now, the SubmitButton subclass workflow rarely needs to worry about the theme while the CommonComponents.createSubmitButton() function workflow needs to add a couple lines of code inside subclasses as a hook for the theme, but it's an uncommon situation. A nearly insignificant burden on the second workflow eases a very large burden on the first.

Excluding a component from the theme

In an ideal world, all of the styles for an HTML page will go into a single, well-structured, external CSS file. In practice, that doesn't always work out perfectly. Styles seem to slip into the HTML or JavaScript much too commonly. Similarly, in that ideal world, a Feathers theme would contain all skinning code required for an app. However, sometimes, you just want to tell Feathers, "Hey, don't give the theme access to this component. I want to skin it myself."

In Feathers 1.x, you couldn't easily set skins on a component without the theme replacing them later. It forced people to immediately learn how themes worked internally instead of allowing them to ease into it.

All components in Feathers 2.0 will have something called a style provider. Think of a style provider as a component's link to the theme. When the component initializes, it asks the style provider to set the skins.

A component isn't required to have a style provider, though. The chosen theme provides one by default, but you can get rid of it before the component initializes. Telling a theme not to skin a button is as easy as setting the style provider to null:

var button:Button = new Button();

// no theme, please!
button.styleProvider = null;

// now set some skins!
button.defaultSkin = new Image( texture );

this.addChild( button );

Once you've done that, you can set any property that you want, and you'll be confident that the theme won't interfere.

Beyond Feathers 2.0

These changes should ease some of the biggest pain points people have with Feathers. That said, as you all get comfortable with the new changes, I don't doubt that different architectural issues will be uncovered now that I've cleaned up the bigger ones. I want to fix those issues too! Please, never hesitate to start a thread in the forums or to open an issue on Github. I may not be able to address every issue right away, but your feedback will not be forgotten. I want to make Feathers better for all Starling projects, including both games and apps.

A beta build of Feathers 2.0 will be available in the coming weeks. I'm looking forward to your feedback — both positive and negative. If you'd like an extra early peek at the new 2.0 source code, you can download the Feathers master branch on Github. Remember, this isn't a stable build that everyone should try. It's pre-beta code that may contain bugs. Use at your own risk, and have some fun!

Feathers 1.3.0

Today, I’m very happy to present Feathers 1.3.0, the latest stable release of the open source user interface components for Starling Framework. This version packs a punch with a couple of much-anticipated new features. I also dedicated many days to filling in many gaps and annoyances here and there, so get ready for the most stable and mature release of Feathers yet.

percent-layout-smaller

First up, we have one feature that many developers have been waiting for: percent-based dimensions in layouts. Fluid layouts have been possible since Feathers 1.1.0, with the introduction of AnchorLayout, but I know that many developers prefer percentages instead. HorizontalLayout, VerticalLayout, and AnchorLayout all support adding layout data to components to specify percent width and height values.

Flash Text Engine (FTE) provides advanced text layout capabilities that the traditional Flash TextField can never achieve, with more low-level control over text-metrics, formatting, and bi-directional text. Feathers 1.3.0 adds a new text renderer named TextBlockTextRenderer that exposes many FTE APIs.

Feathers 1.3.0 includes many other smaller enhancements. Among them include support for Mac HiDPI resolutions, better support for multiple desktop windows with different Starling instances, and the example themes are now built as SWCs to allow anyone to easily drop them into a new project. That’s not all, of course. For complete details about what’s new in Feathers 1.3.0, please read the release notes. Now, go download Feathers 1.3.0, and enjoy!

Where to download old versions of the Adobe Flex SDK

If you’re maintaining a legacy project that will not compile or run correctly with the latest Apache Flex SDK, you may prefer to avoid overhauling the entire project simply to make some minor bug fixes. If you’d rather continue using the same Flex SDK that project was originally developed with, you’ll be asking yourself, “Where can I find old builds of the Adobe Flex SDK?” They’re not exactly easy to find.

Adobe helpfully provides Archived Flash Player versions and Archived AIR SDK versions on their website. However, I had some difficulty finding a similar archive for the Adobe Flex SDK. The most promising resource was the SourceForge Flex SDK Downloads, but all of the links point to a strange FlexLicense.swf on blogs.adobe.com that my browser asks me to download instead of running directly.

After searching for a while, I could only find direct links to a few specific versions of the Adobe Flex SDK, but most versions remained seemingly lost. Eventually, I returned to that weird FlexLicense.swf, and I gave it a try with the standalone Flash Player. Someone else posted that they couldn’t get it to run at all after downloading it (which is why I didn’t try it earlier), but it worked for me, and I took the time to select each version of the Adobe Flex SDK that it listed, and I was able to open a valid URL in my browser for every single one of them.

In order to keep my fellow developers from going through the same hassle, I compiled the following list of legacy Adobe Flex SDK versions that are still available on Adobe’s servers at the time of this writing:

Hopefully, that helps another Flex developer with some legacy code to maintain.