Simple UIScrollView / CATiledLayer PDF Example (MonoTouch version)

Monday, 28 February 2011 04:52 by Krumelur

Searching the web for a simple example how to preview a PDF page using a CATiledLayer, I found some code on Olive Toast's blog: http://www.olivetoast.com/blog/2009/08/simple-uiscrollview-catiledlayer-pdf-example/

A very small and lean solution to demonstrate viewing, zooming and scrolling a page of a PDF. The code can easily be extended to a full PDF viewer which uses only very little memory.

I went and MonoTouched the example. You can download the sample's main file here PdfDemo.cs.zip (1,59 kb) . Also check out the source below:

 

using System;
using MonoTouch.Foundation;
using System.IO;
using MonoTouch.UIKit;
using System.Text;
using System.Diagnostics;
using System.Drawing;
using MonoTouch.CoreGraphics;
using MonoTouch.CoreAnimation;

namespace iOSTest
{
    public class Application
    {
        static void Main ( string[] args )
        {
            UIApplication.Main ( args );
        }
    }

    // The name AppDelegate is referenced in the MainWindow.xib file.
    public partial class AppDelegate : UIApplicationDelegate
    {
        // This method is invoked when the application has loaded its UI and its ready to run
        public override bool FinishedLaunching ( UIApplication app, NSDictionary options )
        {
            NSUrl u = NSUrl.FromString("http://www.tfl.gov.uk/assets/downloads/standard-tube-map.pdf");
            this.o = new AppDelegate.PdfViewController(u);
            this.o.View.Frame = new RectangleF(0, 20, 320, 480 - 20);
            window.AddSubview(this.o.View);
           
            window.MakeKeyAndVisible();       
            return true;
        }
       
        private PdfViewController o;
       
        /// <summary>
        /// Previews first page of a PDF.
        /// </summary>
        public class PdfViewController : UIViewController
        {
            public PdfViewController(NSUrl oUrl) : base()
            {
                this.oUrl = oUrl;
            }
           
            private NSUrl oUrl;
            private UIView oContentView;
            private CGPDFDocument oPdfDoc;
            private CGPDFPage oPdfPage;
           
            public override void ViewDidLoad ()
            {
                base.ViewDidLoad ();
                Console.WriteLine("Loading PDF: {0}", this.oUrl.ToString());
                this.oPdfDoc = CGPDFDocument.FromUrl(this.oUrl.ToString());
               
                // For demo purposes, show first page only.
                this.oPdfPage = this.oPdfDoc.GetPage(1);
               
                RectangleF oPdfPageRect = this.oPdfPage.GetBoxRect(CGPDFBox.Crop);
               
                // Setup tiled layer.
                CATiledLayer oTiledLayer = new CATiledLayer();
                oTiledLayer.Delegate = new TiledLayerDelegate(this);
                oTiledLayer.TileSize = new SizeF(1024f, 1024f);
                oTiledLayer.LevelsOfDetail = 5;
                oTiledLayer.LevelsOfDetailBias = 5;
                oTiledLayer.Frame = oPdfPageRect;
               
                this.oContentView = new UIView(oPdfPageRect);
                this.oContentView.Layer.AddSublayer(oTiledLayer);
               
                this.View = new UIView();
                this.View.AutoresizingMask =
                    UIViewAutoresizing.FlexibleWidth
                    | UIViewAutoresizing.FlexibleHeight
                    | UIViewAutoresizing.FlexibleTopMargin
                    | UIViewAutoresizing.FlexibleBottomMargin
                    | UIViewAutoresizing.FlexibleLeftMargin
                    | UIViewAutoresizing.FlexibleRightMargin;
                this.View.AutosizesSubviews = true;
               
#if DEBUG
                this.View.Layer.BorderColor = UIColor.Red.CGColor;
                this.View.Layer.BorderWidth = 2f;
#endif
               
                // Prepare scroll view.
                UIScrollView oScrollView = new UIScrollView(this.View.Frame);
                oScrollView.AutoresizingMask = this.View.AutoresizingMask;
                oScrollView.Delegate = new ScrollViewDelegate(this);
                oScrollView.ContentSize = oPdfPageRect.Size;
                oScrollView.MaximumZoomScale = 1000f;
                oScrollView.MinimumZoomScale = 0.1f;
                oScrollView.AddSubview(this.oContentView);
               
                this.View.AddSubview(oScrollView);
            }
           
