When you create a default Mono for Android project the included resource files are named using a mixture of uppercase and lowercase letters. Please, do NOT follow this naming convention because this is the cause of a variety of unresolved, mostly minor bugs. Instead name all your resource files using all lowercase letters and underscores. It is much safer to follow this practice as opposed to the one presented by Xamarin.
Wednesday, July 25, 2012
Wednesday, July 11, 2012
ActionBarSherlock with Mono for Android
3/7/2013 - I updated the blog post so everything should be current and relevant as of today. This was long overdue, sorry.
For instant gratification try downloading the Xamarin sample project. However this will most likely yield an outdated version of the ActionBarSherlock library.
Today I will explain how to bind the ActionBarSherlock Java library so that it can be used with Mono for Android. ActionBar compatibility is important since over 90% of Android users are still running a pre 3.0 platform. It's a luxury Java programmers have enjoyed for awhile now, which can finally be shared with fellow C# programmers.
The required steps are listed below:
Build the ActionBarSherlock Zip
- First, if necessary, download and install the latest version of Eclipse along with the ADT Plugin.
- Next, download the latest version of ActionBarSherlock. After the download finishes extract the library folder from archive.
- Rename the library folder to actionbarsherlock. In this tutorial, the library folder has been renamed/moved to c:\downloads\actionbarsherlock.
- Start Eclipse and create a new workspace. In this tutorial, I created a workspace located at c:\projects\actionbarsherlock.
- Begin creating a new Android project by clicking File -> New -> Other -> Android -> Android Project From Existing Code. Click Next.
- In the "Root Directory" field, browse to c:\downloads\actionbarsherlock. Check the "Copy projects into workspace" field. Click Finish.
- Click Project -> Clean and wait for Eclipse to finish building the project. Exit Eclipse after the build is complete. If you encounter any compile errors ensure that you are targetting Java 6+.
- Open Windows Explorer, and browse to c:\projects\actionbarsherlock\actionbarsherlock. Select the bin, assets, and res folders and add them to a new Zip file. Name the file actionbarsherlock.zip.
- Now browse to c:\projects\actionbarsherlock\actionbarsherlock\libs and locate the file android-support-v4.jar. No action is required yet, but remember this file location for future use.
- Later, both the actionbarsherlock.zip and android-support-v4.jar files will be copied into Visual Studio.
Create the Binding Library
- Open Visual Studio and create a new JAR Bindings Library project (click File -> New -> Project -> Mono for Android -> Java Bindings Library). Name the project ActionBarSherlockBinding and click OK.
- Click Project -> ActionBarSherlockBinding Properties and change the Target API level to 14+.
- Add a reference to the Mono.Android.Support.v4 binding library by clicking Project -> Add Reference and switching to the .NET tab. Select the Mono.Android.Support.v4 library and click OK.
- Now copy the actionbarsherlock.zip and android-support-v4.jar files (from the previous section) into the Jars folder of the ActionBarSherlockBinding project in Visual Studio.
- In the properties pane, right click on the the actionbarsherlock.zip file and change the Build Action to "LibraryProjectZip". Next, right click on the android-support-v4.jar file and change the Build Action to "ReferenceJar".
- Open the Metadata.xml file located under the the Transforms folder and replace all of its contents with the XML code below. Save and close the file when finished.
<metadata> <!-- Don't bind internal packages/classes --> <remove-node path="/api/package[starts-with(@name, 'com.actionbarsherlock.internal')]" /> <!-- Normalize the API, forced to use underscore to avoid name conflicts --> <attr path="/api/package[@name='android.support.v4.app']" name="managedName">Android.Support.V4.App</attr> <attr path="/api/package[@name='com.actionbarsherlock']" name="managedName">ActionBar_Sherlock</attr> <attr path="/api/package[@name='com.actionbarsherlock.app']" name="managedName">ActionBar_Sherlock.App</attr> <attr path="/api/package[@name='com.actionbarsherlock.view']" name="managedName">ActionBar_Sherlock.View</attr> <attr path="/api/package[@name='com.actionbarsherlock.widget']" name="managedName">ActionBar_Sherlock.Widget</attr> </metadata>
Note: Additional documentation regarding this step can be found here. Lines 6-11 are trivial but line 4 is important.
- Build the solution and verify that there are no errors. There will probably be some warnings but it should still build successfully.
Reference the Binding Library
- In Visual Studio, add a new Android Application project to the existing solution (click File -> Add -> New Project -> Mono for Android -> Android Application). Name the project ActionBarSherlockDemo and click OK.
- Click Project -> ActionBarSherlockDemo Properties and change the Target API level to 14+.
- Add a reference to the binding library by clicking Project -> Add Reference and switching to the Projects tab. Select the ActionBarSherlockBinding project and click OK.
- Also add a reference to the Mono.Android.Support.v4 binding library from the .NET tab of the Add Reference dialog.
- Rebuild the solution and verify that there are no errors.
Extend the SherlockActivity Class
- Open Activity1.cs and change it so that it inherits from the ActionBar_Sherlock.App.SherlockActivity class. Documentation for the ActionBarSherlock library is more or less equivalent to the native ActionBar API.
- Items can be added to the ActionBar by creating a menu resource and overriding the OnCreateOptionsMenu method.
- Generate the AndroidManifest.xml and then edit it and set the SDK and theme like this:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly"> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="14" /> <application android:theme="@style/Theme.Sherlock" /> </manifest>
- Rebuild the solution, deploy to the emulator or device, and congratulations, you're finished!
By Request - An ActionBar Tab Example
This is a quick and dirty example of ActionBar tabs with Mono for Android using ActionBarSherlock. This code is only intended as a demonstration of basic concepts. Please refer to the official Android ActionBar documentation for best practices and for a more complete example.
using System; using Android.OS; using Android.Views; using ActivityAttribute = Android.App.ActivityAttribute; using ActionBarNavigationMode = Android.App.ActionBarNavigationMode; using Android.Support.V4.App; using ActionBar_Sherlock.App; using Tab = ActionBar_Sherlock.App.ActionBar.Tab; namespace ActionBarSherlockDemo { [Activity(Label = "Tab Activity", MainLauncher = true)] public class TabActivity : SherlockFragmentActivity, ActionBar_Sherlock.App.ActionBar.ITabListener { protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.Main); SupportActionBar.NavigationMode = (int)ActionBarNavigationMode.Tabs; SupportActionBar.SetDisplayShowTitleEnabled(true); Tab tab = SupportActionBar.NewTab(); tab.SetTag("TAB1"); tab.SetText("TAB 1"); tab.SetTabListener(this); SupportActionBar.AddTab(tab); tab = SupportActionBar.NewTab(); tab.SetTag("TAB2"); tab.SetText("TAB 2"); tab.SetTabListener(this); SupportActionBar.AddTab(tab); } public void OnTabSelected(Tab tab, Android.Support.V4.App.FragmentTransaction ft) { string tag = tab.Tag.ToString(); Fragment f = SupportFragmentManager.FindFragmentByTag(tag); if (f != null) { ft.Show(f); return; } if (tag == "TAB1") f = new TestFragment1(); else if (tag == "TAB2") f = new TestFragment2(); ft.Add(Resource.Id.fragmentPlaceholder, f, tag); } public void OnTabUnselected(Tab tab, Android.Support.V4.App.FragmentTransaction ft) { string tag = tab.Tag.ToString(); Fragment f = SupportFragmentManager.FindFragmentByTag(tag); if (f != null) { ft.Hide(f); return; } } public void OnTabReselected(Tab tab, Android.Support.V4.App.FragmentTransaction ft) { //Do nothing } } public class TestFragment1 : Fragment { public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { return inflater.Inflate(Resource.Layout.test1, container, false); } } public class TestFragment2 : Fragment { public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { return inflater.Inflate(Resource.Layout.test2, container, false); } } }