Showing posts with label iphone. Show all posts
Showing posts with label iphone. Show all posts

Thursday, 3 January 2013

Localizing iOS6 Storyboards with MonoTouch

Localization and internationalization of XIB and Storyboard files has historically been a very manual process. Typically these file types would be duplicated in each 'language directory' (*.lproj) and then the text and layout tweaked independently by each translator. Changes to the actual Storyboard or XIBs would need to be manually propagated across all the 'language copies'.

In iOS6 Apple introduced a new concept - Base Localization - which you can read about in their documentation on Internationalizing Your App. Your project can contain a 'special' Base.lproj directory where the Storyboard files are located, and then a corresponding *.strings file (whose filename matches the Storyboard's) in each language directory with the translations.

There is a small sample showing how this works with MonoTouch - TaskyL10nStoryboard on github. There is no IDE support currently, but you can easily create the Base.lproj directory manually in MonoDevelop and everything works as expected. Here's a screenshot of the project structure:

then inside the Storyboard itself you need to identify the controls you wish to localize. Click on a control to discover its Object ID, and shown in this screenshot:

Using the Object IDs from the Storyboard file, we can translate the display values for various properties (including text, placeholders and others) in the MainStoryboard.strings file in each language directory, like this:
"SXg-TT-IwM.placeholder" = "nombre de la tarea";
"Pqa-aa-ury.placeholder"= "otra información de tarea";
"zwR-D9-hM1.text" = "Detalles de la tarea";
"bAM-2j-Rzw.text" = "Notas";
"NF3-h8-xmR.text" = "Completo";
"MWt-Ya-pMf.normalTitle" = "Guardar";
"IGr-pR-05L.normalTitle" = "Eliminar";
Using the Object ID and property as the localization key is quite different to Apple's previous guidance on localization, where the key is typically the base-language's actual displayable value.

Here's the localized Storyboard, in Japanese:


What about layout?
Strings can often be very different lengths in different languages. When you used a different Storyboard or XIB for each language then the control sizes could be manually adjusted to fit. When using Base Localization you should use Apple's new constraint-based layout to handle these size differences.

What about iOS5 and earlier?
This method only works on iOS6. To localize text on earlier versions of iOS you will have to duplicate your Storyboards and XIBs for each language, or create outlets for all the controls and set their localized text values in code using NSBundle.MainBundle.LocalizedString().
There is another localized sample - TaskyL10n - which shows how to localize text elements directly and uses MonoTouch.Dialog.

Sunday, 23 September 2012

iOS 6 UIRefreshControl with MonoTouch

Another cute little new feature of iOS 6 is the built-in pull-to-refresh control - UIRefreshControl. It is really simple to wire up with Xamarin on a regular UITableViewController or with MonoTouch.Dialog.

In case you're unfamiliar with it, this is how the new control looks:

To implement:

  • Assign the RefreshControl property of a UITableViewController to a new instance of the control, eg. RefreshControl = new UIRefreshControl();
  • Create a handler for the control's ValueChanged event, eg RefreshControl.ValueChanged += HandleValueChanged;. In this handler your code will do whatever is required to refresh the data when the user pulls down enough to trigger the event.
  • In HandleValueChanged code, once you have refreshed the table, call the EndRefreshing method of the control to stop it spinning. Your refresh code was probably not running on the main thread, in which case you'll probably want to use InvokeOnMainThread like this: InvokeOnMainThread (() => {RefreshControl.EndRefreshing (); });

There are additional features you may use:

  • BeginRefreshing - call this method from your code if you start a refresh operation from code (eg. on a timer or in response to some other event). This sets the UI of the control to indicate there is already a refresh in progress.
  • Refreshing - whether there is already a refresh in progress.
  • AttributedTitle - optional text that appears under the refresh control.
  • TintColor - customize the appearance of the control to match your application's theme.

Refer to Apple's UIRefreshControl doc for additional info.

UPDATE: What about iOS 5?

This above example will not work on earlier versions of iOS - the UIRefreshControl class does not exist, nor does the RefreshControl property on UITableViewController. To get around this problem, the following code does a system check and falls back to an old-fashioned navbarbutton in earlier versions of iOS:

if (UIDevice.CurrentDevice.CheckSystemVersion (6,0)) {
    // UIRefreshControl iOS6
    RefreshControl = new UIRefreshControl();
    RefreshControl.ValueChanged += (sender, e) => { Refresh(); };
} else {
    // old style refresh button
    NavigationItem.SetRightBarButtonItem (new UIBarButtonItem (UIBarButtonSystemItem.Refresh), false);
    NavigationItem.RightBarButtonItem.Clicked += (sender, e) => { Refresh(); };
}

The Refresh method should contain the code that actually gets new data and updates the UITableView. That method should contain a similar if (CheckSystemVersion(6,0)) clause that wraps the call to the RefreshControl.EndRefreshing method on the main thread. Users on older operating systems will see this:

Wednesday, 19 September 2012

iOS 6 released, supported by Xamarin

It would be hard to miss the news that Apple is launching their new iPhone 5 this week, and has also released the final version of iOS 6. What's also great is that Xamarin supports iOS 6 too, on release day! There's already plenty of documentation, using C# with StoreKit, PassKit, EventKit, UIKit changes and more.

Of course there are heaps of little additions as well as those big ones, including a raft of new Core Image Filters to play with. For those working on the next Instagram (isn't everyone ;-), here's a preview of a couple of them:


(Posterize, Bloom, Invert, Perspective and Vortex)

For more information, review the Introduction to CoreImage in iOS 5 and the additional sample code for iOS 6. You might also like Apple's CoreImage Filter Reference.

Monday, 18 July 2011

Xamarin welcomes MonoTouch and MonoDroid "home"

Great news! Xamarin has acquired a "broad, perpetual license" to the MonoTouch and Mono-for-Android work that was done while the dev team was part of Novell (prior to the Attachmate buyout kerfuffle). There's a press release on the Novell website and Miguel posted on his blog too. Congratulations to the Xamarin team!

Check out the product details at:
Start with the iOS Roadmap to find out what's coming up next.

Monospace is going to be great! Have you downloaded the app yet :-) ?

Wednesday, 13 July 2011

"M"osetta Stone II: ViewController → Activity

After my recent posts I received a question asking for tips on porting a MonoTouch app to MonoDroid. I'm going to take a crack at that over a couple of days - with the warning that you probably shouldn't rush out and buy either tool but wait for Xamarin's future Mono-on-iOS and Mono-on-Android products.

The purpose of the original "M"osetta Stone post was to give cross-platform developers a 'head start' with some high-level concepts. This post will look a little closer at a screen from the Monospace11 app: the Speakers list.


This may be a massive oversimplification, but...
if you have
___ in iOS
then you want
___ in Android
to
UIViewControllerActivitysubclass to present a screen/form/page to the user
ViewDidLoad()OnCreate()setup the UI
Add() or AddSubview()SetContentView()use in ViewDidLoad/OnCreate to 'attach' UI to display
ViewWillAppear()OnResume()load/re-load data that might change and bind to UI
UITableViewListViewvisual control that presents a scrolling list
UITableViewSourceAdaptersubclass to broker the display of a data collection to the UI
GetCell()GetView()to build the layout(UI) for each cell/row, including re-using cells/views for performance
RowSelected()ItemClick EventHandlerperform an action when a row is touched
RowsInSectionCounttell the table/list how many rows to cater for

Here's how it looks in a Visual Studio Class Diagram*
* I've greyed out some of the methods not relevant to the discussion - the iOS implementation of the alphabetic index down the right edge doesn't have an Android equivalent, for example

Notes:
  • UITableViewSource has been implemented as an nested class to resemble the iOS pattern of implementing the equivalent Obj-C protocols on the ViewController - this pattern makes no sense in Android so the classes are separate.
  • The MonoTouch example code builds the UI in C# (eg. tableView=new UITableView();AddSubview (tableView);) whereas MonoDroid loads layout XML files SetContentView(Resource.Layout.Speakers);. This can happen in both ViewDidLoad/OnCreate and GetCell/GetView where UI controls must be created and presented to the user.
  • The 'touch event handler' is in a different class: in MonoTouch the TableViewSource handles a touch for a specific row (NSIndexPath); MonoDroid implements the ItemClick EventHandler<ItemEventArgs> on the ListView for a given GetRow(e.Position).
  • Both examples use the constructor (TableViewSource/SpeakersAdapter) of the 'broker' class to pass the actual business object collection for display. This pattern lets the data be filtered/sorted/whatever before being passed in for display.
  • Calling refreshSpeakers() from ViewDidLoad/OnResume is kinda redundant in this example since the list never changes - but in other spots (eg the Favorites screen) you would want to refresh the list each time because it may have changed.

The Code
You can have a look at the MonoTouch code SpeakersViewController.cs and the MonoDroid SpeakersActivity.cs, SpeakersAdapter.cs to see the actual implementation. For MonoDroid you'll also need to check out the layout XML files Speakers.axml and SpeakersItem.axml.

One more thing...
One final piece which takes some getting used to... in MonoTouch this screen is part of a UINavigationController stack and your RowSelected creates a new ViewController object (passing whatever parameters you need) and calls NavigationController.PushViewController(). The ViewController instances in the navigation stack are 'stateful' and it is really easy to pass business objects around as parameters.
In MonoDroid, the ever-present 'back-stack' does not require a specific 'navigation controller' BUT at it's simplest the mechanism is much more primative and involves passing simple type parameters (eg. strings) like this
var intent = new Intent();
intent.SetClass(this, typeof(SpeakerActivity));
intent.PutExtra("Name", speaker.Name);
StartActivity(intent);

There are more sophisticated approaches but it is probably best to keep your parameter-passing to a minimum - this way the Android hardware 'Back' button "just works".

HTH Slava ;-)