            public override void ViewDidUnload ()
            {
                base.ViewDidUnload ();
                this.oPdfPage.Dispose();
                this.oPdfDoc.Dispose();
                this.oContentView.Dispose();
                this.oPdfPage = null;
                this.oPdfDoc = null;
                this.oContentView = null;
            }
           
            public class TiledLayerDelegate : CALayerDelegate
            {
                public TiledLayerDelegate(PdfViewController oParentController) : base()
                {
                    this.oParentController = oParentController;
                }
               
                private PdfViewController oParentController;
               
                public override void DrawLayer (CALayer layer, CGContext context)
                {
                    context.SaveState();
                    context.SetRGBFillColor( 1.0f, 1.0f, 1.0f, 1.0f);
                    context.FillRect( context.GetClipBoundingBox());
                    context.TranslateCTM( 0.0f, layer.Bounds.Size.Height);
                    context.ScaleCTM( 1.0f, -1.0f);
                    context.ConcatCTM( this.oParentController.oPdfPage.GetDrawingTransform(CGPDFBox.Crop, layer.Bounds, 0, true));
                    context.DrawPDFPage(this.oParentController.oPdfPage);
                    context.RestoreState();
                }
            }
           
            public class ScrollViewDelegate : UIScrollViewDelegate
            {
                public ScrollViewDelegate(PdfViewController oParentController) : base()
                {
                    this.oParentController = oParentController;
                }
               
                private PdfViewController oParentController;
               
                public override UIView ViewForZoomingInScrollView (UIScrollView scrollView)
                {
                    return this.oParentController.oContentView;
                }
            }
        }
       
    }
}


iOS: Store passwords in the keychain using MonoTouch

Tuesday, 1 February 2011 05:20 by Krumelur

EDIT: I have just updated this post a bit. Storing a password now supports data encryption. This means you can specify when the stored password is accessible (e.g. only if the device is unlocked).

After searching the web a lot I could not find a resource providing examples on how to store a password securely on an iOS device. StackOverflow.com pointed me to the iOS's KeyChain and I found this example which does the magic using ObjectiveC: https://github.com/ldandersen/scifihifi-iphone/

As I want to give the community something back I offer a MonoTouch implementation inspired by to code referenced above for download here.

My code contains three static methods:

/// <summary>
/// Deletes a username/password record.
/// </summary>
/// <param name="sUsername">the username to query. May not be NULL.</param>
/// <param name="sService">the service description to query. May not be NULL.</param>
/// <returns>SecStatusCode.Success if everything went fine, otherwise some other status</returns>
public static SecStatusCode DeletePasswordForUsername ( string sUsername, string sService )

/// <summary>
/// Sets a password for a specific username.
/// </summary>
/// <param name="sUsername">the username to add the password for. May not be NULL.</param>
/// <param name="sPassword">the password to associate with the record. May not be NULL.</param>
/// <param name="sService">the service description to use. May not be NULL.</param>
/// <param name="eSecAccessible">defines how the keychain record is protected</param>
/// <returns>SecStatusCode.Success if everything went fine, otherwise some other status</returns>
public static SecStatusCode SetPasswordForUsername ( string sUsername, string sPassword, string sService, SecAccessible eSecAccessible )

/// <summary>
/// Gets a password for a specific username.
/// </summary>
/// <param name="sUsername">the username to query. May not be NULL.</param>
/// <param name="sService">the service description to use. May not be NULL.</param>
/// <returns>
/// The password or NULL if no matching record was found.
/// </returns>
public static string GetPasswordForUsername ( string sUsername, string sService )

Find the MonoTouch C# file attached for download with this post.

2011_2_KeyChain_MT.cs (4,69 kb)

iOS: UIAlertView with a UITextField - a MonoTouch implementation

Friday, 28 January 2011 16:26 by Krumelur

I have searched the web for a way to subclass UIAlertView and add a UITextField to it, like Apple does it in the iTUnes store.

Apple however uses a private call which we "normal" developers are not allowed to use. So I came up with some code. It is not perfect yet, especially when rotating the device, but feel free to improve it.

I tested it on iPad using iOS 4.2 only.

 

using System;
using MonoTouch.UIKit;
using System.Drawing;
using System.Collections.Generic;
using MonoTouch.Foundation;
using MonoTouch.CoreGraphics;

