I've been reading tutorials and articles on how to create a sort of UserControl for Android Xamarin and I still have no clue on how to do it due to the poor explanation of those tutorials/articles or due to the lack of examples.
What I need is to create an UserControl that will hold some info about a store ( an image, store name, store address, store contact, and a few more details, but these should be enough to build a sample here ).
ASCII Sample:
+-----------------------------------+
| +----------+                      |
| |/ / / / / |  STORE NAME          |
| | / / / / /|                   \  |
| |/ / / / / |  STORE ADDRESS     > |
| | / / / / /|                   /  |
| |/ / / / / |  STORE CONTACT       |
| +----------+                      |
+-----------------------------------+
Now, how would I build this on Android Xamarin? I get that, from the tutorials I've seen, I need a layout and a code-behind (duh!), but exactly which one - Activity or Fragment? Even though in the Visual Studio when I'm editing the layout file it shows the layout within a phone frame that doesn't mean that I'm building an page layout rather that the UserControl layout?
Solution found
With the answer given by Jon Douglas, I was able to do what I wanted.
I'll leave here the sample code necessary to replicate the layout I've made above and some explanation - maybe it can help someone later.
To the store buttons list I needed to create 4 files:
- The Buttonlayout template, which would hold the structure of the button;
- The ListViewadapter, which will contain the code necessary to the initialization of theListViewand events;
- The Stores layout, which will have basically only a ListViewthat will be populated with a list of Stores;
- The Stores fragment, which will have the logic when this specific fragment is used.
Although I'm using fragments, I don't think this would be that much difference between an sample using activities.
Button Layout Template
<?xml version="1.0" encoding="utf-8"?>
<!-- The root of the layout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingLeft="5dp"
     android:paddingRight="5dp" >
    <!-- Needed to add the elements side-by-side,
        for some reason didn't work to me setting
        the `orientation` on the root layout -->
    <LinearLayout
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="5dp" >
        <!-- The store image -->
        <ImageView
             android:id="@+id/StoreImage"
             android:layout_gravity="top"
             android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="55"
             android:paddingTop="0dp" />
        <!-- This `LinearLayout` will hold the store name,
             address and contact vertically -->
        <LinearLayout
             android:orientation="vertical"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="100"
             android:layout_marginLeft="15px" >
            <!-- The store name -->
            <TextView
                 android:textAppearance="?android:attr/textAppearanceMedium"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:textColor="#FFDCBB73"
                 android:id="@+id/StoreName"
                 android:layout_marginBottom="5dp" />
            <!-- The store address -->
            <LinearLayout
                 android:orientation="horizontal"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" >
                <!-- Store address label -->
                <TextView
                     android:text="@string/AddressText"
                     android:textAppearance="?android:attr/textAppearanceSmall"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:textColor="#FF9D9D9D"
                     android:layout_marginRight="5dp" />
                <!-- Store address value -->
                <TextView
                     android:textAppearance="?android:attr/textAppearanceSmall"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:textColor="#FF9D9D9D"
                     android:textStyle="bold"
                     android:id="@+id/StoreAddress" />
            </LinearLayout>
            <!-- The store contact -->
            <LinearLayout
                 android:orientation="horizontal"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" >
                <!-- Store contact label -->
                <TextView
                     android:text="@string/ContactsText"
                     android:textAppearance="?android:attr/textAppearanceSmall"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:textColor="#FF9D9D9D"
                     android:layout_marginRight="5dp" />
                <!-- Store contact value -->
                <TextView
                     android:textAppearance="?android:attr/textAppearanceSmall"
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     android:textColor="#FF9D9D9D"
                     android:textStyle="bold"
                     android:id="@+id/StoreContacts" />
            </LinearLayout>
        </LinearLayout>
        <ImageView
             android:src="@drawable/arrowright"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:layout_marginRight="5dp"
             android:paddingRight="5dp"
             android:paddingLeft="5dp"
             android:id="@+id/StoreEntry_ViewStore" />
    </LinearLayout>
