One interesting aspect of building cross-platform apps is how to adopt the 'standard' UI elements so that each app looks 'native'. A basic iPhone/MonoTouch and WindowsPhone7 application was introduced in
a previous post. Each app uses the 'default' list representation.
This post is about making those apps easier to use, adding each platform's default "list index" to help select from long, sorted lists. The images below hardly need captions:
- on the left is the iPhone app with alphabetic index down the right side of the screen
- on the right is the WindowsPhone7 app showing the alphabet tiles 'in' the list, and the grid that is displayed when you touch one of those tiles
Implementing the two different solutions highlights the difference in the two platforms (referring of course to C#/
MonoTouch on the iPhone, and C#/Silverlight on the WindowsPhone7). Get the complete code from
github - the main changes for each platform are highlighted below:
iPhone (MonoTouch) UITableView sections
The following code was added to the
UITableViewSource
subclass to break up the list into sections, identify the section labels and wire up the alphabetic navigation. The
GetCell
and
RowSelected
methods also required a minor change.
List<string> sectionTitles;
Dictionary<int, <restaurant>> sectionElements = new Dictionary<int,restaurant>>();
public TableViewSource (List<restaurant> list, MainViewController controller)
{
this.list = list;
mvc = controller;
sectionTitles = (from r in list
orderby r.StartsWith
select r.StartsWith).Distinct().ToList();
foreach (var restaurant in list)
{ // group elements together into 'alphabet'
int sectionNumber = sectionTitles.IndexOf(restaurant.Name[0].ToString());
if (sectionElements.ContainsKey(sectionNumber))
sectionElements[sectionNumber].Add(restaurant);
else
sectionElements.Add(sectionNumber, new List<restaurant> {restaurant});
}
}
public override int NumberOfSections (UITableView tableView)
{
return sectionTitles.Count;
}
public override string TitleForHeader (UITableView tableView, int section)
{
return sectionTitles[section];
}
public override string[] SectionIndexTitles (UITableView tableView)
{
return sectionTitles.ToArray();
}
public override int RowsInSection (UITableView tableview, int section)
{
return sectionElements[section].Count(); //list.Count;
}
Windows Phone 7 'quick jump grid'
Although you'll see this kind of navigation in the 'built-in' applications, it isn't actually part of the default SDK. Thankfully
Kevin Marshall has posted a
quick jump grid sample which has been integrated into the
RestGuide app - just add the relevant Assembly References then update the XAML to use the
QuickJumpGrid
(don't forget to add the relevant
xmlns:
declarations)
<cc:QuickJumpGrid DataSource="{Binding}"
IsAlphaNumeric="True"
Margin="12,0,0,0"
SelectionChanged="MainListBox_SelectionChanged"
x:Name="MainListBox"
OverlayTileBackground="#8CBF26">
<cc:QuickJumpGrid.QuickJumpGridSelector>
<local:RestaurantNameSelector />
</cc:QuickJumpGrid.QuickJumpGridSelector>
<cc:QuickJumpGrid.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding Cuisine}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</cc:QuickJumpGrid.ItemTemplate>
</cc:QuickJumpGrid>
and implement this 'helper' class (which is referenced from the XAML)
namespace RestGuide
{
public class RestaurantNameSelector : IQuickJumpGridSelector
{
public Func<object, IComparable> GetGroupBySelector()
{
return (p) => ((Restaurant)p).Name.FirstOrDefault();
}
public Func<object, string> GetOrderByKeySelector()
{
return (p) => ((Restaurant)p).Name;
}
public Func<object, string> GetThenByKeySelector()
{
return (p) => (string.Empty);
}
}
}