iAD with Monotouch

by ManniAT 4. July 2010 20:07
Technorati-Tags: ,,

Working on my RPS project (http://iphone.pp-p.net/) I decided (at a late moment) to implement iAd.

But let’s start from the beginning. The design goal for this app was to build a game which can be played with nearby players as well as over the internet.

So my first approach was to implement a form which allows me to pick peers. The result – a lot of “double entries” or only one side seeing the other and things like this.
So the next decision was – 2 forms – one for the internet and for gamekit I’ll use the GKPeerPickerController.

Unfortunately two things happened:

  1. GKPP is also showing double entries (or nothing sometimes)
  2. GKPP force me to turn on Bluetooth

So the problem became even worse – and I decided to go back to my own implementation.
The first approach was to subclass a UIAlertView (which works well) but later the iAD framework took my attention. The idea – it’s could be a boring  situation (waiting for matching players) and that’s from my point of view a good place to show an add which doesn’t annoy the user too much.

But iAD needs a UIViewController – it doesn’t work when you host it in a UIAlertView.
So I changed the things to a “normal” UIViewController which I simply push when needed.

It looks like this:

4List IMG_0331

 

As you can see – the second version shows an add.
My first problem – I couldn’t get the thing running. Messing around for about an hour I got stuck providing format information. My (typical) reaction – joining the MonoTouch IRC channel – and ask stupid questions.

And (within minutes) “kangaroo” confirmed a bug – and help me implementing a workaround.
That’s what I like most with MonoTouch – you have a problem – and get it fixed real fast.
By the way – I had only little problems – and some of them have been my fault.

Anyhow – the documentation about the iAd framework is a bit poor – so I decided to write this post.
To come to a point – after “fixing” the bug (a property returns null) it took me about 2 minutes to implement what you see above – an add at the bottom of my UI.

Here is the relevant code:

Snippet created with CBEnhancer
public class Application {
    static void Main(string[] args) {
        Globals.IsOnOS4 = UIDevice.CurrentDevice.RespondsToSelector(new Selector("isMultitaskingSupported"));
        if(Globals.IsOnOS4) {
            Globals.IsMultitaskingEnabled = UIDevice.CurrentDevice.IsMultitaskingSupported;
        }
        Console.WriteLine("OS4: " + Globals.IsOnOS4.ToString() + " Multi: " + Globals.IsMultitaskingEnabled.ToString());
        UIApplication.Main(args);
    }
}

 

My project is a universal app – so I placed this code in Main.cs – you could also place something like this in you AppDelegate… file at FinishedLaunching.

“Globals” is a static class which holds some information I need all around the project.

Now to the iAd related code in the UIViewController:

Snippet created with CBEnhancer
00 private object m_adBannerView;
01 
02 public override void ViewDidLoad() {
03     base.ViewDidLoad();
04     //boring stuff
05     if(Globals.IsOnOS4) {
06         m_adBannerView = new ADBannerView();
07         ADBannerView adBannerView = m_adBannerView as ADBannerView;
08         NSMutableSet nsM = new NSMutableSet();
09         nsM.Add(new NSString("ADBannerContentSize320x50"));
10         adBannerView.RequiredContentSizeIdentifiers = nsM;
11         adBannerView.AdLoaded += new EventHandler(m_adBannerView_AdLoaded);
12         adBannerView.FailedToReceiveAd += new EventHandler<AdErrorEventArgs>(m_adBannerView_FailedToReceiveAd);
13         adBannerView.Frame = new RectangleF(0, m_uivInner.Frame.Bottom + 9, 320, 50);
14         View.AddSubview(adBannerView);
15         adBannerView.Hidden = true;
16     }
17 }
18 
19 void m_adBannerView_AdLoaded(object sender, EventArgs e) {
20     (m_adBannerView as ADBannerView).Hidden = false;
21 }
22 void m_adBannerView_FailedToReceiveAd(object sender, AdErrorEventArgs e) {
23     (m_adBannerView as ADBannerView).Hidden = true;
24 }

 

First I declared the m_adBannerView – since I was a bit scared if it could make problems on “prior iOS 4” systems I declared it as object.
This explains the code in line 07 – where I use a local variable to prevent me from permanent casting.

Line 09 – a set to tell the AddBannerView which formats I support (the constant in line 09 is because of the bug).
Then two methods I need to implement – AdLoaded (called when an ad is available) and FailedtoReceiveAd.
The second method (although the event parameter is “..Error…”) is nothing more than an information that no ad is there (no matching ad in the inventory, no internet connection, …)

And for the ones curious about line 13 – this m_uivInner is a childview in the blue rectangle which holds buttons, the list and so on.
I use this subview since the same thing is also used on the iPad – but with a different size / location.

Anyhow – the code does 3 very simple things:

  1. It creates the ADBannerView  - telling it that I support portrait mode only (…320x50)
    It adds this view to my UI and hides it
  2. …AdLoaded displays the view
  3. …FailedToReceiveAd hides the view again

Of course I could have used an inline delegate – but I like methods – and these to guys will get some extra code to animate the things. So having the methods isolate gives me more isolation (primarily optical).

Snippet created with CBEnhancer
void m_adBannerView_FailedToReceiveAd(object sender, AdErrorEventArgs e) {
        float fZoom = 0.45f;
        float fAngle = 45;

        UIView.BeginAnimations("HideAdStep1");
        UIView.SetAnimationDelegate(this);
        UIView.SetAnimationCurve(UIViewAnimationCurve.EaseIn);
        UIView.SetAnimationDuration(0.2);
        CGAffineTransform ctZoom = CGAffineTransform.MakeScale(fZoom, fZoom);
        ctZoom.Rotate(ToRadians(fAngle));
        (m_adBannerView as ADBannerView).Transform = ctZoom;
        (m_adBannerView as ADBannerView).Alpha = fZoom;
        UIView.SetAnimationDidStopSelector(new Selector("DoHideAdStep2"));
        UIView.CommitAnimations();
    }
    [Export("DoHideAdStep2")]
    private void DoHideAdStep2() {
        UIView.BeginAnimations("HideAdStep2");
        UIView.SetAnimationDelegate(this);
        UIView.SetAnimationCurve(UIViewAnimationCurve.EaseOut);
        UIView.SetAnimationDuration(0.1);
        (m_adBannerView as ADBannerView).Alpha = 0;
        UIView.CommitAnimations();
    }

 

This is just a simple example – it turns the add (45°) – makes it smaller – and in step 2 it hides it by setting alpha to 0. The reverse thing is done in AdLoaded.

There are other events for the ADBannerView you might be interested.
The ActionFinished (tells you that the user closed the “banner dialog”). This is also available as event on the ADBannerView.
The second thing is (unfortunately not available as event) ActionShouldBegin. To handle this you have to implement you own delegate (just overriding this single method).

In my case I don’t care – a user watches gets bored and clicks the ad. The iAd guide says I should (!!!) disable sounds, animation or other activities that require user interaction.

That’s (almost) what I do – except – if someone invites the user while he watches the ad content I notify him with a sound. My understanding of the iAd guide makes me feel that this is ok.

Manfred

I attached a little sample showing the things.
The iAdTest$.. project is the VS project - the one without the $ signs the MT project.

iAdTest.zip (13.84 kb)

Tags: , ,

iPhone | MonoTouch

Layered UI or how to reuse UIs with MonoTouch and Silverlight

by ManniAT 29. March 2010 12:23

When we started the development of TTMoney one of our main goal was a “UI Designer” which should enable the User to change the look of his UI.
Think of it like “dynamic Themes”. Themes mean – I choose one and my colors, fonts, backgrounds, … change their style.

We wanted to go a step further an let the user compose his UI using a web interface.
Due to our skills we decided that this designer should be built using Microsoft Silverlight.

Since we use MonoTouch for our iPhone applications it is not really hard to share a lot of code.

The only challenge is the UI itself. For the iPhone we use (could use) the interface designer and for Silverlight we got Microsoft Expression Blend.
Sounds good – but it is unfortunately totally different. Not only from “how to use” – the output is the problem.

So one idea was to build a XIB – File parser (XIB files are what the Interface Designer generates) or a XAML (Blend output) file parser.

We decided NOT to build such a thing. Instead we designed our UIs to use a layered design.
This means: we have a “native UI layer” which mimics for an example the differences between a UIImageView (iPhone) and an Image Control (Silverlight).
This layer has to be changed when we transfer an iPhone UI to Silverlight.

Such techniques are well know form DALs (Data Access Layer). Using generics and some abstract methods and extensions it was not really hard to do this.
The only limitation is that MonoTouch has to compile all the .NET code (no Generic Methods and things like this) to native iPhone code.

Anyhow – this was not really a stopper. Especially Generics work very well and the rest is nothing more than to avoid some C# (.NET) elements.

Most of the “basic layer” work by translating controls (UIView becomes a Canvas for an example) and Property setters.
myUIView.AddSubview(ControlX) becomes myCanvase.Children.Add(ControlX).
And instead of setting the Frame (iPhone) we set “CanvasLeft, CanvasTop” and so on.

The abstract methods enable the framework to do enhanced things like animating something or things like this. While I start a storyboard in Silverlight I add a transition or something like this for the iPhone.

Above that layer a set of Generics are implemented. For an example – it’s an often asked question “how to have a background image in a UITableView…”. We have BackGroundViewController<TableViewController> for this.

We build our UIs completely in (reusable) code.
Negative: No rich UI designer.
Positive: It is more or less “platform independent” and it enables the things to be driven by a database.

Last not least Microsoft has Silverlight for Windows Phone 7 – and that means (with very little work) that our application will also run on this platform.

A simple example is this (very basic) Silverlight implementation of the “UI Themer”:
SLDesigner

A note about this “designer” – we’ve used the Telerik Silverlight Controls for it. And that shows how independent you could be if your “UI Layers” are well done.
We could have done the same thing using native Silverlight controls – but why if we have an easy way to use these enhanced Telerik  things.

We made this framework for TTMoney but while building this project we had the need to build another app.
This is Sticker and uses the Framework built for TTMoney.

Which brings me to my answer to Shawn Burke's great Blog Series.

I like what he wrote – except the “code line counting”. I fact most of the code is there to make the things work.
And if I calculate how much money you have left it does not matter if this is Windows Mobile 7 or iPhone code.
Building Sticker was about 200 Lines of UI code – the rest is “business logic”.
And for TTMoney we have ration of about 8.5 BL to 1.5 UI.

Of course – in both cases we have several hundred lines of code for the “UI Framework” – but this is totally reusable and will work in future projects also.

From my point of view the more important thing is how to handle “mobile specific” things in Windows Mobile 7 / iPhone.

Just as an example – Sticker allows you to send your “existing / missing lists”.
In MonoTouch the code looks like this:

Snippet created with CBEnhancer
void m_hbDoSendMail_Click(object sender, EventArgs e) {
        if(MFMailComposeViewController.CanSendMail) {
            MFMailComposeViewController mail = new MFMailComposeViewController();
            mail.SetMessageBody(m_strLastText + m_strStickerLink, true);
            mail.Finished += HandleMailFinished;
            this.PresentModalViewController(mail, true);
        }
    }
    void HandleMailFinished(object sender, MFComposeResultEventArgs e) {
        e.Controller.DismissModalViewControllerAnimated(true);
        if(e.Result == MFMailComposeResult.Sent) {
            Globals.MessageBox("Info", ULocalizer.ULOC["ZS_MailSent"].TheText);
            CloseDialog(false);
        }
        else {
            Globals.MessageBox("Error", ULocalizer.ULOC["ZS_MailSendError"].TheText);
        }
    }

 

I hope Shawn Burke will keep on extending his iPhone SDK vs. Windows Phone 7 Series SDK Challenge.

A last note – of course I’m not comparing with Objective-C – I talk about MonoTouch – but it is an existing technology – so why don’t use it.

Manfred

Tags: , , ,

iPhone | MonoTouch | Silverlight | telerik

UILabel with VerticalAlignment

by ManniAT 17. January 2010 18:37
Technorati-Tags: ,,

The default UILabel always centers text vertically.
Often you want to keep your text on top - or bottom of the control.

In my current project I have the following situation:

  1. Little space (as usual).
  2. On top a UILabel with 3 lines
  3. 90% of the time the Top UILabel uses 2 lines or even only 1 line

When there is only one line of text in the Top-Label the things look OK.
With 2 lines I have to much space on top – and too little on bottom. (Looks very nasty).
With 3 lines Top space is OK and bottom is a bit narrow. But this only occurs very seldom.
And it doesn’t look totally bad, since the top space is also small.

The reason for the problem – UILabel always centers the text vertically.

This is just an example – but I often have the situation where I would like to have “a bit more space for exceptional situations”.
As used from windows development I solve such problem by using a label which has place for the extra information – and comes near the next control.
This means a nice looking UI – and if the space is needed it is there.
In this (seldom) situation the distance to the next control is smaller than normally – but this doesn’t occur often.

To come to a point: the real problem is that UILabel always centers text vertically.

To overcome the problem I decided to build my own label control – with a VerticalAlignment property added.
Since I guess that such a situation is more or less common I decided to publish this class.
And because it is really simple – I don’t attach a file, or publish a library somewhere – instead I post the code here.

Snippet created with CBEnhancer
public class HLabel : UILabel {
        public enum VerticalAlignments {
            Middle = 0,    //the default (what standard UILabels do)
            Top,    Bottom        }

        #region VerticalAlignment
        private VerticalAlignments m_eVerticalAlignment;
        public VerticalAlignments VerticalAlignment {
            get { return m_eVerticalAlignment; }
            set {
                if (m_eVerticalAlignment != value) {
                    m_eVerticalAlignment = value;
                    SetNeedsDisplay();    //redraw if value changed
                }
            }
        }
        #endregion
        #region construction
        public HLabel() { }
        public HLabel(RectangleF rF) : base(rF) { }
        //add other constructors if needed
        #endregion
        #region overrides (DrawText, TextRectForBounds)
        //normally it uses full size of the control - we change this
        public override void DrawText(RectangleF rect) {
            RectangleF rErg = TextRectForBounds(rect, Lines);
            base.DrawText(rErg);
        }
        //calculate the rect for text output - depending on VerticalAlignment
        public override RectangleF TextRectForBounds(RectangleF rBounds, int nNumberOfLines) {
            RectangleF rCalculated=base.TextRectForBounds(rBounds, nNumberOfLines);
            if (m_eVerticalAlignment != VerticalAlignments.Top) {    //no special handling for top
                if (m_eVerticalAlignment == VerticalAlignments.Bottom) {
                    rBounds.Y += rBounds.Height - rCalculated.Height;    //move down by difference
                }
                else {    //middle == nothing set == somenthing strange ==> act like standard UILabel
                    rBounds.Y += (rBounds.Height - rCalculated.Height) / 2;
                }
            }
            rBounds.Height = rCalculated.Height;    //always the calculated height
            return (rBounds);
        }
        #endregion
    }

The class is really simple. It overrides TextRectForBounds – a method which calculates the rectangle wherein a text should display. In this method we change height and top (Y) of the bounding rectangle depending on VerticalAlignment.

Next we have a property for vertical alignment – where the setter forces a redraw if the value changes.
The property has (of course) an enum for the values.

Last not least we have constructors – that’s it.
Very simple (written in about 5 minutes) – but (at least for me) very usefully.

I hope some of you think also that this class is useful.

Manfred

Tags: , ,

iPhone | MonoTouch

My first iPhone application on the appStore

by ManniAT 12. December 2009 18:34

On a lengthy bus trip after DevReach Lino Tadros from FALAFEL inspired me to do some work with MonoTouch.

Years ago I did a project for a customer which includes a tool that supports their drivers with “Section Control(s)”.

This system has different names and (AFAIK) exists in Australia, UK, Italy the Netherlands and in Austria.
In Germany the plan to install such a system in the nearer future.

In the UK it’s named SPECS http://www.speedcheck.co.uk/ and has over 180 Installations.

In our region (Upper Austria) a new installation will be activated at Dezember 18th.
Information in German

So I remembered the “old solution” (it’s still in use) and decided to build this thing for the iPhone.

The main reason for this application is security. Let me explain.

The systems work with very small tolerances.
In Austria for an example you have 3% or 3 km/h for limits of 100 km/h and above.

So this means to always watch your speed very carefully. And that means look at your speedometer.
BUT: with 50 km/h one look to the Speedo means 28 meters “blind flight”.

I’ve heard rumors that some of my customers drivers abuse the system in the following way:
There is traffic and a limit of 80 km/h on a section  3 Kilometers long.
Due to the traffic they can go only about 50 km/h for about 2 Kilometers.
After this Section Controls shows (of course) that his average speed is 30 km/h below the allowed, so … Devil

Anyhow – the reason for Section Control is safety. You don’t have to watch the speedometer that much; Section Control will give an acoustic warning if your exceed the allowed average speed.

Back to building the application.
MonoTouch enable me to use a lot of the Windows Mobile C# Code for the new project.

Messing around with “Key-chains, provisioning, contracts,…” and all that other funny Apple stuff it took me about a week to build a development environment that does all I need.
This means – Max and PC Share a G15 Keyboard and my my 24” Main Monitor (I usually work with 2 19” Monitors and one 24”)
I have Windows Keyboard-Mapping on the Mac, shared drives…
Last not least I built a little tool to use MonoTouch Solutions in Visual Studio.

Anyhow, the infrastructure was done and it doesn’t take to much time to build the application.

UI Graphics took a lot of time in designer software, but coding was very easy. That’s one of the screens and it’s navigation animation :

Main     MainFlip
About 300 Kilometer of test driving later I was ready to put the app to the app store.

I read that it takes about 14 days for review. I did all I can to fulfill the rules for an iPhone application and so I was optimistic that Section Control will pass the review.

 

And YES – I submitted my application on Wednesday December 3rd (at about 1 am).
On Monday December 7th it changed the state from “Waiting for review” to “In  review”
Finally on Thursday December 10th an email arrived: “Your application is Ready for Sale” Big Grin

And since I early signed the “Artwork contract” I’m now allowed to use:

AppStore

 

YES – the Image has a working link!!

So thanks to MonoTouch which allowed me to use my existing .NET skills for iPhone development and thanks to the (at least in this case) very fast reviewers at Apple my first iPhone application is on the appStore!!

I just submitted an article about some parts of the solution at http://dotnetslackers.com/ – it will be reviewed and if gets published I will link it here.

Tags: , ,

iPhone | MonoTouch

MonoTouch in Visual Studio

by ManniAT 18. November 2009 18:31
Technorati-Tags: ,,

After doing my first steps with MonoTouch using MonoDevelop I decided that this is not they way I want to work.

First the MacBook - Shit+Alt+7 for Backslash At wits end

I added an external keyboard plus keyboard layouts to my MacBook, I changed CTRL / OPT / COMMAND…
But there are still things I really hate.
You press “End” – which brings you to the end of the file.
Ctrl+Left is not a word left – it’s beginning of line – and so on.

This turns my productivity down.
I worked with Windows for more than 17 years (mostly with the keyboard) – and you often see me typing:
Shift+Ctrl+Left, Shift+Ctrl+Left, Ctrl+C, Down, End, Ctrl+V….

Further MonoDevelop has problems with multiple screens.
Refractoring is poor, I miss: addons, instant macros, splitting windows,…

I decided to look for a different solution and found that Visual Studio can open MonoTouch projects (solutions).
The only problems:

  • An error because of an unknown project type (removing one line from .csproj fixes this)
  • A missing reference to monotouch.dll

To fix this I wrote a little program which creates a Visual Studio solution from a MonoTouch Solution.
It also adds a csproj.user to include a reference path where I place my monotouch DLLs at the PC.
You can find those DLLs at “Mac Harddrive\Developer\MonoTouch\usr\lib\mono\2.1” (2.1 or other version).

I place my MonoTouch projects on a shared volume – so I can have them open in VS for editing – and in MonoDevelop (on my Mac) for building / testing / design (XIB) at the same time.

One problem is left with this solution: I need my Mac to “error check compile” my solution.
Some errors are seen by Visual Studio – some not (since I can’t build in VS).

The solution for this comes from telerik – it is called JustCode.

I already use JustCode (as Telerik MVP I was on the internal beta) and I love it.
I never thought this tool could help me with my iPhone development – but I learned that it does this job very well.

Beside the other cool features JustCode brings to Windows Development it also analyzes the code you enter.
It finds (and helps you to solve) problems / error without the need to compile your project.

Once again telerik made my live much easier Happy

JustCode is “open beta” now – so you can download the JustCode for free.
It is “just a refactoring tool like the others” – with one big difference: incredible speed!!!

You can download my little tool (.NET 3.5 WinForms) from here:
VSMTouch (Setup.exe + MSI) 400k
VSMTouch (MSI only) 200k

Update Version that supports multiple projects in one solutin: VSMTouch (Setup + MSI ) 400k

This software is provided “as it is” – no support,….

Getting started:

  1. Install VSMTouch
  2. Create a “RefLibs” directory somewhere on you PC
  3. Copy the MonoTouch DLLs from you Mac to this directory
  4. (optional) Download JustCode from telerik
  5. (optional) Install JustCode
  6. Run VSMTouch
  7. Select the directory where you placed you MonoTouch DLLs as “Reference Path”
  8. Select you MonoTouch solution
  9. Click Create
  10. Open the new oldname$VS.sln solution in Visual Studio

 

Have Fun
Manfred

Tags: ,

MonoTouch | telerik

Powered by BlogEngine.NET 1.5.0.7

RecentPosts