iPhone SDK vs. Windows Phone 7 Series SDK Challenge, Part 2: MoveMe
In this series, I will be taking sample applications from the iPhone SDK and implementing them on Windows Phone 7 Series. My goal is to do as much of an apples-to-apples comparison as I can. This series will be written to not only compare and contrast how easy or difficult it is to complete tasks on either platform, how many lines of code, etc., but Id also like it to be a way for iPhone developers to either get started on Windows Phone 7 Series development, or for developers in general to learn the platform.
Heres my methodology:
Run the iPhone SDK app in the iPhone Simulator to get a feel for what it does and how it works, without looking at the implementation
Implement the equivalent functionality on Windows Phone 7 Series using Silverlight.
Compare the two implementations based on complexity, functionality, lines of code, number of files, etc.
Add some functionality to the Windows Phone 7 Series app that shows off a way to make the scenario more interesting or leverages an aspect of the platform, or uses a better design pattern to implement the functionality.
You can download Microsoft Visual Studio 2010 Express for Windows Phone CTP here, and the Expression Blend 4 Beta here.
If youre seeing this series for the first time, check out Part 1: Hello World.
A note on methodologyin the prior post there was some feedback about lines of code not being a very good metric for this exercise. I dont really disagree, theres a lot more to this than lines of code but I believe that is a relevant metric, even if its not the ultimate one. And theres no perfect answer here. So I am going to continue to report the number of lines of code that I, as a developer would need to write in these apps as a data point, and Ill leave it up to the reader to determine how that fits in with overall complexity, etc. The first example was so basic that I think it was difficult to talk about in real terms. I think that as these apps get more complex, the subjective differences in concept count and will be more important.
MoveMe
The MoveMe app is the main end-to-end app writing example in the iPhone SDK, called Creating an iPhone Application. This application demonstrates a few concepts, including handling touch input, how to do animations, and how to do some basic transforms.
The behavior of the application is pretty simple.
User touches the button: The button does a throb type animation where it scales up and then back down briefly.
User drags the button: After a touch begins, moving the touch point will drag the button around with the touch.
User lets go of the button: The button animates back to its original position, but does a few small bounces as it reaches its original point, which makes the app fun and gives it an extra bit of interactivity.
Now, how would I write an app that meets this spec for Windows Phone 7 Series, and how hard would it be? Lets find out!
Implementing the UI
Okay, lets build the UI for this application. In the HelloWorld example, we did all the UI design in Visual Studio and/or by hand in XAML.
In this example, were going to use the Expression Blend 4 Beta.
You might be wondering when to use Visual Studio, when to use Blend, and when to do XAML by hand. Different people will have different takes on this, but heres mine:
XAML by hand simple UI that doesnt contain animations, gradients, etc., and or UI that I want to really optimize and craft when I know exactly what I want to do.
Visual Studio Basic UI layout, property setting, data binding, etc.
Blend Any serious design work needs to be done in Blend, including animations, handling states and transitions, styling and templating, editing resources.
As in Part 1, go ahead and fire up Visual Studio 2010 Express for Windows Phone (yes, soon it will take longer to say the name of our products than to start them up!), and create a new Windows Phone Application. As in Part 1, clear out the XAML from the designer. An easy way to do this is to just:
Click on the design surface
Hit Control+A
Hit Delete
Theres a little bit left over (the Grid.RowDefinitions element), just go ahead and delete that element so were starting with a clean state of only one outer Grid element.
To use Blend, we need to save this project. See, when you create a project with Visual Studio Express, it doesnt commit it to the disk (well, in a place where you can find it, at least) until you actually save the project. This is handy if youre doing some fooling around, because it doesnt clutter your disk with WindowsPhoneApplication23-like directories. But its also kind of dangerous, since when you close VS, if you dont save the projectits all gone. Yes, this has bitten me since I was saving files and didnt remember that, so be careful to save the project/solution via Save All, at least once.
So, save and note the location on disk.
Start Expression Blend 4 Beta, and chose File > Open Project/Solution, and load your project. You should see just about the same thing you saw over in VS: a blank, black designer surface.
Now, thinking about this application, we dont really need a button, even though it looks like one. We never click it. So were just going to create a visual and use that. This is also true in the iPhone example above, where the visual is actually not a button either but a jpg image with a nice gradient and round edges. Well do something simple here that looks pretty good.
In Blend, look in the tool pane on the left for the icon that looks like the below (the highlighted one on the left), and hold it down to get the popout menu, and choose Border:
Okay, now draw out a box in the middle of the design surface of about 300x100. The Properties Pane to the left should show the properties for this item.
First, lets make it more visible by giving it a border brush. Set the BorderBrush to white by clicking BorderBrush and dragging the color selector all the way to the upper right in the palette. Then, down a bit farther, make the BorderThickness 4 all the way around, and the CornerRadius set to 6.
In the Layout section, do the following to Width, Height, Horizontal and Vertical Alignment, and Margin (all 4 margin values):
Youll see the outline now is in the middle of the design surface.
Now lets give it a background color. Above BorderBrush select Background, and click the third tab over: Gradient Brush. Youll see a gradient slider at the bottom, and if you click the markers, you can edit the gradient stops individually (or add more). In this case, you can select something you like, but wheres what I chose:
Left stop: #BFACCFE2 (I just picked a spot on the palette and set opacity to 75%, no magic here, feel free to fiddle these or just enter these numbers into the hex area and be done with it)
Right stop: #FF3E738F
Okay, looks pretty good. Finally set the name of the element in the Name field at the top of the Properties pane to welcome.
Now lets add some text. Just hit T and itll select the TextBlock tool automatically:
Now draw out some are inside our welcome visual and type Welcome!, then click on the design surface (to exit text entry mode) and hit V to go back into selection mode (or the top item in the tool pane that looks like a mouse pointer).
Click on the text again to select it in the tool pane.
Just like the border, we want to center this. So set HorizontalAlignment and VerticalAlignment to Center, and clear the Margins:
Thats it for the UI. Heres how it looks, on the design surface:
Not bad! Okay, now the fun part
Adding Animations
Using Blend to build animations is a lot of fun, and its easy. In XAML, I can not only declare elements and visuals, but also I can declare animations that will affect those visuals. These are called Storyboards.
To recap, well be doing two animations:
The throb animation when the element is touched
The center animation when the element is released after being dragged.
The throb animation is just a scale transform, so well do that first.
In the Objects and Timeline Pane (left side, bottom half), click the little + icon to add a new Storyboard called touchStoryboard:
The timeline view will appear. In there, click a bit to the right of 0 to create a keyframe at .2 seconds:
Now, click on our welcome element (the Border, not the TextBlock in it), and scroll to the bottom of the Properties Pane. Open up Transform, click the third tab ("Scale), and set X and Y to 1.2:
This all of this says that, at .2 seconds, I want the X and Y size of this element to scale to 1.2.
In fact you can see this happen. Push the Play arrow in the timeline view, and youll see the animation run!
Lets make two tweaks. First, we want the animation to automatically reverse so it scales up then back down nicely.
Click in the dropdown that says touchStoryboard in Objects and Timeline, then in the Properties pane check Auto Reverse:
Now run it again, and youll see it go both ways. Lets even make it nicer by adding an easing function.
First, click on the Render Transform item in the Objects tree, then, in the Property Pane, youll see a bunch of easing functions to choose from. Feel free to play with this, then seeing how each runs. I chose Circle In, but some other ones are fun. Try them out! Elastic In is kind of fun, but well stick with Circle In.
Thats it for that animation.
Now, we also want an animation to move the Border back to its original position when the user ends the touch gesture. This is exactly the same process as above, but just targeting a different transform property.
Create a new animation called releaseStoryboard
Select a timeline point at 1.2 seconds.
Click on the welcome Border element again
Scroll to the Transforms panel at the bottom of the Properties Pane
Choose the first tab (Translate), which may already be selected
Set both X and Y values to 0.0 (we do this just to make the values stick, because the value is already 0 and we need Blend to know we want to save that value)
Click on RenderTransform in the Objects tree
In the properties pane, choose Bounce Out
Set Bounces to 6, and Bounciness to 4 (feel free to play with these as well)
Okay, were done.
Note, if you want to test this Storyboard, you have to do something a little tricky because the final value is the same as the initial value, so playing it does nothing. If you want to play with it, do the following:
Next to the selection dropdown, hit the little "x (Close Storyboard)
Go to the Translate Transform value for welcome
Set X,Y to 50, 200, respectively (or whatever)
Select releaseStoryboard again from the dropdown
Hit play, see it run
Go into the object tree and select RenderTransform to change the easing function.
When youre done, hit the Close Storyboard x again and set the values in Transform/Translate back to 0
Wiring Up the Animations
Okay, now go back to Visual Studio. Youll get a prompt due to the modification of MainPage.xaml. Hit Yes.
In the designer, click on the welcome Border element. In the Property Browser, hit the Events button, then double click each of ManipulationStarted, ManipulationDelta, ManipulationCompleted. Youll need to flip back to the designer from code, after each double click.
Its code time. Here we go.
Here, three event handlers have been created for us:
welcome_ManipulationStarted: This will execute when a manipulation begins. Think of it as MouseDown.
welcome_ManipulationDelta: This executes each time a manipulation changes. Think MouseMove.
welcome_ManipulationCompleted: This will execute when the manipulation ends. Think MouseUp.
Now, in ManipuliationStarted, we want to kick off the throb animation that we called touchAnimation. Thats easy:
1: private void welcome_ManipulationStarted(object sender, ManipulationStartedEventArgs e) 2: { 3: touchStoryboard.Begin(); 4: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Likewise, when the manipulation completes, we want to re-center the welcome visual with our bounce animation:
1: private void welcome_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) 2: { 3: releaseStoryboard.Begin(); 4: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Note there is actually a way to kick off these animations from Blend directly via something called Triggers, but I think its clearer to show whats going on like this. A Trigger basically allows you to say When this event fires, trigger this Storyboard, so its the exact same logical process as above, but without the code.
But how do we get the object to move? Well, for that we really dont want an animation because we want it to respond immediately to user input.
We do this by directly modifying the transform to match the offset for the manipulation, and then well let the animation bring it back to zero when the manipulation completes. The manipulation events do a great job of keeping track of all the stuff that you usually had to do yourself when doing drags: where you started from, how far youve moved, etc.
So we can easily modify the position as below:
1: private void welcome_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) 2: { 3: CompositeTransform transform = (CompositeTransform)welcome.RenderTransform; 4: 5: transform.TranslateX = e.CumulativeManipulation.Translation.X; 6: transform.TranslateY = e.CumulativeManipulation.Translation.Y; 7: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
Thats it!
Go ahead and run the app in the emulator. I suggest running without the debugger, its a little faster (CTRL+F5). If youve got a machine that supports DirectX 10, youll see nice smooth GPU accelerated graphics, which also what it looks like on the phone, running at about 60 frames per second. If your machine does not support DX10 (like the laptop Im writing this on!), it wont be quite a smooth so youll have to take my word for it!
Comparing Against the iPhone
This is an example where the flexibility and power of XAML meets the tooling of Visual Studio and Blend, and the whole experience really shines.
So, for several things that are declarative and 100% toolable with the Windows Phone 7 Series, this example does them with code on the iPhone. In parens is the lines of code that I count to do these operations.
PlacardView.m: 19 total LOC
Creating the view that hosts the button-like image and the text
Drawing the image that is the background of the button
Drawing the Welcome text over the image (I think you could technically do this step and/or the prior one using Interface Builder)
MoveMeView.m: 63 total LOC
Constructing and running the scale (throb) animation (25)
Constructing the path describing the animation back to center plus bounce effect (38)
Beyond the code count, yy experience with doing this kind of thing in code is that its VERY time intensive. When I was a developer back on Windows Forms, doing GDI+ drawing, we did this stuff a lot, and it took forever! You write some code and even once you get it basically working, you see its not quite right, you go back, tweak the interval, or the math a bit, run it again, etc. You can take a look at the iPhone code here to judge for yourself. Scroll down to animatePlacardViewToCenter toward the bottom. I dont think this code is terribly complicated, but its not what Id call simple and its not at all simple to get right.
And then theres a few other lines of code running around for setting up the ViewController and the Views, about 15 lines between MoveMeAppDelegate, PlacardView, and MoveMeView, plus the assorted decls in the h files.
Adding those up, I conservatively get something like 100 lines of code (19+63+15+decls) on iPhone that I have to write, by hand, to make this project work.
The lines of code that I wrote in the examples above is 5 lines of code on Windows Phone 7 Series.
In terms of incremental concept counts beyond the HelloWorld app, heres a shot at that:
iPhone:
Drawing Images
Drawing Text
Handling touch events
Creating animations
Scaling animations
Building a path and animating along that
Windows Phone 7 Series:
Laying out UI in Blend
Creating & testing basic animations in Blend
Handling touch events
Invoking animations from code
This was actually the first example I tried converting, even before I did the HelloWorld, and I was pretty surprised. Some of this is luck that this app happens to match up with the Windows Phone 7 Series platform just perfectly. In terms of time, I wrote the above application, from scratch, in about 10 minutes. I dont know how long it would take a very skilled iPhone developer to write MoveMe on that iPhone from scratch, but if I was to write it on Silverlight in the same way (e.g. all via code), I think it would likely take me at least an hour or two to get it all working right, maybe more if I ended up picking the wrong strategy or couldnt get the math right, etc.
Making Some Tweaks
Silverlight contains a feature called Projections to do a variety of 3D-like effects with a 2D surface.
So lets play with that a bit.
Go back to Blend and select the welcome Border in the object tree. In its properties, scroll down to the bottom, open Transform, and see Projection at the bottom. Set X,Y,Z to 90. Youll see the element kind of disappear, replaced by a thin blue line.
Now
Create a new animation called startupStoryboard.
Set its key time to .5 seconds in the timeline view
Set the projection values above to 0 for X, Y, and Z.
Save
Go back to Visual Studio, and in the constructor, add the following bold code (lines 7-9 to the constructor:
1: public MainPage() 2: { 3: InitializeComponent(); 4: 5: SupportedOrientations = SupportedPageOrientation.Portrait; 6: 7: this.Loaded += (s, e) => 8: { 9: startupStoryboard.Begin(); 10: }; 11: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
If the code above looks funny, its using something called a lambda in C#, which is an inline anonymous method. Its just a handy shorthand for creating a handler like the manipulation ones above.
So with this youll get a nice 3D looking fly in effect when the app starts up. Here it is, in flight:
Pretty cool!Did you know that DotNetSlackers also publishes .net articles written by top known .net Authors? We already have over 80 articles in several categories including Silverlight. Take a look: here.