前回 はリストの選択時に読み上げを行うようにしました
今回はさらにコンテキストアクション(Android と Windows Phone は長押し、iOS は水平スワイプ)で追加のメニュー表示(詳細記事のリンクを開く)を加えてみたいと思います
まずは XAML 側から修正
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XamarinReader.Views.TopPage" x:Name="root" BindingContext="{Binding Path=ViewModel, Source={x:Reference Name=root}}"> <ContentPage.Padding> <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0"/> </ContentPage.Padding> <StackLayout Orientation="Vertical" Spacing="10"> <StackLayout Orientation="Horizontal" Padding="15,5" BackgroundColor="#33ffffff" Spacing="5"> <Label Text="TechCrunch" TextColor="Lime" FontSize="Medium"/> <Label Text="Reader" FontSize="Medium"/> </StackLayout> <ListView ItemsSource="{Binding Items}" SeparatorColor="Transparent" HasUnevenRows="True" IsRefreshing="{Binding IsRefresing}" IsPullToRefreshEnabled="True" ItemSelected="OnListItemSelected" RefreshCommand="{Binding RefreshCommand}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ViewCell.ContextActions> <MenuItem Text="Read more" Command="{Binding LaunchLinkUriCommand}" CommandParameter="{Binding}"/> </ViewCell.ContextActions> <StackLayout Orientation="Vertical" Spacing="0" Padding="15,10"> <Image Source="{Binding Thumbnail}" HeightRequest="150" VerticalOptions="StartAndExpand" Aspect="AspectFill"/> <StackLayout Orientation="Vertical" Padding="10" BackgroundColor="#66000000" Spacing="10"> <Label Text="{Binding Title}" TextColor="Accent" FontSize="Medium"/> <Label Text="{Binding Description}" TextColor="Default" FontSize="Small"/> </StackLayout> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
ListView.ItemTemplate の ViewCell に下記の記述を追加しました
<ViewCell.ContextActions> <MenuItem Text="Read more" Command="{Binding LaunchLinkUriCommand}" CommandParameter="{Binding}"/> </ViewCell.ContextActions>
この修正を受けてコードビハインドも修正します
/// <summary> /// Top page /// </summary> public partial class TopPage : ContentPage { ~ 中略 ~ /// <summary> /// Appearing event handler /// </summary> protected override async void OnAppearing() { base.OnAppearing(); this.speech = ((App)App.Current).Container.Resolve<ITextSpeechService>(); await this.Refresh(); } /// <summary> /// Refresh news feed items /// </summary> /// <returns>Task</returns> private async Task Refresh() { this.ViewModel.IsRefresing = true; await this.newsFeed.Update(); // Add items on UI thread foreach (var item in this.newsFeed.Feed.Channel.Items.OrderBy(i => i.PubDate)) { var vm = new NewsItemViewModel { UniqueId = item.Guid, Categories = new ObservableCollection<string>(item.Categories), Title = item.Title, Link = item.Link, LastUpdated = item.PubDate, Description = ReadMoreRegex.Replace( WebUtility.HtmlDecode( HtmlTagRegex.Replace(item.Description, string.Empty)), string.Empty), LaunchLinkUriCommand = new DelegateCommand<NewsItemViewModel>(this.LaunchLinkUri), }; var imgMatch = ImgTagRegex.Match(item.Description); if (imgMatch.Success) { vm.Thumbnail = ImageSource.FromUri(new Uri(imgMatch.Groups["uri"].Value)); } var oldItem = this.ViewModel.Items.FirstOrDefault(i => i.UniqueId.Equals(vm.UniqueId)); if (oldItem != null) { if (oldItem.LastUpdated.CompareTo(vm.LastUpdated) >= 0) { // no update continue; } // updated oldItem.Categories = vm.Categories; oldItem.Title = vm.Title; oldItem.Link = vm.Link; oldItem.LastUpdated = vm.LastUpdated; oldItem.Description = vm.Description; oldItem.Thumbnail = vm.Thumbnail; continue; } // new item this.ViewModel.Items.Insert(0, vm); } this.ViewModel.IsRefresing = false; } /// <summary> /// ListView item selected event handler /// </summary> /// <param name="sender">Event publisher</param> /// <param name="e">Event arguments</param> private void OnListItemSelected(object sender, SelectedItemChangedEventArgs e) { var item = e.SelectedItem as NewsItemViewModel; if (item == null) { return; } this.speech.SetLanguage("English"); this.speech.Speak(string.Format("{0}: {1}", item.Title, item.Description)); } /// <summary> /// Launch a selected item link uri /// </summary> /// <param name="item">Select item</param> private void LaunchLinkUri(NewsItemViewModel item) { Device.OpenUri(new Uri(item.Link)); } }
リンクを開くための LaunchLinkUri というメソッドを追加して、リストアイテムの ViewModel である NewsItemViewModel.LaunchLinkUriCommand に設定しています
最終的に先ほどの XAML の Read More の MenuItem にバインドされます
やることはこれだけ!実にかんたん!そしてさっそくおためし
Windows Phone はにょきっと生えます・・・プラットフォームごとに全然インタラクションが違いますがそれは省略