FC2ブログ

記事一覧

ListViewのセルのレイアウト方法 -CustomViewCell- | Xamarin.Forms


今回はXamarin.FormsでListViewのセルのレイアウト方法についてご紹介いたします。文字だけのListViewなら簡単ですが、画像や文字または背景色など様々なデータを表示したい場合にレイアウトを設定することが大変です。そこでViewCellを継承したクラスをテンプレートとして、簡単に配置する方法を以下にまとめてみました。


xamarin_viewcell_01.png


前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.795 (NuGet Xamarin.Forms 2.3.4.247)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.6.0.10



1.レイアウト

画像の赤枠がViewCellです。
後に出てきますコード上の名称でlayout1~4はStackLayoutオブジェクトというレイアウト専用のコントロールみたいなものです。

layout1が紫枠に相当します。
画像と横並びにする必要があるためlayout2~layout4までを束ねてから赤枠内で横並びにしています。

layout2~4は青枠に相当します。
表示する行数が3行の場合でご説明しておりますが、必要な場合はStackLayoutを増やしてしまえば良いだけです。

また、それぞれのStackLayout内のの左寄せ・右寄せについては各コントロールのHorizontalOptionsで変更します。



2.実装方法

PCLにViewCellを継承したクラスを実装します。
後にListViewのテンプレートとして呼び出します。

ListViewCellTest.cs
using Xamarin.Forms;
using AppName.Controls;
using AppName.ViewModels;
using AppName.Models.Converter;
namespace AppName.Controls
{
    public class ListViewCellTest : ViewCell
    {
        //コントロール定義
        private Image img = new Image();
        private Label lblName1 = new Label();
        private Label lblName2 = new Label();
        private Label lblNotes = new Label();
        private Label lblId = new Label();
        private Label lblEnabled = new Label();
        private BaseCheckBox chkBox = new BaseCheckBox();
        StackLayout baseLayout = null;
        StackLayout layout1 = null;
        StackLayout layout2 = null;
        StackLayout layout3 = null;
        StackLayout layout4 = null;
        MenuItem actionDelete = null;

        //コンストラクタ
        public ListViewCellTest(Page page, bool isBaseCheckBoxShowing = false)
        {

            try
            {
                this.Initialize(page);

                if (isBaseCheckBoxShowing)
                {
                    if (baseLayout == null)
                    {
                        baseLayout = new StackLayout
                        {
                            Padding = new Thickness(5),
                            Orientation = StackOrientation.Horizontal, //横に並べる
                            Children = { chkBox, img, layout1 },
                        };
                    }
                    View = baseLayout;
                }
                else
                {
                    if (baseLayout == null)
                    {
                        baseLayout = new StackLayout
                        {
                            Padding = new Thickness(5),
                            Orientation = StackOrientation.Horizontal, //横に並べる
                            Children = { img, layout1 },
                        };
                    }
                    View = baseLayout;
                }
                //無効の背景色を変更
                View.SetBinding(View.BackgroundColorProperty, new Binding("IsEnabled", BindingMode.Default, new BackColorConverter(), null));
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine + ex.StackTrace);
            }
        }

        private void Initialize(Page page)
        {
            //コントロール定義1
            chkBox.IsChecked = false;
            chkBox.VerticalOptions = LayoutOptions.Start;
            chkBox.SetBinding(BaseCheckBox.IsCheckedProperty, new Binding("IsDeleted"));
            chkBox.Clicked += (s, e) =>
            {
                try
                {
                    if (BindingContext == null)
                    {
                        return;
                    }
                    var data = (EventInfo)BindingContext;
                    data.IsDeleted = chkBox.IsChecked;
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine + ex.StackTrace);
                }
            };

            //コントロール定義2
            img.SetBinding(Image.SourceProperty, new Binding("Picture", BindingMode.Default, new ImageSourceFromByteArrayConverter(), null));
            img.Aspect = Aspect.AspectFill;

            //コントロール定義3
            lblName1.FontSize = 16;
            lblName1.TextColor = Color.Black;
            lblName1.SetBinding(Label.TextProperty, new Binding("Name1"));
            lblName1.HorizontalOptions = LayoutOptions.StartAndExpand;
            lblName1.VerticalOptions = LayoutOptions.End;

