Corrado's Blog 2.0

Online thoughts of a technology funatic

Use IDEA IDE for Android UI design with Visual Studio and Xamarin

While Xamarin did a monster job integrating Android and iOS designers in both Visual Studio and Xamarin Studio as soon as your project becomes larger you’ll soon hit their limitations, that why many pro developers end up using native designers for UI design. This post is about how to use IntelliJ IDEA based IDEs for Android UI design together with Visual Studio, following the same approach we use with Blend for Windows development.

Step 1: install your favorite IDE: Android Studio or IntelliJ IDEA (they’re practically the same since Android Studio is based on IntelliJ IDEA)

Step 2: Install XamarIdea extension for Visual Studio, this extension, recently updated for Visual Studio 2015, will make integration between the two IDEs a lot faster, thanks to Egor Bogatov (@EgorBo) for sharing.
No idea if something similar exists for Xamarin Studio (sorry, I’m not an pro Xamarin Studio user)

Step 3: Create a new blank Android app using Visual Studio

image

and wait until initial project skeleton creation process ends.

Step 4: Right-click the Main.axml file inside Resources\layout folder and you should see a new option: Open in IDEA/Android Studio

image

click it and you’ll get an initial configuration dialog that should point to IDEA/Android Studio path, if not select it manually, together with other plugin options

image

click Ok, and you’ll see a warning dialog saying that your project needs some modifications:

image

These modifications are necessary since Android layout files use a different extension (.xml) and project structure is slightly different than Xamarin Android apps, just say yes; unfortunately these changes will prevent you to use the integrated Xamarin Android designer further unless you rename the layout file back to .axml. Click Yes, and you’ll get a final dialog reminding you to recompile your project inside Android IDE and that plugin options are available under Visual Studio’s Tools menu:

image

Step 5: Switch to IDEA IDE and, for sure, rebuild the project

image

On the left you’ll see the project structure, under app node expand the Resources folder and you’ll see the familiar Android folder structure together with your renamed main.xml file.

image

Double click it to open the designer.

image

I won’t go into design detail since there are lots of demo tutorials on JetBrains’s site, just want you to see some of the plus of IDEA and why it is more productive than Visual Studio’s integrated editor/designer.

Step 5: Design

-Select and delete the autogenerated button from design surface.
-Let’s change root LinearLayout to a RelativeLayout using the Component tree window in the upper right corner.

image

-Drag a Plain Text to design surface until top tooltip shows CenterVertical/CenterHorizontal

image

-Set layout_width to match_parent using Properties window (hint: if you need to search for a property just start typing to select matching properties Smile)

-Let use xml editor to add left and right margins: Switch to text, select the EditText and start typing: ma, YES! full intellisense to the rescue!

image

-Do you want to create a style that you can reuse with others EditTexts? just right click the edit text and use Refactor –> Extract Style menu

image

Select the properties you want to export (this dialog will look familiar to Reshaper users) and click OK

image

the layout xml has been changed to:

<EditText android:id="@+id/editText" style="@style/MyEditTextStyle"/>

and a styles.xml file has been created for you under values folder:

image

Of course you can edit the styles.xml file with full intellisense / editors support

image

Step 6-Back to Visual Studio

Save the project and switch back to Visual Studio, your main.xml file is automatically updated, but unfortunately the new files that have been added to the project, like styles.xml in our demo, must be added manually to the project.

Add styles.xml under values folder, compile and continue developing your app using Visual Studio.

Closing:

I’ve just scratched the surface of IDEA design productivity features, I encourage you to give it a try, I’m sure you’ll love it.

Have fun exploring!

PS: Did I tell you that IDEA renders AppCompat’s widgets instead of a boring dark gray box? Winking smile

Xamarin build server is too old?

This morning, no idea why, trying to compile a Xamarin.iOS app resulted in an error “Xamarin build server is tool old…” apparently without any reason since nothing has changed on my machine during the weekend. Tried also connecting to a different Mac machine but error was still there while compiling using Xamarin Studio on the Mac machine was ok.
After some investigation I’ve found the solution: looks like that “someone” changed my proxy settings (probably Fiddler) and that was causing the weird message.

Turning it off did the trick.

image

Hope this will help you in case you see this weird message too.

Declarative event handlers in Xamarin Android

In Android applications the UI components are totally isolated from associated activity so to ‘glue’ them you need to follow a ‘javascript like’ approach: find the element fist  and then interact with it. Let’s say you have a .axml file containing a button with id MyButton

 <Button
        android:id="@+id/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello" />

in the associated activity, to subscribe its Click event you have to write this code:

public class MainActivity : Activity
 {
  int count = 1;

  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);

   SetContentView(Resource.Layout.Main);
   Button button = FindViewById<Button>(Resource.Id.MyButton);
   button.Click += button_Click;
  }

  void button_Click(object sender, EventArgs e)
  {
   (sender as Button).Text = string.Format("{0} clicks!", count++);
  }
 }

If you, like me, come from XAML and love the declarative approach I’ve got a good new for you, there’s an alternative, just follow this steps:

1-Add a reference to Mono.Android.Export library

2-Declare you handler in .axml file this way:

<Button
        android:id="@+id/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello"
    android:onClick="myHandler"/>

3-Refactor the code in associated activity this way:

public class MainActivity : Activity
 {
  int count = 1;

  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);

   SetContentView(Resource.Layout.Main);
  }

  [Java.Interop.Export("myHandler")]
  public void button_Click(View v)
  {
   (v as Button).Text = string.Format("{0} clicks!", count++);
  }
 }

And you’re done!

