kamulog

xamarin.formsのネタなど

Xamarin.Forms 2.4.0でEffectsの挙動が変わったような気がする点(Androidのみ)

2.4.0がStableになってAiForms.Effectsの対応作業をしていて気づいた点をいくつかご紹介したいと思います。

変わったような気がする点

iOSに関してはEffectsに関して変わったところには遭遇しませんでした。

Android

  • PlatformEffectでContainerやControlの中身が微妙に変わっている。
  • FastRendererを有効にするとさらに変わる。
  • 主にLayout系でClickイベントを付与しても発火しなくなった。
  • IVisualElementRendererのElementがnullかどうかでDispose済みかの判定ができなくなった。

Container Control に何が入ってきて何が有効か

片っ端から調べてみました。調査結果は以下の通りです。

通常

Element Control Container Click Touch
ActivityIndicator ProgressBar ActivityIndicatorRenderer OK OK
BoxView BoxRenderer NG OK
Button AppCompatButton ButtonRenderer OK OK
DatePicker EditText DatePickerRenderer OK OK
Editor FormsEditText EditorRenderer OK OK
Entry FormsEditText EntryRenderer OK OK
Image FormsImageView ImageRenderer OK OK
Label FormsTextView LabelRenderer OK OK
ListView ListView ListViewRenderer Error OK
Picker EditText PickerRenderer OK OK
ProgressBar ProgressBar ProgressBarRenderer OK OK
SearchBar SearchView SearchBarRenderer OK OK
Slider FormsSeekBar SliderRenderer NG OK
Stepper LinearLayout StepperRenderer OK OK
Switch SwitchCompat SwitchRenderer OK OK
TableView ListView TableViewRenderer Error OK
TimePicker EditText TimePickerRenderer OK OK
WebView WebView WebViewRenderer NG OK
ContentPresenter DefaultRenderer NG OK
ContentView DefaultRenderer NG OK
ScrollView ScrollViewRenderer ScrollViewRenderer NG OK
TemplatedView DefaultRenderer NG OK
AbsoluteLayout DefaultRenderer NG OK
Grid DefaultRenderer NG OK
RelativeLayout DefaultRenderer NG OK
StackLayout DefaultRenderer NG OK
  • FrameはそもそもEffectがアタッチされないので以前から動作せず。
  • ListView TableViewはClickイベントを登録すると例外が発生。
  • LongClickもClickと同様。

FastRenderer 有効

Element Control Container Click Touch
Button ButtonRenderer OK OK
Image ImageRenderer NG OK
Label LabelRenderer NG OK
  • FastRendererはContainerがnullとなる。
  • 他は通常と同じ。

主にLayout系でClickイベントが発生しなくなっていました。 これは以前は確実にできていたので、もし以前のバージョンでLayout系でClickイベントを付与するEffectを使っていた場合は改修が必要です。

さらにFastRendererを有効にした場合は、Containerがもれなくnullになり、Buttonを除いてClickイベントも効かなくなります。

Containerがnullになったのは、軽くするために従来ならコントロールをラップするViewGroupがあったんですが、それがなくなって親のViewGroupの直接の子になったためだと思います。

対策は表を見ての通り、代わりにTouchイベント使えばOKです。 MotionEventActions.Upの時にCommandでも発火させればタップしたのと同じような動きになるはずです。

ただ問題もあって、ロングタップどうするんだ?ということとRippleEffectを

kamusoft.hatenablog.jp

この方で付与しても効果が発動しなくなることです。 多分ClickイベントとRippleが関係していてClickが効かないのでRippleも発動しないのかなと思いますが、詳しいことは分かりませんw

その辺りの対策はまた別の記事で紹介したいと思います。

Disposeされているかの判定方法

これはEffects限定のことではないですが…

今までは以下のように判定していました。 (これが正しかったのは分かりません)

var renderer = Container as IVisualElementRenderer;
if (renderer?.Element != null) {    // Check disposed
    //Disposeされていなかった場合の処理
}

2.4.0以降はContainerがnullの場合もある上にFastRendererはIVisualElementRendererのElementがnullにならなかったりで、いろいろ調べた結果

var renderer = (Container ?? Control) as IVisualElementRenderer;
if (renderer?.Tracker != null){    // Check disposed
    //Disposeされていなかった場合の処理
}

代わりにTrackerで判定すれば大体いけました。 大体というのはFastRendererのButtonに限りTrakerがnullにならなかったからです。まぁでも妥協できるレベルだと思います。妥協しない方法はまた別の機会に。

検証リポジトリ

github.com

宣伝

2.4.0対策したAiForms.Effectsのpre版を公開中です。

www.nuget.org

github.com