4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[初心者さん・学生さん大歓迎!] Xamarin その1Advent Calendar 2017

Day 18

[Xamarin.Forms]ListView・TableViewのセル高さの更新(iOS)

Posted at

はじめに

この記事は [初心者さん・学生さん大歓迎!] Xamarin その1 Advent Calendar 2017 の18日目の記事です。

Xamarin.FormsのiOSでListViewやTableViewは1.3.4からセルの高さを自動調節してくれるようになりました(だいぶ前の話)。ですが、BindingしているItemの値がかわったときなどに、セルの高さが動的に更新されてくれません(Androidでは勝手にセル高さが変わってくれます)。

ListViewでよく出てくるパターンなのにベストプラクティスがよくわからなかったのでまとめてみました。

ForceUpdateSize()を呼ぶ

Xamarinの公式sampleを見るとセルの高さを計算し、HeightRequestを設定してForceUpdateSize()を呼んでいます。


image.HeightRequest = image.Height + 100;
viewCell.ForceUpdateSize ();

Forms側だけで書けるので、シンプルです。

ただし、ForceUpdateSize()がTableViewでは効かなかったり、セル内にカスタムレンダラやEffectでちょっと複雑なことをしていたときに不安定なことがあります。これでつまずいていたときに他の方法を教えてもらいました(参考)。↓

iOSのカスタムレンダラーでReloadData()を呼ぶ

セルの高さがかわる瞬間にiOSのカスタムレンダラーでReloadData()を呼んでやるとリフレッシュされます。

まずはListViewを継承したクラスを作り、Rendererへの橋渡しの準備をします。


    public class ResizableListView : ListView
    {
        public event EventHandler<EventArgs> DataChanged;

        public void OnDataChanged()
        {
            var handler = this.DataChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }

次に先ほど作ったDataChangedイベントをカスタムレンダラーでハンドルしてReloadData()を呼んでやります。


public class ResizableListViewRenderer : ListViewRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
    {
        base.OnElementChanged(e);
        if (e.OldElement == null)
        {
            ((ResizableListView)e.NewElement).DataChanged += (object sender, EventArgs args) => { Control.ReloadData(); };
        }
    }
}

あとは、Formsのセル高さを変更したいタイミングで、作ったListViewのカスタムクラスのOnDataChanged()メソッドを呼び出してやるだけです。

TableViewでも同じことができます。TableViewの継承クラスを作り、TableViewRendererを継承したカスタムレンダラーでReloadData()を呼びだすだけですので全く同じです。

まとめ

Forms側だけで簡潔に書けるので、ForceUpdateSize()で試してみて、うまくいかなかったらカスタムレンダラーのReloadData()を呼ぶようにしてみたらよいかと思います。他にもいいやり方があればコメント欄にて教えてください。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?