Monday, 11 July 2011

MonoDroid v MonoTouch : a comparison

The past few days I've posted MonoDroid and MonoTouch apps for Monospace - and while they aren't perfect examples of the sort of code-sharing and efficiency that's possible with Mono I thought it would be interesting to compare them as the functionality they offer is very similar.

First, these are the high-level code metrics (as calculated by Visual Studio):
Unfortunately I didn't align the namespaces very well. Here's the explanation:

Total lines of code (TLOC)
Mono-for-Android: 802 lines
MonoTouch: 1,420 lines (2,033 - 613 in SQLite)
At first glance, the MonoDroid app 'wins' with just half the code of the MonoTouch version. I've ignored the SQLite library and the MonoTouch.Dialog framework as they aren't "user code", and any non-.cs files (eg XML markup).

Common code
Although difficult to 'see' because I've rushed these codebases into the public domain, there is a bit of 'code re-use' in these apps (ie. it was only written once, and the c# shared across both platforms using the power of Mono :)
ConfXml == MIX10Xml == approx 200 lines of business objects (DTOs mainly) that match the serialized conf.xml format that is the shared data structure for both platforms.
The ConceptDevelopment.Kelvin code is also shared (different sizes in each aren't relevant for now).

Removing the common code from the comparison results in these totals:
Mono-for-Android: 575 lines (802-199-28)
MonoTouch: 1,145 lines (1,420-178-97)

"Re-used" code
Mono-for-Android's Main.cs::DeserializeConferenceFile, LoadWhatsOn and MonoTouch's AppDelegate.cs::FinishedLaunching both contain "very similar" code in the form of the conf.xml deserializer and parser. In MonoTouch it's 70 lines and in MonoDroid it's 307 lines. The MonoTouch version is heavily assisted by the Linq/MonoTouch.Dialog code in HomeController (another 150 lines or so) which explains part of the difference... but what is shared is the deserialization logic and a number of Linq statements that help parse it for display. These would be harded to shift into a common library due to the dependency on MonoTouch.Dialog - but there was definitely an efficiency gain by having the code already written and tested on one platform before porting to the other. I'll adjust both by the same 'average' LOC count to try and reflect the 'copy/paste but modify' efficiency gain.

Mono-for-Android: 375 lines (575-200)
MonoTouch: 945 lines (1,145-200)

Feature parity
Adjust the MonoTouch solution to allow for the fact that it implements the Map feature that is not available on MonoDroid - 118 lines of code across a few classes.
MonoTouch: 827 lines (945-118)

What's left?
Once we've removed the libraries, the shared data structure, common code and allowed for some "copy/paste re-use", what's left to differentiate the two codebases? Basically just the UI and the code that binds our DTOs to it.
Mono-for-AndroidMonoTouch (iOS)
Code375 lines827 lines
'markup'14 AXML1 XIB
Views7 Activities9 ViewControllers
DataSources6 Adapters5 TableViewSource
Some notes on the difference:
  • There are 350 lines of AXML to define the layouts used in MonoDroid - the equivalent task in MonoTouch is done mostly in C#, significantly contributing to the LOC difference. I could have implemented a lot of that MonoTouch layout in XIBs using InterfaceBuilder - I just don't like doing it that way.
  • The UITabBarController takes more code to setup than
    OnCreateOptionsMenu.
  • The iOS SQLite implementation of saving Favorites is more verbose than the XML-serialized-file solution used on Android.
  • The MonoTouch source is almost 2 years old, and in some places isn't as succinct as it could be.

Conclusion
So is MonoTouch instrinsically more verbose than MonoDroid? I don't think so - it depends greatly on your preference for constructing your Views (XIBs or in-code). The more important question: does building with Mono* make it easier to port your app to other mobile platforms... and the answer is YES! In future this code might get tidied up into a good example of a cross-platform app... in that case I'll re-examine the stats to make an even better case.

Look at it this way: the iOS app took 1,400 lines of code (it was written first). For an additional 375 LOC (plus some layout XML) we got an Android port - almost for free!

Thankfully it sounds like Xamarin Studio is coming along nicely.

Saturday, 9 July 2011

MonoTouch for Monospace II

Further to the MonoDroid version, I've just submitted an iOS version of the Monospace 2011 conference app to Apple (fingers crossed it gets approved, and in time for the conference!).

Here's how it looks:

Even if it doesn't get approved in time, the code is open-source and can be found at github.com/conceptdev/Monospace11. It is based on the original Monospace09, PDC09 and MIX10 apps. A couple of guys helped out with the MIX10 version: @migueldeicaza, @kangamono and @chrisntr. I know Miguel in particular was keen for this code to be open-sourced... I think (?) it was one of the first outings of his awesome MonoTouch.Dialog library. I'd like to thank them again for their help (and to note that any remaining bugs or problems are mine). Also note: there is some old code in there (like, almost 2 years)... it scares me a little to put it up on Github, so please, be gentle.

I'll update with an AppStore link if/when Apple is done; but for now just enjoy the code :)

See you at Monospace!

Friday, 18 February 2011

Status Update: accessing Facebook with MonoTouch

Haven't blogged for a while, but hopefully that's about to change... and to kick off more regular posts here is a simple example of accessing the Facebook OpenGraph API using MonoTouch.

The core of the example is @redth's MonoTouch.Facebook.Authorization ViewController which uses the Facebook OAuth webpage hosted in a UIWebView to authenticate and grab the access_token you need for subsequent requests.

The app looks like this when it runs (and yes, when you Save your status update, it appears directly on your Facebook Profile):
The code is available on github at github.com/conceptdev/Facebook - remember you need to have a Facebook Application 'Client ID' (create one here) to get it working. NOTE: this is a sample - there is very little in the way of error detection, correction or recovery... left as an exercise for the reader :)