            //コントロール定義4
            lblName2.FontSize = 16;
            lblName2.TextColor = Color.Black;
            lblName2.SetBinding(Label.TextProperty, new Binding("Name2"));
            lblName2.HorizontalOptions = LayoutOptions.StartAndExpand;
            lblName2.VerticalOptions = LayoutOptions.End;

            //コントロール定義5
            lblNotes.Margin = new Thickness(5, 0, 0, 0);
            lblNotes.FontSize = 14;
            lblNotes.TextColor = Color.Gray;
            lblNotes.SetBinding(Label.TextProperty, new Binding("Notes"));
            lblNotes.HorizontalOptions = LayoutOptions.StartAndExpand;
            lblNotes.VerticalOptions = LayoutOptions.Center;

            //コントロール定義6
            lblId.FontSize = 14;
            lblId.TextColor = Color.Gray;
            lblId.SetBinding(Label.TextProperty, new Binding("Id"));
            lblId.HorizontalOptions = LayoutOptions.End;
            lblId.VerticalOptions = LayoutOptions.Center;
            lblId.IsVisible = false;

            //コントロール定義6
            lblEnabled.FontSize = 14;
            lblEnabled.TextColor = Color.Gray;
            lblEnabled.SetBinding(Label.TextProperty, new Binding("IsEnabled", BindingMode.Default, new BoolConverter(), null));
            lblEnabled.HorizontalOptions = LayoutOptions.EndAndExpand;
            lblEnabled.HorizontalTextAlignment = TextAlignment.End;
            lblEnabled.VerticalOptions = LayoutOptions.Center;

            if (layout4 == null)
            {
                layout4 = new StackLayout
                {
                    Orientation = StackOrientation.Horizontal,  //横に並べる
                    Children = { lblNotes, lblId },
                };
            }
            if (layout3 == null)
            {
                layout3 = new StackLayout
                {
                    Orientation = StackOrientation.Horizontal,  //横に並べる
                    Children = { lblName2, lblEnabled },
                };
            }
            if (layout2 == null)
            {
                layout2 = new StackLayout
                {
                    Orientation = StackOrientation.Horizontal,  //横に並べる
                    Children = { lblName1 },
                };
            }
            if (layout1 == null)
            {
                layout1 = new StackLayout
                {
                    Orientation = StackOrientation.Vertical,  //縦に並べる
                    Children = { layout2, layout3, layout4 },
                };
            }


            //アクション定義
            actionDelete = new MenuItem
            {
                // 2つのアクションを追加するため、MenuItemクラスのインスタンスを2つ生成している
                Text = "Delete",
                // MenuItemオブジェクトのIsDestructiveプロパティをtrueにセットすることで、メニューアイテムの表示が赤色になる(※ただし、iOSのみ)
                IsDestructive = true,
            };
            actionDelete.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
            actionDelete.Clicked += async (s, e) =>
            {
                // MenuItemオブジェクトのClickedイベントに追加する
                try
                {
                    bool ret = await page.DisplayAlert("削除",
                                                         "削除してもよろしいですか?",
                                                         "OK", "Cancel");
                    if (ret)
                    {
                        //削除するロジックを実装する
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine + ex.StackTrace);
                }
            };
            ContextActions.Add(actionDelete);

        }

        // プロパティが変更された時に呼ばれる
        protected override void OnBindingContextChanged()
        {
            try
            {
                base.OnBindingContextChanged();
                if (BindingContext == null)
                {
                    return;
                }
                // 表示対象のデータを取得
                var data = (EventInfo)BindingContext;

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message + System.Environment.NewLine + ex.StackTrace);
            }
        }
    }
}

バイト配列を画像に変換したり、Boolを文字列に変換するコンバータのソースについては割愛しています。



3.使用方法

ViewCellをListViewのItemTemplateに設定します。

TestPage.xaml.cs
void OnButtonClick()
{
    this.ListView1.ItemTemplate = new DataTemplate(() => new AppName.Controls.ListViewCellTest(this, false));
    this.ListView1.ItemsSource = new ObservableCollection<EventInfo>();
}

※必要なViewModelクラスEventInfoは自身のクラスに置き換えてください。





最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。