@seto_hiです。主食はMaterialDesignとViewGroupです。
Android Advent Calendar 2017 の10日目の記事です。
DroidKaigi 2018のセッションのステマ記事です。
この記事をお読みのイケてるAndroidエンジニアの皆様におかれましては当然ConstraintLayoutをお使いのこととお慶び申し上げます。
複雑なレイアウトを1階層で簡単に実現できる魔法のようなライブラリですが、やはり年末が近づくにつれて内部実装が気になってきます。
偶然にも僕はDroidKaigi 2018で「詳解 ViewGroupのレイアウト内部実装」という発表をするので、今回は以下の機能の実現方法について解説します。
- Guideline
- Group
- Barrier
- Chain
Guideline
Guideline、実はViewです。
Guideline自身がViewとしてLayoutされることによって、他のViewのレイアウト位置を調整しています。
指定した位置にレイアウトされるだけというクラスです。
超シンプル!
Group
Group、実はViewです。
Viewを継承したConstraintHelperというクラスを継承しています。
レイアウト前に呼ばれる#updatePreLayout
というメソッドで、対象となるViewのvisibilityとelevationを変更しているだけです。
超シンプル!
Barrier
Barrier、実はViewです。
Barrier自身がViewとしてLayoutされることによって、他のViewのレイアウト位置を調整しています。
Guidelineと違い、他Viewの位置に依存するためConstraintHelperを継承しています。1
シンプル!
Chain
Chain、実はViewではありません。
上記の機能と違い、layoutのXMLに要素として記載しないので当然ですね。
ConstraintLayoutはconstraint-layout-solver
というライブラリに依存しています。
その中にあるChainクラスというstaticメソッドが2つだけあるクラスで実現しています。
実装内容は「このViewとこのViewの間隔は固定値」「このViewとこのViewの間隔は大きくなって良い」といったような条件を不等式に変換して線形計画問題2に追加しているだけです。3
Chainであるかの判定は循環参照の検知(例:自身の右の制約のViewの左の制約が自身であるか)です。
シンプル...?ではないですね...
さいごに
ConstraintLayoutはソースが公開されていないのでデコンパイルされたコードを読むしかありませんが、色々と面白い実装になっているので是非コードを読まれてみると良いと思います!
無料で50時間くらいは悩める楽しいコンテンツです!
そして是非DroidKaigiで僕とConstraintLayout・ViewGroupの内部実装の話をしましょう!
DroidKaigiのセッションではもっと詳しい話をするのでご期待ください!!!
それではよいConstraintLayoutライフを!
-
別にViewクラスの直継承でも同じ機能を実現できる気がするのですが、詳しい人教えてください。ConstraintHelperだとmeasureされないので高速化できるとかそのあたりですか? ↩
-
ConstraintLayoutは内部で線形計画問題を解決してレイアウト位置を算出しています。詳しくは@inamiyさんのiOSDCの発表かDroidKaigiのセッションで! ↩
-
chainStyleやViewの状態(wrap_contentかどうか、chainの一番端のViewであるか、などなど)で条件分けしてLinearSystem.addGreaterThanなどで不等式を追加しています。LinearSystemなども説明したいところですが、それだけで1万文字くらいになってしまうのでこの記事では概要だけにします。詳しくはDroidKaigiのセッションで! ↩