</LinearLayout>
ListView Adapter
using Android.App;
using Android.Graphics;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Project {
    public class ListViewAdapter : BaseAdapter<StoreObject> {
        // Properties
        private Activity Context {
            get; set;
        }
        private List<StoreObject> StoresList {
            get; set;
        }
        // Methods
        public override Int32 Count {
            get {
                return StoresList.Count;
            }
        }
        public override Int64 GetItemId( Int32 position ) {
            return position;
        }
        public override StoreObject this[ Int32 position ] {
            get {
                return StoresList[ position ];
            }
        }
        public override View GetView( Int32 position, View convertView, ViewGroup parent ) {
            StoreObject
                 store = StoresList[ position ];
            View
                 view = convertView ?? Context.LayoutInflater.Inflate( Resource.Layout.StoreEntry, null );
            // Set the store image
            Double
                 imageWidth = Context.Resources.DisplayMetrics.WidthPixels / Context.Resources.DisplayMetrics.Density * (3.0 / 7.0);
            Bitmap
                 storeBitmap = Utils.GetBitmap( store.Image, (Int32) imageWidth );
            view.FindViewById<ImageView>( Resource.Id.StoreImage ).SetImageBitmap( storeBitmap );
            // Set the store name
            view.FindViewById<TextView>( Resource.Id.StoreName ).SetText( store.Name, TextView.BufferType.Normal );
            // Set the store schedule, whether is open or closed
            String
                 storeSchedule = store.isOpen ?
                      Context.Resources.GetString( Resource.String.OpenText ) :
                      Context.Resources.GetString( Resource.String.ClosedText );
            view.FindViewById<TextView>( Resource.Id.StoreSchedule ).SetText( storeSchedule, TextView.BufferType.Normal );
            // Set the store address
            String
                 storeLocation = Context.Resources.GetString( Resource.String.NotAvailableText );
            if (store.Address != null) {
                storeLocation = store.Address.City;
            }
            view.FindViewById<TextView>( Resource.Id.StoreAddress ).SetText( storeLocation, TextView.BufferType.Normal );
            // Set the store contact
            String
                 storeContact = Context.Resources.GetString( Resource.String.NotAvailableText );
            if (store.contacts != null && store.contacts.Count > 0) {
                storeContact = store.contacts.FirstOrDefault().PhoneNumber.ToString();
            }
            view.FindViewById<TextView>( Resource.Id.StoreContacts ).SetText( storeContact, TextView.BufferType.Normal );
            return view;
        }
        // Constructors
        public ListViewAdapter( Activity context, List<StoreObject> items ) : base() {
            Context = context;
            StoresList = items;
        }
    }
}
Stores Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
     android:minWidth="25px"
     android:minHeight="25px"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/StoresHolder"
     android:listSelector="#7FDCBB73" />
Stores Fragment
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Android.App;
using Android.OS;
using Android.Views;
using Android.Widget;
namespace Project {
    public class Stores : Fragment {
        // Properties
        private List<StoreObject> StoresList {
            get; set;
        }
        private View CurrentView {
            get; set;
        }
        private ListView StoresHolder {
            get {
                return CurrentView.FindViewById<ListView>( Resource.Id.StoresHolder );
            }
        }
        // Events
        public override void OnCreate( Bundle savedInstanceState ) {
            base.OnCreate( savedInstanceState );
        }
        public override View OnCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) {
            base.OnCreateView( inflater, container, savedInstanceState );
            CurrentView = inflater.Inflate( Resource.Layout.Stores, container, false );
            if (StoresList == null) {
                StoresList = GetStores();
            }
            StoresHolder.ItemClick += ItemClick;
            StoresHolder.Adapter = new ListViewAdapter( Activity, StoresList );
            return CurrentView;
        }
        private void ItemClick( Object sender, AdapterView.ItemClickEventArgs e ) {
            // Do stuff...
        }
    }
}
I hope that this can help someone in the future.
 
     
     
     
     
    