Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9293

Xamarin Android GridViewのカスタムレンダラーの作成

$
0
0

前書き

XamarinもAndroidも初めてで、両方の知識が必要なCustomRendererを作成するのに手こずったので書き残しました。
冗長な書き方や間違いがある可能性が高いです。

※CustomRendererはPCL側のXamlで実装できない、できたけど速度が遅い。みたいなときに各プラットフォームごとの固有の書き方をすることで改善することができる機能。(今回はAndroidなのでC#、xmlで実装していきます)

完成形

Screenshot_20200513-005743.png

実装

※私のnamespaceやプロジェクト名は自分のものに置き換えてください

PCL側

PCLとXamarin.Androidを紐づけるためのクラスを用意します。

PCLCustomGridViewRenderer.cs

usingSystem.Runtime.CompilerServices;usingXamarin.Forms;[assembly:InternalsVisibleTo("MyProject.Android")]namespaceMyProject.Views.Renderer{publicclassPCLCustomGridViewRenderer:ItemsView{}}


ItemsViewは配列を受け取るための抽象クラス。継承してやることでXamlからPCLCustomGridViewRendererに対して配列を渡すことができる。(配列はそのままAndroid側の実装で扱えます)

XamlからPCLCustomGridViewRendererを呼び出します。

<StackLayoutxmlns:renderer="clr-namespace:MyProject.Views.Renderer"><renderer:PCLCustomGridViewRendererItemsSource="{Binding Items}"/></StackLayout>

※PCLCustomGridViewRendererが見つからないエラーが出る場合はプロジェクトをリビルドしてみてください。

ちなみにDataList内のデータ構成はObservableCollectionになっています。

ObservableCollection<Item>Items;classItem{publicstringText{get;set;}}

PCL側の実装は以上です。

Xamarin.Android側

3つほどクラスファイルを用意します。
1.Android側で配列を受け取りGridViewを生成するクラス。
2.Androidの世界で出てくるAdpterクラス。データとxmlを紐づけるためのクラス。
3.GridView内に配置する要素のxmlファイル

1.AndroidCustomGridViewRenderer.cs
エラー線が出る箇所がありますが、進めていく際に治るので、一旦無視してください。

usingAndroid.Content;usingAndroid.Support.V7.View;usingAndroid.Widget;usingMyProject.Droid.Renderer;usingMyProject.Droid.Views.Adapter;usingMyProject.Views.Renderer;usingSystem.ComponentModel;usingXamarin.Forms;usingXamarin.Forms.Platform.Android;//互いに参照できるよう定義[assembly:ExportRenderer(typeof(PCLCustomGridViewRenderer),typeof(AndroidCustomGridViewRenderer))]namespaceMyProject.Droid.Renderer{publicclassAndroidCustomGridViewRenderer:ViewRenderer<PCLCustomGridViewRenderer,GridView>{privateGridViewAdapteradapter;publicAndroidCustomGridViewRenderer(Contextcontext):base(context){}// 生成時一度だけ呼ばれるイベントprotectedoverridevoidOnElementChanged(ElementChangedEventArgs<PCLCustomGridViewRenderer>e){base.OnElementChanged(e);if(e.OldElement!=null){if(adapter!=null)adapter.Element=null;}if(e.NewElement!=null){if(Control==null){// Adpterの生成adapter=newGridViewAdapter(Context);           // GridViewの生成varrecyclerView=newCustomGridView(newContextThemeWrapper(Context,Resource.Style.VerticalScrollbarRecyclerView));           // GridViewのパラメータを設定(親サイズに追従する設定)recyclerView.LayoutParameters=newLayoutParams(LayoutParams.MatchParent,LayoutParams.MatchParent);// カラム数recyclerView.NumColumns=3;           // Viewに対しAdpterを設定recyclerView.Adapter=adapter;//多分コントロールを実際に生成SetNativeControl(recyclerView);}if(adapter!=null)// NewElementにはIList<Person>が入ってきます// ElementはAdpterクラスが私が定義しました。adapter.Element=e.NewElement;}}protectedoverridevoidOnElementPropertyChanged(objectsender,PropertyChangedEventArgse){base.OnElementPropertyChanged(sender,e);if(e.PropertyName==ItemsView.ItemsSourceProperty.PropertyName){adapter?.UpdateItems();}}protectedoverridevoidDispose(booldisposing){base.Dispose(disposing);adapter.Dispose();}}}

2.AndroidCustomGridViewAdapter.cs

usingSystem.Collections.ObjectModel;usingSystem.Linq;usingAndroid.Content;usingAndroid.Views;usingAndroid.Widget;usingMyProject.Models;usingMyProject.Views.Renderer;namespaceMyProject.Droid.Views.Adapter{classAndroidCustomGridViewAdapter:BaseAdapter{privatePCLCustomGridViewRendererelement;publicPCLCustomGridViewRendererElement{get=>element;set{element=value;UpdateItems();}}Contextcontext;privateObservableCollection<Item>viewModels=newObservableCollection<Item>();publicAndroidCustomGridViewAdapter(Contextc){context=c;}publicoverrideintCount{get{returnviewModels.Count();}}publicoverrideJava.Lang.ObjectGetItem(intposition){returnnull;}publicoverridelongGetItemId(intposition){return0;}publicvoidUpdateItems(){viewModels.Clear();if(Element?.ItemsSource!=null){foreach(variteminElement.ItemsSource){if(itemisItemmodel){viewModels.Add(model);}}}NotifyDataSetChanged();}// Countプロパティの数だけ呼ばれるViewを生成する関数publicoverrideAndroid.Views.ViewGetView(intposition,Android.Views.ViewconvertView,ViewGroupparent){varview=LayoutInflater.From(parent.Context).Inflate(Resource.Layout.custom_gridview_item,parent,false);// 要素の作成SetUp(view,viewModels[position]);returnview;}privatevoidSetUp(Android.Views.Viewview,Itemmodel){vartext=view.FindViewById<TextView>(Resource.Id.text);text.Text=model.Text;}}}

3.custom_gridview_item.xml
Resources/layoutフォルダに配置して下さい。

<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/text"android:text="ああああああああああああああああ"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout>

まだエラー線が出ている箇所があると思うので定義を追加します。
Resources/values/styles.xmlのresourcesタグの中に以下を追加します

<stylename="VerticalScrollbarRecyclerView"parent="android:Widget"><itemname="android:scrollbars">vertical</item></style>

完成

ビルドしてみてください。

もしプロジェクトの実行の際に以下のエラーが出た場合

System.InvalidOperationException: 'The class, property, or method you are attempting to use ('VerifyCollectionViewFlagEnabled') is part of CollectionView; to use it, you must opt-in by calling Forms.SetFlags("CollectionView_Experimental") before calling Forms.Init()

MyProject.AndroidプロジェクトのMainActivity.csに1行追加してください

global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental"); ←下の行より前にこの行を追加global::Xamarin.Forms.Forms.Init(this,savedInstanceState);      

あとがき

今回はただテキストを表示するだけでしたが、Itemクラスを拡張したり、xmlを変えたりすることで自由な表現ができると思います。


Viewing all articles
Browse latest Browse all 9293

Trending Articles