Follow this walkthrough to migrate your Crosslight Android Classic to Crosslight Android Material. At the end of this tutorial, you should have the following result:

Samples:

basic-inventory.zip

Follow these steps:

Prerequisites

It is recommended that you have read through these conceptual topics in order to get a better understanding:

To use this walkthrough, you will need to use at least Crosslight version 5.0.500.543 in order to achieve the desired result.

Let's get started. 

Configuring Your Project

  1. Open your Crosslight Android Classic application. In this walkthrough, let's try to migrate the MyInventory classic sample to the new Crosslight Android Material.
  2. Open the project properties, and set the TargetFramework to Android 5.0 (Lollipop)
  3. Afterwards, set the Minimum Android version to 4.0.3 (API Level 15) and Target Android version (API Level 21)
  4. Install the Crosslight Android v7 NuGet Package using the Intersoft Package Manager Console. 

    To learn more on how to use Crosslight NuGet Packages, see Introduction to Crosslight NuGet Packages.

    To use the Intersoft Package Manager Console, you need to have properly installed Intersoft Mobile Studio 2016 and above.

  5. Ensure that the Crosslight references and its dependencies are properly installed.

Applying Crosslight Android Material Theme

  1. To properly incorporate Android Material theme to your application, you can simply use one of the two built-in Crosslight themes that are designed specifically for Material Design: Theme.Crosslight.Material and Theme.Crosslight.Material.Light. It is most recommended to use the default Theme.Crosslight.Material.Light theme. 

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-sdk android:minSdkVersion="15" />
        <application android:theme="@style/Theme.Crosslight.Material.Light" android:label="MyInventory"></application>
    </manifest>
  2. Copy-paste the following code to the colors.xml file located inside Android/Resources/values/ folder.

    <?xml version="1.0" encoding="utf-8" ?>
    <resources>
      <color name="primary">#673AB7</color>
      <color name="accent">#7E57C2</color>
      <color name="navigation_bar">#9575CD</color>
      <color name="primary_dark">#7E57C2</color>
      <color name="window_background">#eaeaea</color>
      <color name="action_menu_background">#673AB7</color>
      <color name="window_dark_background">#000000</color>
      <color name="window_light_background">#ffffff</color>
    
      <color name="action_menu_foreground">#ffffff</color>
      <color name="button_foreground">#ffffff</color>
    
      <color name="progress_dialog_background">#673AB7</color>
      <color name="progress_text_color">#ffffff</color>
      <color name="progress_bar_color">#ffffff</color>
      <color name="progress_text_color_inverse">#7E57C2</color>
      <color name="progress_bar_color_inverse">#7E57C2</color>
    </resources>
  3. Clean up old styles or resources as they are no longer relevant.

Converting Your Activities and Fragments to Crosslight Material Fragments

