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を
この方で付与しても効果が発動しなくなることです。 多分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にならなかったからです。まぁでも妥協できるレベルだと思います。妥協しない方法はまた別の機会に。
検証リポジトリ
宣伝
2.4.0対策したAiForms.Effectsのpre版を公開中です。