As you see the trick is to export the function, using the Java.Interop.Export attribute that also allows you to use a export the method with a different name, leave it empty if you don’t need to differentiate.

Lot simpler, and cleaner… IMHO Smile

TranslateTo issue with Xamarin Forms 1.2.3

This Xamarin Forms snippets shifts a button left when clicked and restores it back when dialog is dismissed.

public static Page CreateMainPage3()
  {
   StackLayout container = new StackLayout() { Orientation = StackOrientation.Vertical };
   Button btn = new Button() { Text = "Ok" };
   btn.Clicked += async (s, e) =>
   {
    await btn.TranslateTo(-btn.Width, 0, 500);
    await MainPage.DisplayAlert("Test", "Hello", "Ok", "Cancel");
    await btn.TranslateTo(0, 0, 500);
   };

   container.Children.Add(btn);
   
   return MainPage = new ContentPage()
   {
    Content = container,
    Padding = new Thickness(10, 20, 10, 20)
   };
  }

Easy right? unfortunately it doesn’t work on Android (it is ok on Windows Phone and iOS) with Xamarin Forms version 1.2.3

The workaround is quite easy: use LayoutTo instead of TranslateTo, following code works on all platforms.

...
btn.Clicked += async (s, e) =>
   {
    Rectangle defaultRect = btn.Bounds;
    await btn.LayoutTo(new Rectangle(-btn.Width, btn.Y, btn.Width, btn.Height), 500);
    await MainPage.DisplayAlert("Test", "Hello", "Ok", "Cancel");
    await btn.LayoutTo(defaultRect, 500);
   };
 ...

Add “intellisense” to Xamarin .axml files

When you manually edit .axml files inside Visual Studio 2013 you don’t have any minimal intellisense support, and, as Visual Studio user, you know how frustrating is typing without any kind of help.

image

Since editing the same file using the XML editors brings you a ‘partial’ intellisense i tried to find what was the difference and finally found how to enable it also inside Android designer source view.

  1. 1-With Designer in source view, select Visual Studio’s xml menu and then Schemas…
  2. image
  3. 2-Navigate to C:\Program Files (x86)\MSBuild\Xamarin\Android and select android-layout-xml.xsd file.
  4. 3-Click Ok to confirm and dismiss the dialog.
  5. Here’s what you now get when typing android: in source view:
  6. image
  7. Of course, this is not the same experience we have in XAML, but better than nothing.
  8. After adding the schema, the first time you add a new Android layout Visual Studio asks you to trust a new file, just select Trust and everything will work as usual in future.
  9. Enjoy!

Xamarin: Infinite scrolling list in iOS app

I’ve spend the last few weeks studying Xamarin, not because I’m considering abandoning the Windows platform but because I think it’s clear that, as developer, we need to take note that there are other big platforms with which it is right to live with.

While not yet mature and in some cases quite cumbersome, my experience with it was highly positive and I absolutely recommend it in case you need to create Android and/or iOS applications.

This post comes from a need I had during development of a iOS application: Create an infinite scrolling list of data starting from paged data coming from a REST service.

Note: I’m a Xamarin beginner so this might not be the perfect solution, but it worked fine in my case.

To get infinite scrolling I created a custom UITableSource

public class BookedCarsTableViewSource : UITableViewSource
    {
        private readonly DataService dataService;
        private readonly PagedResult<BookedCarResponse> firstPage;
        private readonly List<BookedCarResponse> bookedCars;
        private int pageIndex;
        private bool isFetching;

        private const string cellId = "bookedCarCell";

        public BookedCarsTableViewSource(DataService dataService, PagedResult<BookedCarResponse> firstPage)
        {
            this.dataService = dataService;
            this.firstPage = firstPage;
            this.bookedCars = firstPage.Result.ToList();
            this.pageIndex = 0;
        }

        public override int RowsInSection(UITableView tableview, int section)
        {
            return (int)Math.Max(this.bookedCars.Count, this.firstPage.TotalCount);
        }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            int index = indexPath.Row;
            UITableViewCell cell = tableView.DequeueReusableCell(cellId) ?? new UITableViewCell(UITableViewCellStyle.Subtitle, cellId);
            BookedCarResponse bookedCar = this.bookedCars[index];
            cell.TextLabel.Text = bookedCar.CarPlate;
            cell.DetailTextLabel.Text = bookedCar.CompanyName;            
            if (!this.isFetching && this.pageIndex < this.firstPage.TotalPages && index > this.bookedCars.Count * 0.8)
            {
                this.isFetching = true;
                Task.Factory.StartNew(this.LoadMore);
            }

            return cell;
        }

        private async void LoadMore()
        {
            this.pageIndex++;
            var nextPage = await this.dataService.GetBookedCars(this.pageIndex, this.firstPage.PageSize);
            this.bookedCars.AddRange(nextPage.Result);
            this.isFetching = false;
        }
    }

As you see the trick is inside GetCell, when requested index is near the end of currently available items I spin a new request and add results to bookedCars collection.

In order to get initial block of items I used this code inside related controller:

public class BookedCarsScreenController : UITableViewController
    {
        private PagedResult<BookedCarResponse> firstPage;

        public override async void ViewDidLoad()
        {
            base.ViewDidLoad();
            this.firstPage = await DataManager.Current.GetBookedCars(0, 30);
            this.TableView.Source = new BookedCarsTableViewSource(DataManager.Current, firstPage);
            this.TableView.ReloadData();
        }
    }

I had to invoke TableView’s ReloadData otherwise list was appearing initially empty.

Note that since I’m using Subtitle layout I didn’t find the way to use  iOS 6 automatic cell reuse mode.

Hope it helps! Smile