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
using Xamarin.Forms;
public class TestPage : ContentPage
{
void OnButtonClick()
{
    this.ListView1.ItemTemplate = new DataTemplate(() => new AppName.Controls.ListViewCellTest(this, false));
    this.ListView1.ItemsSource = new ObservableCollection<EventInfo>();
}
}

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





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


関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


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

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

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