Facebook Login
The Facebook OAuth 'magic' happens inside a UIWebView... we create one and navigate to https://graph.facebook.com/oauth/authorize which displays and processes the login form. A successful authentication results in a redirect to a 'known page'; the redirected URL contains the access_token needed for subsequent 'authorised' requests so the code strips it out and saves it. Thanks again to Jon without whom the rest of the code wouldn't be here!

Facebook Newsfeed
Getting the news feed is relatively simple and thanks to some useful info on using Json.NET with MonoTouch it is easy to parse too!
var b = wc.DownloadData(
   new Uri("https://graph.facebook.com/me/home?access_token=" + token));
var s = Encoding.UTF8.GetString(b);
var posts = JsonConvert.DeserializeObject<Posts>(s);
The parsing works so easily because Objects.cs contains a set of classes that (roughly, not completely) match the JSON returned by Facebook, for example:
{"data":[\{"id":"57755305836_10150135900140837","from":\{"name":"Tiga","category":"Musician\\/band","id":"57755305836"\},
"message":"Bad DJ Signs Vol.1:  when your dancefloor reminds you of the \\"club\\" scene from \\"Vanilla Sky\\"",
"icon":"http:\\/\\/photos-d.ak.fbcdn.net\\/photos-ak-snc1\\/v27562\\/23\\/2231777543\\/app_2_2231777543_9553.gif",
"actions":[\{"name":"Comment","link":"http:\\/\\/www.facebook.com\\/57755305836\\/posts\\/10150135900140837"\},
\{"name":"Like","link":"http:\\/\\/www.facebook.com\\/57755305836\\/posts\\/10150135900140837"\},
\{"name":"\\u0040ciaotiga on Twitter","link":"http:\\/\\/twitter.com\\/ciaotiga?"\}],
"type":"status","created_time":"2011-02-18T07:23:42+0000","updated_time":"2011-02-18T08:25:22+0000",
"likes":33
maps to
The DeserializeObject() call is then all that is required to take the JSON string and turn it into an object graph that is easily bound to a UITableView (see Main.cs).

Facebook Status Update
Once we have the authentication token updating your status is easy - a simple POST using WebClient is all it takes.
System.Net.WebClient wc = new System.Net.WebClient();
var result = wc.UploadString
("https://graph.facebook.com/me/feed?access_token=" + token
, "message=" + status);


but isn't there a Facebook API for iOS?
Yes, in addition to this 'manual' way of authenticating using an embedded webpage Facebook also provides a Mobile API. The UI presented to the user looks nicer than the webpage AND it can interact with the official Facebook app (if installed). To get that working with MonoTouch requires btouch-library bindings... but that's a story for another post.

UPDATE: (from comments below) @klmcmahon has already ported the Facebook iOS SDK and sample to MonoTouch - thanks Kevin!

Sunday, 7 November 2010

Conf mobile schedule for TechEd Berlin & Ƙredev

Europe is awash with conference attendees this week - for TechEd Berlin and Ƙredev.

If you are attending either conference, you might want to download Conf to your iPhone or Windows Phone 7 (no Android for now, but coming...).

One warning for Ƙredev - the 'unusual' session starting times (eg. 10 after the hour) were not catered for in the code, so the "up next" algorithm doesn't really work. To be fixed in the next release!


Hopefully no such issues occur with the TechEd Europe schedule, bought to you by the power of OData!

If you're reading this, you must be interested in these conferences, so you probably want to know about these other mobile schedule apps too*:
* DISCLAIMER: I had nothing to do with either of these apps - just mentioning them FYI...

Wednesday, 4 August 2010

UIGlassButton Generator in MonoTouch

Sometimes the default look of iOS controls (such as UIButton) is a little 'flat'. Apple themselves sometimes use a very pretty 'glass button' effect, which could be achieved (apparently, I'm paraphrasing here) using an undocumented UIGlassButton class. You can read more about this in the source links for this sample:
Anyway... Martin did a great job porting this approach to MonoTouch, creating a GlassButton.dll wrapper as part of a sample project that allows you to create great-looking PNG-image-glass-buttons to incorporate into your iOS projects. The only thing missing was a double-resolution version for my new iPhone4's Retina Display, so that's what I've added to this github project: GlassButtonGenerator.

How it works:
  1. Edit the string constants for button text and filename
  2. Edit the filename which is used in the path to save the output
  3. Run the app in the Simulator and press the [Generate Glass Button] button
  4. Grab the images that are saved to your Desktop
  5. Use the images in your iOS app in UIButton controls
Here is the 'output' when you are running it in the simulator (the button images should be saved to your Desktop):

If you are then wondering what to do with the two images, check out Miguel's post on Building apps for the Retina Display. Basically you should use UIImage.FromBundle to load the image and ensure that the 'regular' and 'retina' versions have the same filename (with the 'retina' version having a suffix @2x).

For the code below, the /Images/ folder has four images: BuyGlass.png, BuyGlass@2x.png, CancelGlass.png, CancelGlass@2x.png (where the @2x images have double the height & width dimensions of the base image)...
buyButton.SetImage(
     UIImage.FromBundle("Images/BuyGlass.png")
   , UIControlState.Normal);
cancelButton.SetImage(
     UIImage.FromBundle("Images/CancelGlass.png")
   , UIControlState.Normal);

Don't forget to make the Build Action: Content for your image files! And remember, DON'T use UIGlassButton in your apps directly - generate the images and include them.

UPDATE (May 2011): Miguel has posted a code-based glass button implementation which you might prefer to this pre-generated image one. See Glass button for iPhone and the code on github.

Friday, 23 July 2010

Drawing on Maps with MonoTouch

iOS4 introduced new features like MKOverlay to help draw lines/routes and shapes/polygons on the MKMapView control, however it has always been possible to add these features to maps in iOS3.

Two (Objective-C) examples of displaying geometric shapes on MKMapView in iOS3 are:
...it is these examples that I've ported to MonoTouch (as a Universal app: iPhone and iPad). You can grab the code from github project MapStuff and see some screenshots below:

I put together a class diagram to try and explain how they work (the classes shown are from the 2nd example, which allows you to draw your own shape).

Please remember all the hard work here has been done by the original authors. All credit goes to them. Any bugs in the MonoTouch code are mine... let me know if you find any.

iOS4 examples to follow...

Sunday, 18 July 2010

More MonoTouch Machine-translation Madness!

In addition to the recent dodgy Spanish localization, my TweetStation fork now has dodgy French, Japanese, German and Italian translations (courtesy of the Microsoft Translator API that was introduced at MIX10). Here's how they look:



The following two code snippets were added to ngenstrings so that once the text has been extracted from TweetStation, it is automatically translated and written to .strings files ready for inclusion in the correctly-named .lproj folders (this code hasn't been committed to github - but it should be easy to add to your local copy).

add code to the end of MainClass.Main
string[] languages = new string[]{"fr","ja","it","de"};
foreach (var language in languages)
{
   foreach (var table in tables.Values)
   {
      foreach (LocalizedString locstring in table.Values)
      {
         locstring.Value = Translate(locstring.Key, language);
      }
      table.WriteStringsFile(assemblyName, outputFormat, language);
   }
}

add method to MainClass
//http://msdn.microsoft.com/en-us/library/ff512421.aspx
static string Translate (string text, string toLanguageCode)
{
   string appId = "REGISTER_AND_INSERT_YOUR_APPID";
   string translation = text;
   text = text.Replace(" ", "%20").Replace("&", "").Replace("#","%3F");

   string detectUri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=" + appId +
  "&text=" + text + "&from=en&to=" + toLanguageCode;
   Console.WriteLine(detectUri);
   try {
      System.Net.HttpWebRequest httpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(detectUri);
      System.Net.WebResponse resp = httpWebRequest.GetResponse();
      Stream strm = resp.GetResponseStream();
      StreamReader reader = new System.IO.StreamReader(strm);
      translation = reader.ReadToEnd();
   }
   catch (Exception e)
   {
      Console.Write("Translation failed for " + text + " - " + e.Message);
   }
   return translation;
}

Hopefully that gives you some ideas (or inspiration) on how to increase the market for your apps across the world. Remember that machine-translation is NOT a substitute for a professional human translation, however it can be useful to test your application's ability to handle and display different languages (eg. the size of the strings, etc).

Friday, 16 July 2010

TwitEstaƧion: MonoTouch TweetStation en espaƱol

If you are a MonoTouch developer then you should already be familiar with the two subjects of this post:
It just so happens that Chapter 12 - Localizing for an International Audience of the book introduces a small utility called ngenstrings that helps you to translate your application into other languages. Today I updated ngenstrings to use the latest Mono.Cecil version, and to test it out I decided to have a go at localizing TweetStation into Spanish. You can download the Localizable.strings file that was created (and translated courtesy of Bing). Here's a screenshot showing where it fits into the solution:
...and here are a couple of screenshots showing TwitEstaƧion in action ;-)

NOTE: Miguel had already made a good start building an internationalized app - many of his strings were wrapped in a Locale.GetText() method which was easy for me to work with. None of his code needed to change except for Locale.Get() and Locale.Format() to add NSBundle.MainBundle.LocalizedString(str,"");
NOTE2: this was a MACHINE TRANSLATION - of course you would arrange for a real person to translate your apps before taking them to the AppStore!
NOTE3: I have not translated 100% of Miguel's app - this is for demonstration purposes at the moment.
NOTE4: It's called TwitEstaƧion because "TweetEstaƧion" is too long for the iPhone home screen, and gets shortened unreadably. I don't speak Spanish so who knows if that makes any sense at all!

UPDATE: a few more screenshots... (again, apologies for the machine translation:)
UPDATE2: localized code forked from TweetStation main now available on github.

Friday, 9 July 2010

MonoTouch port of TDBadgedCell

I recently wanted to add an 'item count' to a UITableView in one of my iPhone/iPad projects and thought it would be nice to match the grey/encircled 'badge' used in the Mail application.

Happily,  I found (via The Unofficial Apple Weblog) that Tim Davies had the same idea and already done the hard work, albeit in Objective-C. Tim's code for TDBadgedCell is on github (you can help him out and donate, too), as is the MonoTouch/C# port: TDBadgedCellSharp. Both produce the same output (shown below)

The important stuff (TDBadgeView and TDBadgeCell) is in TDBadgedCell.cs - the rest of the project is purely for demonstration purposes.

Here's a very simple example of how to use the badged cell (warning: doesn't show DequeueReusableCell which you would normally use in the GetCell method)...

public override UITableViewCell GetCell 
   (UITableView tableView, NSIndexPath indexPath)
{
   TDBadgedCell cell = new TDBadgedCell (UITableViewCellStyle.Subtitle, "Cell");
   cell.TextLabel.Text = contents[indexPath.Row].Title;
   cell.TextLabel.Font = UIFont.BoldSystemFontOfSize (14);

   cell.DetailTextLabel.Text = contents[indexPath.Row].Detail;
   cell.DetailTextLabel.Font = UIFont.SystemFontOfSize (13);

   cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
   cell.BadgeNumber = Convert.ToInt32 (contents[indexPath.Row].Badge);

   if (indexPath.Row == 1)
      cell.BadgeColor = UIColor.FromRGBA (1.000f, 0.397f, 0.419f, 1.000f);
   if (indexPath.Row == 2)
      cell.BadgeColor = UIColor.FromWhiteAlpha (0.783f, 1.000f);
   return cell;
}

Thanks Tim!

..and finally, if you didn't notice the cover at the top of this page or seen the tweets, "my" book (and Wally, Chris, Martin & Rory's :) is now available from Amazon (and other locations, in paper or PDF)!

Monday, 3 May 2010

iPad 'infinite scrolling' with MonoTouch

Tonights exercise proves that sometimes it's worth taking time out to 'design' a chunk of code before writing it. Here's the "design"... can you see what it's trying to do?


Okay, I'll tell you: I'm trying to create an 'infinite' (well, just a configurable number) of scrollable pages that are rendered with UIWebView controls. I want to use the minimum number of controls for performance and memory but I also want a nice scrolling experience where the next and previous pages are aways pre-loaded. As you scroll left and right, the UIWebViews are shuffled around (X-coordinates only) to create an effect similar to the Time magazine 'app'.

Amazingly it worked out pretty quickly - here are a couple of screens to "prove" that it scrolls left & right as expected. It's using a "CSS3" multi-column hack in the Html, but that's another story...


And here are the 'important bits' of the code. I'm not publishing the entire source right now - the app still has a long way to go - but you get the idea... I hope. I only had a brief look around for existing examples so if you've seen a better one, let me know!

// declarations
UIScrollView MyScrollView;
UIWebView[] WebViewArray = new UIWebView[3];
int[] WebViewHasPage = new int[]{0,1,2};
int NumberOfPages = 8; // news01.html .. news08.html
...
// ViewController ctor
var bounds = new RectangleF(0, 0, View.Bounds.Width, View.Bounds.Height);
MyScrollView = new UIScrollView(bounds);
RectangleF scrollFrame = MyScrollView.Frame; // start with screen size
scrollFrame.Width = PageWidth * NumberOfPages; // then make the content
MyScrollView.ContentSize = scrollFrame.Size; // 8 screens wide
MyScrollView.Scrolled += ScrollViewScrolled; // and attach event handler
for (int i = 0; i < 3; i++)
{ // lay out three web controls to shuffle around
webViewFrame.X = PageWidth * i;
WebViewArray[i] = new UIWebView(webViewFrame);
WebViewArray[i].ScalesPageToFit = false;
var u = NSUrl.FromFilename(basedir+"news0"+(i+1)+".html");
var r = new NSUrlRequest(u);
WebViewArray[i].LoadRequest(r);
MyScrollView.AddSubview (WebViewArray[i]);
}
...
// and the method that does the shuffling
private void ScrollViewScrolled (object sender, EventArgs e)
{
UIScrollView sv = (UIScrollView)sender;
double page = Math.Floor ((sv.ContentOffset.X - sv.Frame.Width / 2) / sv.Frame.Width) + 1;
int LastPage = CurrentPage;
int NewPage = CurrentPage;
if (sv.ContentOffset.X % PageWidth == 0) NewPage = (int)page; // moved pages!
if (NewPage >= 0 && NewPage < NumberOfPages)
{
pageControl.CurrentPage = NewPage;
CurrentPage = NewPage;
int updatePage = 0;
bool shouldMove = false;
if (NewPage > LastPage)
{// moving right
updatePage = NewPage + 1; shouldMove = true;
}
else if (NewPage < LastPage)
{// moving left
updatePage = CurrentPage - 1; shouldMove = true;
}
if (shouldMove & (updatePage >= 0) & (updatePage < NumberOfPages))
{
int webViewSlot = updatePage % 3;
if (WebViewHasPage[webViewSlot] == updatePage) return; // already has it
else WebViewHasPage[webViewSlot] = updatePage;
var url = NSUrl.FromFilename(BaseDirectory+"news0"+(updatePage+1)+".html");
var request = new NSUrlRequest(url);
WebViewArray[webViewSlot].LoadRequest(request);
var rect = new RectangleF (
WebViewArray[0].Frame.Width * updatePage
, WebViewArray[webViewSlot].Frame.Y
, WebViewArray[webViewSlot].Frame.Width
, WebViewArray[webViewSlot].Frame.Height);
WebViewArray[webViewSlot].Frame = rect;
}
}
else
{
Console.WriteLine ("Scrolled a little too far, to page " + page);
}
}

Tuesday, 9 March 2010

Anatomy of a c# iPhone app (with MonoTouch)

Wow - it has been a long time since my last post... and with good reason ;)

Firstly I've been busily writing (along with Wally, Chris, Martin & Rory) for Wrox' upcoming Professional iPhone Programming with MonoTouch and .NET/C# which is available for pre-order on Amazon. If you are interested in developing for the iPhone using C# and the .NET Framework it should be a great addition to all the resources already out there on the web.


Secondly I've been working on an iPhone app for MIX10 in Las Vegas next week (with help from Chris, Miguel & Geoff). Whether you are heading to MIX or just curious about C# and MonoTouch on the iPhone, why not download and give it a try?

Since the MIX10.app was first 'announced' on twitter #MIX10 there have been a number of requests for the source code. Unfortunately the source isn't public at the moment, however that doesn't mean we can't talk about "how it works". To start with, the MIX10.app is based on two previous iPhone apps written in C# with MonoTouch, and whose source code is available:
If you have an Intel Mac (with Snow Leopard) then you can download both the Apple SDK and the MonoTouch trial version for free and get both these C# .NET examples running in the iPhone Simulator for yourself. To deploy on a real iPhone requires certificates and licences (from Apple and Novell/MonoTouch respectively).

MIX10.app
Here's the overall class diagram for the MIX10.app (with the views shown too). Even without seeing the code it's clear that the classes themselves are not overly complex (ie. few methods are required; and inheritance can be leveraged to share common functionality).


The MIX10.app also uses Miguel's MonoTouch.Dialog framwork and he's posted a snippet of code on gist.github which is responsible for this screen (on the left)




And he also posted this code which creates the 'My Schedule' view on the right. Pretty neat use of Linq, eh? I'm not sure I've seen such an expressive user-interface expressed in so few lines of code before...
public class FavoritesViewController : DialogViewController {
  public FavoritesViewController () : base (null) { }
  public override void ViewWillAppear (bool animated)
  {
    var favs = AppDelegate.UserData.GetFavoriteCodes();
    Root = new RootElement ("Favorites") {
      from s in AppDelegate.ConferenceData.Sessions
        where favs.Contains(s.Code)
        group s by s.Start into g
        orderby g.Key
        select new Section (MakeCaption ("", g.Key)) {
          from hs in g
            select (Element) new SessionElement (hs)
        }
    };
  }
}
The object model closely follows the data available from the api.visitmix.com site's OData and RSS feeds. These are plain vanilla C# objects which also run on the server to download and package the data for the iPhone - the object graph is serialized by a .NET application on Windows Server 2003, downloaded by the WebClient class on the iPhone (thanks to MonoTouch) and de-serialized ready for display. A perfect example of the cross-platform possibilities facilitated by MonoTouch and having the .NET framework available on both server and mobile device.


Finally, here's a quick overview of ALL the screens in the app.


...and if you're a Windows Phone Series 7 fan-in-the-making, it should be obvious that having a shared set of services and functionality in C# that can be deployed across iPhones with MonoTouch, and Silverlight/Windows Phone 7 with only UI code needing to be customized is a great way to achieve maximum reach for your apps. The MonoTouch Roadmap is also targetting a Q3 release of MonoDroid, so with a bit of imagination it isn't hard to see where the future of cross-mobile-device development is heading...

Friday, 15 January 2010

MonoTouch MapKit.Delegate-precated

An update to MonoTouch (1.4.4) was released today with these changes/improvements (actually 1.4.5 was released a day later). One in particular caught my eye, since I've previously blogged about MapKit in MonoTouch.
MKMapView now has C# style events

So what does that mean? Basically the crafty team at Novell have turned the Apple SDK "pattern" of using a MKMapViewDelegate class to respond to "events" on its head, and instead exposed familiar .NET events on MKMapView itself. *

Here's a comparison of the 'old' and 'new' MKMapView class:


Here are two 'example' delegate methods that work in 1.4.4 (and .5). Firstly here's an example of wiring up one of the "new" events CalloutAccessoryControlTapped. NOTE the += used to attach the delegate to the event.
Map.CalloutAccessoryControlTapped += 
delegate(object sender, MKMapViewAccessoryTappedEventArgs e)
{
MyAnnotation myAnn = e.View.Annotation as MyAnnotation;
using (var alert = new UIAlertView (myAnn.Title,
myAnn.Subtitle + " clicked", null, "OK", null))
{
alert.Show();
}
};
The second example is probably the most common one - GetViewForAnnotation - which you will need to provide if you want to do any sort of customization of your pins/callouts. NOTE how it is assigned with an equals sign and has a return value!
Map.GetViewForAnnotation = delegate (MKMapView mapView, NSObject annotation) {
if (annotation is MKUserLocation) return null;
MyAnnotation myAnn = annotation as MyAnnotation;
var annView = mapView.DequeueReusableAnnotation ("pin");
if (annView == null) {
var pinView = new MKPinAnnotationView(myAnn, "pin");
pinView.AnimatesDrop = true;
pinView.CanShowCallout = true;
annView = pinView;
}
else
{
annView.Annotation = annotation;
}
return annView;
};

* imagine these are "air quotes" in this paragraph
p.s. This post has been updated since the comments below. The first two kinda don't make sense now... Thanks for the advice mdi.

Tuesday, 10 November 2009

iPhone Obj-C books for MonoTouch devs (first look)

UPDATE 6-JUN-10:This book Professional iPhone Programming with MonoTouch and .NET/C# is available for pre-order on Amazon... one of the authors might be familiar :-)

UPDATE 2-DEC-09: the first MonoTouch-specific book (that I know of) is now available to purchase/download - Building iPhone and iPod touch Applications for the .NET/C# Developer with MonoTouch (Wrox Blox). I haven't had a chance to read closely yet, but it's good value at USD6.99 so definitely worth a look.

iPhone BooksI recently received yet another addition to my 'Objective-C books for iPhone Development' collection - initially started to learn Obj-C (never happened) they are now more of a reference while learning MonoTouch.

Firstly, I have NOT read them cover-to-cover... I've done a bit of flicking, a bit of skimming and read a chapter or two. Secondly, I'm not really evaluating them according to their original purpose - to teach Objective-C - rather I'm making a personal judgement on their suitability as reference material for .NET developers.

I've listed them in their "order of usefulness" for MonoTouch .NET devs (according to me :)

Beginning iPhone Development: Exploring the iPhone SDK [BEGINNING IPHONE DEV]
Dave Mark; Jeff LaMarche (APress)

This was the first iPhone book I purchased, so I've read it more closely than the rest. I learned quite a bit from various examples and discussions in this book - it's probably at the top of the list for this reason. The writing style is easy to read and there isn't too much emphasis on Xcode (other books do seem to focus on Xcode, the Head First one most heavily).

The initial chapters are probably best replaced with a MonoTouch 'Hello World' screencast - you don't really need to know all the Xcode, pch files and @synthesize that the book discusses (and there are quite a few free resources around that cover "your first MonoTouch app").

Pros
• Interface Builder examples are relevant
• Friendly colloquial tone
• Widest variety of topics (includes localization, accelerometer)

Cons
• Large swaths of Objective-C in some chapters
• Still need to decode Objective-C in the examples

Overall, though, my favorite of the bunch.

The iPhone Developer's Cookbook: Building Applications with the iPhone SDK
Erica Sadun (Addison Wesley)

I'm a big fan of Erica's from her blog and applications when the iPhone and iPod Touch first appeared and were programmable. Text is easy to read. Erica often references "when the iPhone first appeared" or "during the Beta period" - often interesting insights that add some fun to the text. There are also references to many 'undocumented' APIs - they're clearly highlighted to avoid confusion, but unfortunately they're even more difficult to use from MonoTouch than Objective-C... I felt a bit "left out" on first reading, although with btouch in MonoTouch 1.2 I'm wondering whether it might be easier to access these APIs now? (even though we're not supposed to...)

