Leopard Innovations • 54:15
Dashcode, a new developer tool in Leopard, provides everything you need to create great Dashboard widgets, even if you are new to programming. Apple engineers will walk you through the creation of a real widget, showing you how to visually construct your widget out of the included parts to give it a custom, polished look. You will then learn how to add new functionality to your widget using the JavaScript editor, debugger, and the runtime expression evaluator. Every widget developer will enjoy this in-depth exploration of Dashcode's capabilities.
Speakers: Max Drukman, Mike Kahl, Han-Ming Ong, Dan Gobera
Unlisted on Apple Developer site
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Good afternoon and welcome to Unlocking the Potential of Dashcode. I'm Phil Schuler. And before we get going, I have just a couple of questions. Just a show of hands, how many out there had a chance to download and get their hands on the Dashcode beta for Tiger? Oh, that's good. And how many of you have had a chance to mess around with Dashcode in the Leopard beta you've had for a couple of days? Oh, some people have had some quality laptop time I see.
So, what do we mean when we say unlocking the potential of Dashcode? What we mean is making customization pay off. So, taking custom art, a little bit of custom code, and in fact a surprisingly small amount of it, and turning a template into a unique expression of your brand and what it is you want to accomplish in your widget.
But then also we're talking about some very powerful features in Dashcode. The debugger for instance which you may have seen if you've seen some other sessions here. We're gonna show you a little bit more and how it's not just for debugging. We're also going to show you some glitz and glamour techniques, how you can make some widgets that are fun and easy to use. And we're going to show you the Dashcode localization workflow which is so easy to use we're betting you're going to want to localize all of your widgets from now on.
So I'm going to get things going with a very easy little demonstration just to get our brains up and running a little bit after lunch. What I'm going to do is I am going to take an RSS template, I'm going to make a new widget and I'm going to turn it into a widget that feeds up two different feeds.
Pretty simple. Now, how am I going to do that? I'm going to brand the widget. I work for a little company called Apple and I'm going to use Apple feeds and I'm going to use Apple artwork to make it look like it's a widget that maybe even Steve would approve of, although I wouldn't bet on that. I'm going to add parts from the Dashcode library to extend the UI and that's very simple. I'll show you how to do that. Just a tiny bit of coding which is all you want me to do because I'm no Java script expert.
But that's good because I'm going to show you how easy it is to do, even for me. I'm going to run the widget in Dashcode and we're all going to burst into spontaneous applause when we see that I've done what I said I was going to do. Let's go to the demo machine.
Before we launch into Dashcode I just wanted to show you what it is we're dealing with content wise. So there are two feeds in particular that I'm interested in from Apple. The iTunes Top 10 Songs, which is what you see before you, and the Top 10's Album feed.
Now as to look and feel, maybe some of you are familiar with this look. It just happens to be plastered all over the world. So that's basically the look I'm going for and I'm going to use these two feeds. So, let's get going. I'm going to launch Dashcode and pick the RSS template. Easy as that, I'm up and running.
And just so we can see what it is I'm doing, I'll make this nice and big, kind of bigger than you'd want a widget to be, but just sort of big enough so that we can get a feel for it. Now, like so many templates, the RSS template allows you to just drop a URL onto it to set the feed source. So that's how I'm going to get going. I'm going to take the top ten songs feed, I'm just going to grab it out of Safari and drop it onto my widget.
If I rename this... iTunes Top Ten Songs, that's pretty much it. If I want to ship a stock looking widget with one feed, I'm practically done, but that's not what you came here to see, so we're going to go in and do a little customization. Now, as I said, I want to customize the look. And I'm a UI guy so I like to work from the outside in and get the interface right first before I do a code. Dashcode allows you to work both ways. It doesn't really matter. I just prefer to work this way.
So, I know I want the look to change. So this header and footer really aren't of much use to me. I'm just going to get rid of them. And what I'm going to replace them with is a little bit of art that I did in Photoshop. So if you have a little bit of Photoshop skills or know somebody who does, easy enough to do. I'm just going to drag both of these pieces of art in and place them where I want them.
So you can see that I used the theme from the iTunes commercial to get a particular look and that's pretty much it. So it's obscured some other content on my widget. All I need to do is grab those two elements, and I can do that over here in the navigator, and I'm going to drag them underneath.
So now I've branded my widget. It's an expression of my brand. Steve's brand. Sorry. So again, if I just wanted to ship a single feed widget that had my brand in it, I'm just about done, but you didn't come to see that either. You may not have come to see any of this, but, I'm going to show you something anyway.
What I want to do is allow the users of my widget to switch the feed. So right now they're seeing songs if they just ran this widget, so I want to give them an affordance to switch to the albums feed. So they're going to need a button to click on.
And the way I can add that is just bring up the library in Dashcode, in the parts tab, which is coming soon, we have a whole lot of parts that you can add to your widget to extend the interface. They're really easy to work with and provide a lot of functionality. I want to add a button. In fact, I want to grab this one, the lozenge button.
All I need to do is drag it onto my widget and there, it's in place. Size it a little bit... Rename it. So now it's an albums button. It's kind of sticking out like a sore thumb. So I can style it a little bit. Bring up the Inspector and in the fill and stroke Inspector, right here, I can do things like change it to a gradient, I can add some glass to it, some fairly common things.
I'm going to make these little semi-transparent which is a nice little design trick to make it look like it's sort of built of the same stuff of the thing that it's on top of. And so now I've got a button, great! What does it do? Nothing. I haven't wired it up yet. But that's easy enough to do too.
And the way I do that is in the Inspector again. I can select the albums button, bring up the Inspector, and go to the last tab, the Behaviors tab. Now the Behaviors tab lets me wire up all of the events that this object listens to, to handlers in my code. So all I need to do is double click in the Handlers and I can start typing. And you can see it autocompletes for me. So if I already have a function written, I can just wire it up very simply like this.
But I want to actually create a new handler so all I need to do is type in a new handler name. Now what just happened? Well, Dashcode created a new function for me. It took the name I gave it and made a new function, stubbed it in, opened the code to show me where it was putting it and left me a little place to insert my code.
Now, like I said, I'm not much of a coder and you sure don't want to watch me mistype this again and again. So I'm going to show you another nice bit of functionality in the library, and that's the Code Snippets Library. Dashcode comes with a whole bunch of code snippets that help you out with some pretty common things that you want to do in Java script.
It also allows you to save your own. That's what I did. I prepared these snippets a while ago and I just saved them back into the library. So now I can reuse them by dragging them back. So I'm just gonna drag this back and let's see what we have here.
I'm now setting the feed source which I should tell you why I'm setting it that. How about this for a demo? Now, why am I calling Set Feed Source? Well, I happen to know how this widget works. But I'm gonna show you how you might understand it too.
So I'm going to go up to the search field and type feed, because we're dealing with feeds, right? So, the search field in Dashcode lets me search throughout my widget project to find elements, code, styles, all kinds of things that I can use. and you'll see that when I search for feed, it found objects, events, functions, styles, end files and even the line numbers where these surfer results appeared. And here's the one I've already blown my cool reveal of, Set Feed Source. That's the one that I need to wire up to.
And that's exactly what I'm doing. So let me go back to my function and we can see that what I'm doing is I'm calling Set Feed Source. So I'm passing it in the URL of the albums feed instead of the songs feed. And I know that because it says Top Albums right there.
And then I'm doing a refresh feed so that I know that the content is up to date. There's one more thing I need to do and that is the title of this widget is Top Ten Songs so I know that when the user switches to albums I need to switch the title of the widget too. And that's easy enough to do. I also have a code snippet for that. And what I'm doing here is I'm using our old friend Get Element by ID, the Feed Title.
And that element, the Feed Title, is this element and I know that again because I can look in the Navigator and see that that's its name. And I'm setting its inner HTML, in other words, the text inside of it, to be Top Ten Albums. So, hey, I'm pretty close to being done. I now have a widget that gets the songs feed and lets the user switch the albums feed.
But they may want to switch back. Darn users! So, I can do that just like I did before. I want to work from the UI in again. So all I'm going to do now is I'm just going to duplicate this button, Command D, and let's rename this to Songs.
Now it's still wired up to the albums feed handler and I don't want that so I want to wire this up to another one, Songs Feed. So, again, just like with Albums Feed, Dashcode made anew function for me and took me there in the code view and all I need to do is add some code, which, again I'm not going to make you watch me type. And this will look pretty familiar to you by now. I'm setting the Feed Source, this time to songs. I'm refreshing the feed, and I'm setting the Feed Title too. So now, if the demo gods are with me, I will have a working widget.
Let's see if I'm wrong. Here it is loading. We've got songs! We're almost there. Top Ten Songs and Top Ten Albums! There! All right! Can we go back to slides please? Okay, well, what'd you just learn? I'm not the best demoer in the world. But, you learned that custom art pays off, right? So a little bit of art goes a long way. What you want to do with your widgets is express your brand to your users so they know it's your widget and they know to go to you for more widgets in the future.
Parts make customization very easy. You saw how easy it was to just drag a button out, style it, wire it up. Boom! I'm done. And clicking buttons is a lot of fun. So, we're not going to stop there though because that was a fairly lame demo. What we're going to do now is we're going to show you so more in-depth stuff.
We're going to write our own code from scratch. We're going to interact with feeds but not just RSS feeds because RSS is pretty prevalent out there but there's a lot of other data out there that you might need to work with. We're going to show you how to interact with those feeds and learn how they work so that you can parse them in your widget and extract the data out of them.
We're also going to take this project and we're going to iterate through the design steps. So we're going to start out with something very simple and we're going to move along until we get something that's fairly fun. And we're going to show you, of course, how Dashcode makes that easy. Here's the set up. When my stock portfolio is up I'm happy.
My mood is good. When my stock portfolio is down, my mood is bad. So, you know, it doesn't get a lot simpler than that. So I thought well, what would be a good way to express that? Well, what came to mind immediately is the glass is half full or it isn't half full. But that's what I want. I want a widget that looks at my stock portfolio, figures out how I'm doing and then tells me what my mood is.
It's either half full or half empty. Now, as I told you, I'm not much of a coder, so what I did, I did the sensible thing and that is I got one of my engineer friends to help me with it. And to tell you all about that is Mike Kahl, engineer extraordinaire and master of the Dashcode debugger. Mike!
Thanks Max.
My name's Mike Kahl and I work on the Dashcode JavaScript debugger which I'll be showing you in a few minutes. Max has asked me to help us get started on this money mood widget which is going to display our mood based on how our stock portfolio is doing.
Now, I'm not much of a UI guy. I'm here to do the behind the scenes work of this widget, so we're just going to use that graphic of a glass that we got from Max and if our stocks are doing well the glass will seem half full and if our stocks are doing poorly then glass will seem half empty. So, let's get started.
This widget follows a common design pattern for widgets. We go out to the Web, we request some data, the data arrives and we load it up into our widget. Now for this widget, the data is available from a feed provided by Yahoo Finance. You tell it which stocks you're interested in and it gives you the information about that stock.
And the JavaScript object that we're going to use to retrieve that data is called XML HTTP Request. As the name implies, XML HTTP Request is usually used to fetch data that is in XML format. But that's not required. It can fetch data that's in any format. And this particular data is not in XML format. So we're going to have to figure out how to parse it ourselves. Then we'll process the data, crunch it down to just one number representing our mood and finally, we'll present some initially simple UI to display the result. Okay, let's write some code.
We begin by creating our XML HTTP Request object. Ultimately, we're going to send that object out onto the Web to retrieve our data. First we have to tell it where to go to find the data and we're going to disable caching because we don't want stale data, we want up to the minute data or, in the case of stocks, up to the twenty minute delay data.
Now, there's one more thing we have to do. When we request this data, it's going to take a few milliseconds for it to arrive and even though that's not a long time from a programming point of view, that's an asynchronous event so we have to specify a call back function.
And this function will be called to notify us when the data arrives. Our call back function just checks that the request completed successfully and calls another function, Data Ready, which looks something like this. Remember our three P's - Parse, Process, Present? We're going to parse the feed, process the data and present the results. Now, we haven't seen this data yet.
So we don't know exactly how to write a parsing code. But a good goal would be to create an array of stocks with one entry with information about each stock in our portfolio and then we can pass that array to a function to calculate our mood. And once we've got our mood as a number, we can call another function to display the UI.
All right. So we're ready to run this code even though we haven't finished writing it. It would be a good idea to test what we have so far and also, more importantly, we're going to use Dashcode's debugger to inspect this feed live and experiment and figure out how to write the parsing code. So, let's go to the demo.
Okay, so here's our widget. I've already done a little bit of work on it. I've incorporated the graphic of a glass that I got from Max and I typed in this code that we just saw in the slides. I took the XML HTTP Request set up code and I wrapped it in a function called Request Data, and down here is our Data Ready function.
So, there's a few things that we do have to do before we're ready to run this code. First of all, this is obviously not the real URL, so let's get rid of that and I'm going to drag in the code to construct the real URL as a function of which stocks are in our portfolio. Now, where is that coming from? How does the widget know which stocks are in our portfolio? Well, ultimately, this widget will have a back and we'll be able to configure our portfolio of each stock we have.
But, for getting started, let's just hard wire that. So I'm going to drag in some more code. By the way, every time I drag in code just please pretend that I'm a very fast and accurate typist. So we'll start with the initial portfolio with 100 shares of Apple and just five shares of Google because that's all the Google we can afford.
Okay, so we're ready to run the widget. I'm going to set a break point here at the entry to this data ready function so that when the data arrives we can take a look, and click run. Up comes the widget and nothing happens. What did we do wrong? Well, we did forget to do one thing. We never actually called that request data function that we wrote. So we never asked for the data, no data arrived. We could stop the widget, insert that code, start over, but we don't have to.
We can use Dashcode's evaluator which is a live JavaScript console. Allows us to type in anything in JavaScript and have it evaluated so we can do it on the fly. And, just in that fraction of a second, it went out to the Web, it requested the data, the data came back and we hit our break point. So now the widget is paused at this break point.
Here's the line of code that's about to be executed. Up here we have the local variables that are visible in this frame and their values. We can single step and a value got assigned to this variable called data. And that's our feed. So let's take a closer look at that. We'll go back to the Evaluator.
Now what we need to do here is figure out how to take this big long string and extract from it the information that we need in order to calculate our mood. So, it looks like we've got multiple lines in that string, one line for each stock that we requested.
So the first step would be to split it up into lines and I'm going to use carriage return, new line, as a separator because I noticed that these lines actually end in a carriage return as well as a new line. And that gives us an array of three elements. Well, why three elements? There are only two stocks. Well, let's take a look. The first element is the first line.
The second element is the second line. Well, what's the third element? It's the empty string. Why do we have an empty string? Well, that empty string is the one that follows the final carriage return new line in our original string. So it's an artifact of the way the split function works. But that's okay, we can still use the split function but we just need to make a mental note when we write the code, if we see any empty strings we should just ignore them.
Okay, now I want to show you another way we could have done what we just did. Instead of looking at each element that we write individually, we could have created a local variable on the fly here in the Evaluator, to hold that array. Now, as I enter this, watch up here with the variables and you'll see a new variable being created.
There it is, it's called lines and it's an array of three elements and we can twist it down and see all the strings at once. All right, so let's move on. Now we need to look inside each line and extract the fields for that stock. And let's use that same technique.
We'll create a variable called fields and we'll use the Apple line and it looks like this data is separated by commas, so this time let's split on comma. And if we look up here, that gave us a new local variable called fields. It's an array of nine elements. We can twist it down and we can see all of the fields.
There's the ticker symbol, the current price, down here is the daily delta, the difference between the current price and yesterday's close. And the other values in this array, we don't really care about for the purpose of this widget. We're just going to concentrate on those three. Now, each of these three fields needs a little bit of massaging before it's really exactly in the format that we want.
For example, this ticker symbol has some extraneous quotes in it that we don't want. So let's see if we can figure out how to get rid of those quotes. Let's try replacing those quotes with the empty string. That'll be our first try. And it doesn't quite work. It only removed the first quote. We need to remove all the quotes. So let's try again.
This time, let's use a regular expression because that gives us the opportunity to specify that we want to replace globally. And that worked. So now, by experimenting in the Evaluator, we have figured out how to write the code that will extract that field. Now let's look at our other two fields.
These are numeric fields. But actually that's not a number, that's a string. And we need it to be a number because we're going to be performing arithmetic on it. So let me share with you a little JavaScript tip. the quickest way to convert a string to a number is to use
( inaudible )
So at this point we have gathered all the information that we need to write the parsing code. Let's stop the widget, go back to our source code and I'm going to drag in the parsing code. Pretend I'm typing! This code is pretty much what we just figured out how to do in the Evaluator. We start by splitting on carriage return and line feed, that gives us an array of lines, we loop to the lines. If a line is an empty string, then we skip it.
We only process the lines that are really there. We split on comma and then for each line we create an object with three properties corresponding to the three fields that we care about. And using those expressions that we figured out in the Evaluator to suitably massage those fields into what we want. Then we accumulate that object into an array of stocks.
Set a break point here following the loop so that we can inspect it and let me get rid of this other break point. And we'll do one more thing before we run the widget. I want to go and insert that call to request data that we left out the first time so that we don't have to simulate it again. I'm going to put it here in the show method.
Click run. Up comes the widget, hits our break point and you can see here we have our local variable, stocks, it's an array of two elements, we can twist it down, we can inspect the contents and everything looks right. No extraneous quotes. The numbers are numbers, we did it right. So the only thing that's left is to write these functions, calculate mood, and display mood. I've already written them, let me drag them in and show you what they do. It's very simple.
Calculate mood is just doing some arithmetic. It computes the total value of our portfolio both now and as of close yesterday and returns a number representing the percentage change. And if that was a positive number, that means that the value of our portfolio increased and so the glass is half full, otherwise the glass is half empty. So let's remove this break point and test our widget. There it goes. The glass is half empty. Now I'm in a bad mood.
So, for testing purposes, we'd like to see the glass be half full. So how can we do that? Remember I said there was going to be a back to this widget where you can configure your portfolio? Well, while you weren't looking I actually implemented that. So here it is and let's try some different stocks. Let's get rid of that loser Apple stock. What if we invested instead in Adobe? Wow! That's not enough. Maybe we have to invest in more Adobe. I don't know. Didn't Adobe go up today? Now the glass will be half full.
So back to slides. So we've seen how to implement a common widget design pattern. We used XML HTTP Request to go out onto the Web, ask for some data, when the data arrives, we load it up into our widget following the three P's. We've also seen some of the features of Dashcode's JavaScript debugger.
The debugger is not just good for tracking down bugs, it also has some tools that will help you to figure out how to write your code correctly in the first place. Well, now that we've got our widget working, the next step is going to be to improve the UI. So for that, I'd like to introduce my colleague Hau Mingh Ohm, take it away Hau Mingh.
Hi there. My name is Hau Mingh Ohm, same old Dashcode engineer from last year's session. Now we've seen how a widget developer like Mike could make use of Dashcode's incredibly powerful debugging environment to write a widget with robust functionality. But you and I know for your users to want to crave for your widget, it's going to have to possess.
So in this part of the session, we're going to see how you can make use of Dashcode to add some of the glamour to your widget. And using Dashcode, it is simple to go the extra amount. The big piece of the puzzle to jazz up your UI is this wonderful parts technology that we're putting into Dashcode. We're going to make use of one of them in the demo.
Let's have a look at Version 2.0 of the UI. So, instead of showing that the glass is half full when the mood is good, we're going to show a huge smiley when you're happy. So to do that we're going to make use of this symbol part from the library. This is the symbol indicator part. Now if you go to the library there are other kind of parts like the guage part which is the indicator part but it has a range associated with it. This is the simple one.
The concept behind this one is pretty easy. You have one value you are monitoring. And when that value which is set at a point, you want to show the user, visually, that you have reached a state. And there's four states and you use this API, set value, to change the state by setting it to a new value.
Let's go to the demo machine please. Okay. This is the widget that you saw earlier on. Since I'm going to change the UI, I'll start by deleting the glass image text and the front image. And then I'm going to set it to be 500 pixels by 500 pixels . The next thing I'm going to do, I'm going to drag in the indicator part that I talked about earlier on. There you go. I'm just going to eyeball it to the size that I want.
Okay. Now if you go to the attributes inspector pane, here is where we check out the indicator part or other parts that you drag in. Let's take a look at the images. I know some of you out there actually make use of this for default traffic light images as the UI for your widget. Now if it looks right for your widget, that's fine. Obviously we're going to change them to smileys so let's start doing that. First, we're going to drag into our widget project and once it's there, I'm going to make use of the first state to be the downloading state.
And the second state to be the indifferent state, the fourth one to be the angry state and the fifth one to be the static state when you're really, really happy. And if you flip over to the values tab you will see the four values that correspond to these four states. We're going to make use of them in the code. Now usually while in the front, you do want to take care of your info button. You can make it visible.
It's always fun and challenging to put where your info button is. Here I want to make it into a nose. Now we are ready to call up the UI. Let's go to the file that you saw earlier on. And I'm going to drag in my own code snippets.
So these are the three values that define the state. Zero being the default so we don't have to define it. Go to the function that we saw earlier on. Again, we want to delete this since we're changing it. And drag in my own body. This part here just maps the percentage change to the stated value.
So if the stock is less than, went down more than 0.5 percent, half a percent, then we're mad. If it goes up by 0.5 percent we're happy, anything else, we don't care. The second part here, get hold of the indicator object and do something to it. As with other Apple supply classes, when you need to get hold of the object you want to manipulate, get hold of the application right here.
Once you get hold of the indicator, you can set value API. Now, for other parts, if you want to know what other API you can use, you can read the documentation but probably most of you wouldn't, so here's a trick. Go to the code library, just search the part that you want. In this case, for example, indicator. And often times you'll find something that probably was so unique, set indicator value, and there you go, set value.
Okay, so we are ready to run it. Let's test it! It's thinking. Okay, I know what it is going to be, mad, so but you probably ? most of you probably don't invest in this company, but some of you might. So let's buy a boat load of it. So I guess Bill is pretty happy today. All right. Let's go back to the slides please. Thank you.
Okay, what you've just learned is that even after you have come up with the basic functionality of the widget using Dashcode, it is not difficult to change the UI and experiment a little bit with it. And check out the parts library to see if that's anything that can help you with your UI. Don't forget that you can actually customize the parts itself by using inspector panes.
Okay, there are other ways to make your widgets even more visually appealing. For example, you can use core graphics operations on the canvas object. Other ways to take advantage of the cool Apple technology known as Quartz composition. We're going to take a QC which is modifiable via JavaScript and then use the Apple Animator to feed values directly to the QC. Again, let's have a look at Version 3.0 of the UI. Same basic functionality but we're not happy with the smilies anymore, we want to have a wheel of fortune to tell us our mood. And this wheel of fortune is the QC.
The thing about a QC is if you're a QC designer, you can expose certain parameters in the QC by publishing them so that it can be modified by using JavaScript. Now this is actually a very powerful concept that bridges between JavaScript and quartz composition. The way they do it is pretty straight forward. Use the regular get element by the API. Once you get hold of the element, use the set value API. Here we're assuming that the published parameter is called property.
Okay, for those not familiar with the Apple animator class, here is a review. Now, as the new cliche goes, an animation is worth more than ten thousand words. So I'm going to use an animation to explain it. The Apple animator takes the duration of the animation, maps it to a range of value, start and you the widget developer, provides a function handler so that at each interval of the animation, the animator will call you back. And when it calls you back it gives you a new value that is dependent on where the animator is and that is visible along the range of values.
In API form, here's the API with the parameters reflecting the five concepts that we talked about. Now, Apple animator does the heavy lifting of driving the animation but you get to decide how the animation should happen. So for our case, the new value represents the degree of the wheel to turn to so we just feed it directly to the QC. Demo time, okay.
So let's look at the previous widget. Okay, we're going to start by deleting dedicator because we don't need it. And let's drag in the wheel of fortune. First thing we want to do is, for our case, set it to transparent and let it show below all the drawn elements. Again, eyeballing to resize it.
Okay. Let's take care of the info button again. Because spinning the wheel is so much fun I'm going to spin it manually. So here I'm going to use a button to do that. So let's drag it in. And let's quickly harmonize the color by going to the even stroke and making it gradient, choosing a few choice colors. Give it a stroke. And I'm going to call it spin the wheel.
Here we go. And let's make the type bigger so they can see it. All right, we're all set. But you've seen how we have to hook up the function for the unclick event. And you've seen this function before, it's request data, so I'm just going to type it in. All right, at this point we are now ready to hook up the new UI. Let's do that.
So we don't need this anymore, steal it back. Let's go to Version 3 of our code snippets. These are the values that my QC designer told me that correspond to the segment of the wheel that I want to turn to. And let's go to display mode. I'm going to keep this chunk of code, okay, because it's still useful. All I need to do is delete this and drag in our create animation code.
This is the important one, the animation handler. So here we get a new value and set it to the rotation as I mentioned earlier on. Now, make sure that a QC has actually exposed rotation as the published parameter. Here's the trick. You select the QC, put it in Inspector, attributes pane, hit the added parameters button and you'll see that rotation is there. Okay? Now, let's run it. But I know it's you know, we're not going to be too happy because it's the same. So is there any stock ticker today that will make me happy? Anyone? Intel! Okay, our partner.
INTC? Oh way, first I have to get rid of something here because... All right, let's spin it again. There you go! All right. Okay. Now notice that we went from a binary state of UI like half full/half empty to one with multiple states. So the lesson here is that you should experiment and evolve your UI until you find something that not only pleases you but the one important thing is that your widget users will use it, they will love it. And if you need to add motion graphics to your widget, consider course composition. Apple Animator Plus, when used judiciously, will definitely add more spice to your widget.
And finally to wrap up the rest of the UI, please check your default image and widget icon. Dashcode does a good job in tracking them based on the front slide of the image. But because each widget is different, so just take a look at them and make sure they look right. And because strings and majors are part of UI, you want to make sure that they look good in other languages. Now that's localization.