There are several fundamental principles when converting classic Activities to new Material Fragments:

  • Activity is now only used as view container and very minimal Activities definitions are needed. In most cases, you'll only need StartActivity, DrawerActivity, and SearchActivity.
  • Configuring layout id and other properties and behaviors still use property overrides.
  • Assigning values that are considered as settings should be done in the Initialize method (override as needed) in the Fragment level and you can directly set the property there.
  • To configure bar items, you can still use menu AXML. Although, it is very much recommended to use the new Crosslight Android Material's new API with predefined CommandItemTypes which will allow you to define bar items easily.
  • Crosslight Android Material provides you with some built-in layout and styles so you do not need to provide it, unless you want to change it. See the complete reference here: Crosslight Android Material Theme Reference.
  • To learn how to configure more settings and behaviors introduced in Material Fragment, see Defining Android Material Views.
  1. Converting ListActivity
    Since the ListActivity is the main Activity, this needs to be converted into an Activity for view container and Fragment as it content view. For example, here's how the old ItemListActivity looks like.

    using Android.App;
    using Android.Content.PM;
    using Intersoft.Crosslight;
    using Intersoft.Crosslight.Android;
    using MyInventory.ViewModels;
    
    namespace MyInventory.Android
    {
        [ImportBinding(typeof(ItemListBindingProvider))]
        [Activity(Label = "My Inventory", LaunchMode = LaunchMode.SingleTop, Icon = "@drawable/icon")]
        public class ItemListActivity : SearchableListActivity<ItemListViewModel>
        {
            #region Properties
    
            protected override ContextualActionBarSettings ContextualActionBarSettings
            {
                get
                {
                    return new ContextualActionBarSettings
                    {
                        ActionBarLayoutId = Resource.Layout.contextualactionbarlayout,
                        MenuCheckAllId = Resource.Id.MenuCheckAll,
                        MenuMoreId = Resource.Id.MenuMore,
                        PopupMenuLayoutId = Resource.Layout.popupmenulayout
                    };
                }
            }
    
            public override EditingOptions EditingOptions
            {
                get { return EditingOptions.AllowEditing | EditingOptions.AllowMultipleSelection; }
            }
    
            protected override int GroupItemLayoutId
            {
                get { return Resource.Layout.ItemGroupLayout; }
            }
    
            public override ListViewInteraction InteractionMode
            {
                get { return ListViewInteraction.Navigation; }
            }
    
            protected override int ListItemLayoutId
            {
                get { return Resource.Layout.ItemListLayout; }
            }
    
            protected override int MenuLayoutId
            {
                get { return Resource.Layout.actionbarlistlayout; }
            }
    
            protected override int SearchButtonId
            {
                get { return Resource.Id.SearchButton; }
            }
    
            public override string SearchScope
            {
                get { return "Name"; }
            }
    
            #endregion
    
            #region Methods
    
            protected override void InitializeView()
            {
                base.InitializeView();
    
                this.RegisterViewIdentifier("TableView", this.ListView);
            }
    
            #endregion
        }
    }


    Here's the new file AppCompatActivity that will act as the view container. You can safely remove the previous ItemListActivity and replace it with the new AppCompatActivity.

    using System;
    using Android.App;
    using Android.Runtime;
    using Intersoft.Crosslight;
    using Intersoft.Crosslight.Android.v7;
    using MyInventory.ViewModels;
    
    namespace MyInventory.Android
    {
        [Activity()]
        public class AppActivity : AppCompatActivity<ItemListViewModel>
        {
            #region Constructors
    
            public AppActivity()
            {
    
            }
    
            public AppActivity(IntPtr javaReference, JniHandleOwnership transfer)
                : base(javaReference, transfer)
            {
    
            }
            #endregion
        }
    }


    Introduce a new ItemListFragment that inherits the new SearchableRecyclerViewFragment available in the v7 library.

    using System;
    using Android.Graphics;
    using Android.Graphics.Drawables;
    using Android.Runtime;
    using Intersoft.Crosslight;
    using Intersoft.Crosslight.Android;
    using Intersoft.Crosslight.Android.v7;
    using Intersoft.Crosslight.Android.v7.ComponentModels;
    using MyInventory.ViewModels;
    using EditAction = Intersoft.Crosslight.Android.v7.ComponentModels.EditAction;
    
    namespace MyInventory.Android
    {
        [ImportBinding(typeof(ItemListBindingProvider))]
        [RegisterNavigation(DeviceKind.Phone)]
        public class ItemListFragment : SearchableRecyclerViewFragment<ItemListViewModel>
        {
            #region Constructors
    
            public ItemListFragment()
            {
    
            }
    
            public ItemListFragment(IntPtr javaReference, JniHandleOwnership transfer)
                : base(javaReference, transfer)
            {
    
            }
    
            #endregion
    
            #region Properties
    
            protected override int ItemLayoutId
            {
                get { return Resource.Layout.item_layout; }
            }
    
            #endregion
    
            #region Methods
    
            protected override void Initialize()
            {
                base.Initialize();
    
                this.ImageLoaderSettings.AnimateOnLoad = true;
                this.Appearance.Background = new ColorDrawable(Color.WhiteSmoke);
                this.ShowGroupSeparator = false;
    
                // Defines floating action button.
                this.FloatingActionButtons.Add(new FloatingActionButton("AddButton")
                {
                    Position = FloatingActionButtonPosition.BottomRight,
                    CommandItemType = CommandItemType.Add,
                    Direction = FloatingActionButtonDirection.Up,
                    HideOnScrollUp = true
                });
    
                // Defines contextual action.
                ListContextualToolbarSettings settings = this.ContextualToolbarSettings as ListContextualToolbarSettings;
                if (settings != null)
                {
                    settings.Mode = ContextualMode.Default;
                    settings.CheckAllEnabled = true;
                    settings.CheckAllMargin = 4;
                    settings.BarItems.Add(new BarItem("DeleteButton", "Delete"));
                    settings.BarItems.Add(new BarItem("MarkSoldButton", "Mark As Sold"));
                }
    
                // Defines editing action from swipe gesture.
                this.EditActions.Add(new EditAction("Sold"));
                this.EditActions.Add(new EditAction("Delete", true));
    
                // Recycler View configuration
                this.InteractionMode = ListViewInteraction.Navigation;
                this.EditingOptions = EditingOptions.AllowEditing | EditingOptions.AllowMultipleSelection;
    
                // Defines shared elements
                this.SourceSharedElementIds.Add(Resource.Id.Icon);
    
                this.AddBarItem(new BarItem("SearchButton", CommandItemType.Search));
    
                this.FilterScope = "Name";
                this.IconId = Resource.Drawable.ic_toolbar;
            }
    
            #endregion
        }
    }
  2. Converting ItemEditActivity. The old FormActivity used to look like this.

    using Android.App;
    using Intersoft.Crosslight.Android;
    using MyInventory.ViewModels;
    
    namespace MyInventory.Android
    {
        [Activity(Label = "Edit Item", Icon = "@drawable/icon")]
        public class ItemEditActivity : FormActivity<ItemEditorViewModel>
        {
            #region Properties
    
            protected override int MenuLayoutId
            {
                get { return Resource.Layout.actionbareditinglayout; }
            }
    
            protected override bool ShowActionBarUpButton
            {
                get { return true; }
            }
    
            #endregion
        }
    }


    You can safely delete the file altogether and replace it with the new FormFragment. With the new Crosslight v7 library, you don't have to deal with creating Activities anymore. Also, you don't have to specify the ShowActionBarUpButton behavior as this is automatic. You need to provide a new constructor overload that accepts one IntPtr object and one JniHandleOwnership object as this is needed for Fragment initialization.

    using System;
    using Android.Runtime;
    using Intersoft.Crosslight;
    using Intersoft.Crosslight.Android.v7;
    using MyInventory.ViewModels;
    
    namespace MyInventory.Android
    {
        [ImportBinding(typeof(ItemListBindingProvider))]
        public class ItemEditFragment : FormFragment<ItemEditorViewModel>
        {
            #region Constructors
    
            public ItemEditFragment()
            {
    
            }
    
            public ItemEditFragment(IntPtr javaReference, JniHandleOwnership transfer)
                : base(javaReference, transfer)
            {
    
            }
    
            #endregion
    
            #region Methods
    
            protected override void Initialize()
            {
                base.Initialize();
    
                this.AddBarItem(new BarItem("SaveButton", CommandItemType.Done));
            }
    
            #endregion
        }
    }

    To add the bar item, you can simply take advantage of the new AddBarItem method that is provided in the new Fragment library. You can use this API in all Fragments existed in the new v7 library. Now that you've got your new FormFragment ready, let's proceed by converting ViewImageActivity next.

  3. The old ViewImageActivity used to look like this.

    using Android.App;
    using Intersoft.Crosslight;
    using Intersoft.Crosslight.Android;
    using MyInventory.ViewModels;
    
    namespace MyInventory.Android.Activities
    {
        [Activity(Label = "View Image", Icon = "@drawable/icon")]
        [ImportBinding(typeof(ItemDetailBindingProvider))]
        [RegisterNavigation("PhotoDetail")]
        public class ViewImageActivity : Activity<ItemDetailViewModel>
        {
            #region Constructors
    
            public ViewImageActivity()
                : base(Resource.Layout.viewimagelayout)
            {
    
            }
    
            #endregion
        }
    }

    Let's convert this to a Fragment instead.

    using System;
    using Android.Runtime;
    using Intersoft.Crosslight;
    using Intersoft.Crosslight.Android.v7;
    using MyInventory.ViewModels;
    
    namespace MyInventory.Android
    {
        [ImportBinding(typeof(ItemDetailBindingProvider))]
        [RegisterNavigation("PhotoDetail")]
        public class ViewImageFragment : Fragment<ItemDetailViewModel>
        {
            #region Constructors
    
            public ViewImageFragment()
            {
    
            }
    
            public ViewImageFragment(IntPtr javaReference, JniHandleOwnership transfer)
                : base(javaReference, transfer)
            {
    
            }
    
            #endregion
    
            #region Properties
    
            protected override int ContentLayoutId
            {
                get { return Resource.Layout.view_image_layout; }
            }
    
            #endregion
        }
    }

    At a first glance, the new Fragment definition seems longer and more tedious. However, it is more consistent. Previously, it was quite confusing determining which view context can accept a layout ID in the constructor, and which ones cannot. In this new library, the process is streamlined to overriding ContentLayoutId instead, making it more consistent, no matter what view context you're dealing with. Next, let's upgrade the look and feel of the existing item list to use CardView. Open up the item_layout.axml inside the Resources/layout folder and use the following code.

    <?xml version="1.0" encoding="utf-8"?>
    <intersoft.crosslight.android.v7.CardView xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:foreground="?android:attr/selectableItemBackground"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:cardElevation="2dp">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="80dp">
            <ImageView
                android:layout_width="72dp"
                android:layout_height="72dp"
                android:id="@+id/Icon"
                android:layout_margin="4dp"
                android:gravity="center_vertical"
                android:layout_centerVertical="true" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@id/Icon"
                android:gravity="center_vertical"
                android:layout_centerVertical="true"
                android:orientation="vertical">
                <TextView
                    android:textAppearance="?android:attr/textAppearanceMedium"
                    android:id="@+id/TextLabel"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:singleLine="true" />
                <TextView
                    android:textAppearance="?android:attr/textAppearanceSmall"
                    android:id="@+id/Text2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:singleLine="true" />
            </LinearLayout>
        </RelativeLayout>
    </intersoft.crosslight.android.v7.CardView>

    You can now take advantage of modern view libraries and properties available in v7 libraries, such as the CardView and view properties like app:cardElevation to give your apps a modern Material look.

Conclusion

Congratulations! You've just finished migrating your MyInventory application from classic android to Material Android.

Sample

You can check out the old project here: http://git.intersoftsolutions.com/projects/CROS/repos/samples/browse/MyInventory and the new project here: http://git.intersoftsolutions.com/projects/CS/repos/basic-inventory/browse.

If you wish to run the sample, simply download the new project and open using Xamarin Studio or Visual Studio and hit Run.

 

Related Topics