Chapter 2 - Views - does a really nice job of gradually introducing various concepts, and the Objective-C is minimal. That chapter on it's own is probably worth reading for anyone coming to iPhone programming. The rest of the first half is also fairly easy to follow (View Controllers, Basic Tables) - if the examples were in C# they might be my favorite 'introduction to iphone programming' :)

Towards the end of the book the amount of Objective-C does increase to a few multi-page listings that are more difficult to read (and probably beyond beginning C#ers) but overall the book is good value.

There is a 2nd edition due in January 2010 which will probably address my other main concern with this book: that it pre-dates the latest iPhone OS releases and hardware. Not a big deal really, but it's always nice to have info on the latest and greatest.

iPhone SDK Application Development: Building Applications for the AppStore
Jonathan Zdziarski (O'Reilly)

Less "reading" in this book - rather than longer explanatory paragraphs the author uses smaller chunks of text interspersed with bullet points, callouts and small and large Objective-C listings. This actually makes it better as a reference book than a front-to-back learning tool - and that makes it more suitable for MonoTouch in my view.

As with the other titles, the initial chapters cover Objective-C concepts like messaging, implementation, protocols, categories and posing(!) which you aren't likely to need as you start out with MonoTouch (although you might return to read about them later, to get your head around more complex examples).

I've used the remainder of the book to 'look up' various things that I want to learn about or need examples of, usually as a backup/alternative to the material that I've found in other books or on the web. It doesn't have the breadth of "Beginning iPhone Dev" nor the easy readability of Erica's stuff, but I have definitely picked up some useful tidbits from this book.


Head First iPhone Development: A Learner's Guide to Creating Objective-C Applications for the iPhone
Dan Pilone; Tracey Pilone (O'Reilly)

I love the Head First series from O'Reilly, so I was determined to like this book; and it definitely lives up to it's promise as a Head First title. The writing, imagery, exercises and screenshots are all as you'd expect and it is really good at explaining Objective-C, Xcode and Interface Builder concepts... however that's partly what makes this volume less useful for C#ers: the writers go out of their way to explain/show how to do everything with Xcode and Interface Builder! As a MonoTouch developer I find myself only in MonoDevelop writing code and building my interfaces in code... so to my dismay I find myself unable to put this book at the top of my list.

It is still a fun read, and the non-techy bits (of which there are many) are extremely relevant to ALL iPhone devs. The recommendation to design your UI on paper, to follow Apple's Human Interface Guidelines, to remember to test on a Touch, and much more... if I ever decide to really learn Objective-C, I'll probably come back to this book and run through all the examples from go-to-whoa since it does try to teach the language and the SDK (and I really need help with my memory management!).


iPhone Cool Projects
Bennett et al (Apress)

The most 'attractive' of the five, due to the easy-to-read typesetting and colorful (yes COLOR) layout and imagery; this book probably doesn't really even belong in the list. It is more of a 'discussion' of iPhone application design - there is a fair amount of Objective-C throughout but it's mainly used to illustrate points of discussion, and the chunks are small enough that a C# developer can easily scan them.

Definitely fun to read - but you'll want any/all of the other books first to advance your knowledge of the iPhone SDK and Objective-C before you start trying to use the examples in this book. It probably isn't a good choice as a 'reference' or a learning tool for C#ers until you've got a few apps under your belt.


Finally...
As time passes and my knowledge increases my opinion of these books might change. Perhaps others have different opinions on what makes a good "Obj-C for C#" book, or have come across other titles? I'm sure there'll be C#/MonoTouch specific titles on the market eventually - it will be interesting to see how they read too!