namespace iBrainloop.Views
{
    public class InputAlertView : UIAlertView
    {
        public InputAlertView ( string sTitle, string sMessage, string sCancel, params string[] aOtherButtons ) : base( sTitle, sMessage, null, sCancel, aOtherButtons )
        {
            this.KeyboardType = UIKeyboardType.ASCIICapable;
            this.KeyboardReturnType = UIReturnKeyType.Done;
            this.InputFieldTextAlignment = UITextAlignment.Center;
            this.InputFieldCapitalization = UITextAutocapitalizationType.AllCharacters;
            this.InputFieldAutocorrection = UITextAutocorrectionType.No;
            this.InputFieldIsSecure = false;
            this.InputFieldPlaceholder = "";
            this.Presented += delegate
            {
                this.oTxtInput.BecomeFirstResponder (  );
                this.Transform = CGAffineTransform.MakeTranslation ( 0, -100 );
            };
        }
       
        private UITextField oTxtInput;
       
        // If the view has been dismissed, this property contains the entered text.
        public string EnteredText
        {
            get
            {
                return this.oTxtInput.Text;
            }
        }
       
        public UIKeyboardType KeyboardType
        {
            get;
            set;
        }
       
        public UIReturnKeyType KeyboardReturnType
        {
            get;
            set;
        }
       
        public UITextAlignment InputFieldTextAlignment
        {
            get;
            set;
        }
       
        public UITextAutocapitalizationType InputFieldCapitalization
        {
            get;
            set;
        }
       
        public UITextAutocorrectionType InputFieldAutocorrection
        {
            get;
            set;
        }
       
        public bool InputFieldIsSecure
        {
            get;
            set;
        }
       
        public string InputFieldPlaceholder
        {
            get;
            set;
        }
       
        public override void Show ()
        {
            base.Show ( );
           
            this.oTxtInput = new UITextField ( new System.Drawing.RectangleF ( 12f, 75f, 260f, 25f ) );
            this.oTxtInput.BackgroundColor = UIColor.White;
            this.oTxtInput.UserInteractionEnabled = true;
            this.oTxtInput.KeyboardType = this.KeyboardType;
            this.oTxtInput.ReturnKeyType = this.KeyboardReturnType;
            this.oTxtInput.TextAlignment = this.InputFieldTextAlignment;
            this.oTxtInput.AutocapitalizationType = this.InputFieldCapitalization;
            this.oTxtInput.AutocorrectionType = this.InputFieldAutocorrection;
            this.oTxtInput.SecureTextEntry = this.InputFieldIsSecure;
            this.oTxtInput.Placeholder = this.InputFieldPlaceholder;
           
            this.Frame = new RectangleF ( this.Frame.X, this.Frame.Y, this.Frame.Size.Width, this.Frame.Size.Height + this.oTxtInput.Bounds.Height + 20 );
           
            this.fInitialHeight = this.Bounds.Height;
            // Increase height of the alert view to have space for the textfield.
            this.AddSubview ( this.oTxtInput );
            this.Superview.SetNeedsLayout (  );
            this.SetNeedsLayout (  );
            this.fInitialY = this.Frame.Y;
        }
        private float fInitialHeight;
        private float fInitialY;
       
        public override void LayoutSubviews ()
        {
            base.LayoutSubviews (  );
            this.Frame = new RectangleF ( this.Frame.X, this.fInitialY - 80, this.Frame.Size.Width, this.fInitialHeight );
            foreach ( UIView oSubView in this.Subviews )
            {
                if ( oSubView is UITextField )
                {
                    oSubView.Frame = new RectangleF ( oSubView.Frame.X, this.Bounds.Height - oSubView.Frame.Height - 65, oSubView.Frame.Width, oSubView.Frame.Height );
                    continue;
                }
                if ( oSubView is UIControl )
                {
                    oSubView.Frame = new RectangleF ( oSubView.Frame.X, this.Bounds.Height - oSubView.Frame.Height - 20, oSubView.Frame.Width, oSubView.Frame.Height );
                }
            }
        }
    }
}

MultiMode LED Lampe für iPhone 4 jetzt im AppStore

Monday, 20 September 2010 19:32 by Krumelur

Nach langem Review seitens Apple (es ist ja auch eine riesen Anwendung...), ist die MultiMode LED Lampe nun endlich im AppStore verfügbar:

Info zur MultiMode LED Lampe anzeigen

Viel Spaß damit!

Support per Email unter rene.ruppert@gmail.com.