Xamarin.Forms の TextCell に矢印を表示する


動機

Xamarin.Forms で、あるアプリを作って、使ってみてもらったときのことです。ListViewTextCell をタップすると次の画面に行けるのですが、そのことに気づいてもらえなかった、ということがありました。ひとつの解決策として、画面遷移のある TextCell には矢印を表示することを考えました。

ViewCell で書く?

はじめ、TextCell をやめて ViewCell にし、ViewCell の中に Label を置くことを考えました。

ところが、 iOS と Android とで TextCell の中のレイアウトに差があります。このプラットフォーム毎の差異を、ViewCell の中のレイアウトの調整によって書き分けなければなりません。これが複雑で... 結局、この方針は採用しませんでした。

別に書き分けなくてもよい、という考えもあるでしょう。矢印を表示しない ListView の TextCell と、見た目が微妙に違ってくるわけですが、これを気にするかどうか。

Xamarin.Forms は、内部でプラットフォーム毎の TextCellRenderer を実装して書き分けています。

エフェクトでは書けない...

なるべく軽い実装にしたかったので探ってみたのですが、 Cell にエフェクトは使えないそうです。仕様。

カスタム レンダラーで実現

次のブログ記事を見つけて解決です。これが正にやりたいことでした。ということで、私の投稿は James の記事の紹介に過ぎません

少々改変しています。例えば、元の記事のコードでは、矢印アイコンが出るのがデフォルトですが、それは過激かと思いましたので、アイコン無しをデフォルトにしています。以下にコードを示します。

MyApp1.iOS\AccessoryTextCellRenderer.cs
using Xamarin.Forms;
using MyApp1.iOS;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(TextCell), typeof(AccessoryTextCellRenderer))]
namespace MyApp1.iOS
{
    public class AccessoryTextCellRenderer : TextCellRenderer
    {
        public override UIKit.UITableViewCell GetCell(Cell item, UIKit.UITableViewCell reusableCell, UIKit.UITableView tv)
        {
            var cell = base.GetCell(item, reusableCell, tv);
            switch (item.StyleId)
            {
                default:
                case "None":
                    cell.Accessory = UIKit.UITableViewCellAccessory.None;
                    break;
                case "Checkmark":
                    cell.Accessory = UIKit.UITableViewCellAccessory.Checkmark;
                    break;
                case "DetailButton":
                    cell.Accessory = UIKit.UITableViewCellAccessory.DetailButton;
                    break;
                case "DetailDisclosureButton":
                    cell.Accessory = UIKit.UITableViewCellAccessory.DetailDisclosureButton;
                    break;
                case "DisclosureIndicator":
                    cell.Accessory = UIKit.UITableViewCellAccessory.DisclosureIndicator;
                    break;
            }
            return cell;
        }
    }
}
Page1.xaml
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell StyleId="DisclosureIndicator" Text="{Binding Text}" Detail="{Binding Detail}" />
                </DataTemplate>
            </ListView.ItemTemplate>

見た目はこんな感じです。

公式ドキュメントではこのあたりが参考になると思います。

Android では表示しない

iOS 側しか手当てしていませんので、Android では従来のまま、矢印アイコンなどは表示されません。iOS にあるようなプロパティは Android の API には無さそうです。API に用意が無いのなら、それが Android の流儀なのだろう、と納得することにしました。Xamarin.Forms に組み込まれていない理由は、iOS にしか無いからでしょうか。

以上、Tweet しながら コーディングしていました。