Google I/O 2018でConstraintLayout2.0が発表されると思いますが、その前に1.1.0の内部実装を読んでおきましょう。
はじめに
DroidKaigi 2018でConstraintLayoutの内部実装に関する発表をした者です。動画はこちら。
発表の中ではレイアウトアルゴリズムを簡単に紹介することしかできなかったので、もう少し踏み込んだ内容の紹介をしたいと思います。
この記事では各クラスの役割について記述します。
環境
ConstraintLayout Ver1.1.0
ConstraintLayoutはbetaのバージョンが1つ上がるだけで内部実装がかなり変わるので、違うバージョンでは参考にならない可能性が高いです。
Ver1.1.0のコードは公開されていないので、逆コンパイルしたコードを読んでいます。
なお、beta-5までならこちらに公開されています。
DroidKaigiの内容のおさらい
ConstraintLayoutの構成
constraint-layout
ライブラリはconstraint-layout-solver
ライブラリに依存しています。
constraint-layout
ライブラリには最低限の実装しかなく、レイアウトの複雑な計算のほとんどはconstraint-layout-solver
側で行われています。
またconstraint-layout-solver
はAndroidに依存しておらず、(使おうと思えば)Android以外のプロジェクトにも使い回せるようになっています。
ConstraintLayoutのレイアウトアルゴリズム
ConstraintLayoutはView同士の関係を一次方程式や一次不等式に見立て、線形計画問題の最適解を求めることでレイアウト位置を決定しています。
線形計画問題の最適解を求めるためにCassowaryという計算アルゴリズムを使っています。
このあたりの詳細は @inamiy さんのこちらの記事が参考になります。
(iOSのAutoLayoutもConstraintLayoutと同じくCassowaryを使ってレイアウトを解決してます)
constraint-layout-solverの各クラスの役割
一部重要そうでないクラスは省略します。
android.support.constraint.solver パッケージ
ArrayLinkedVariables
ArrayベースのLinked List。高速でメモリ効率が良いらしいです。
ArrayBackedVariables
とLinkedVariables
からインスピレーションを受けているそうです。
ArrayVariables
使っている部分を見つけられず。
ArrayLinkedVariablesからhead
とlast
が取り除かれた実装になっています。
ArrayRow
線形計画問題の行列の「行」を表現するクラス。
LinearSystem.Row
を継承しています。
LinearSystem
線形方程式の最適解を求めるクラス。solverパッケージでも重要なクラスです。
Cassowaryがここに実装されています。
Metrics
LinearSystemの状態を保持する値クラス。
SolverVariable
ViewやContainWidgetのレイアウトをLinearSystemで解決するために変換した値を保持するクラス。
最適解の値も保持をします。
android.support.constraint.solver.widget パッケージ
ConstraintWidget
Androidフレームワークで言うViewクラス。
WidgetContainer
Androidフレームワークで言うViewGroupクラス。ConstraintWidget
を継承しています。
ConstraintWidgetContainer
Androidフレームワークで言うConstraintLayoutクラス。WidgetContainer
を継承しています。
ConstraintHorizontalLayout, ConstraintTableLayout
constraint-layout
で使われていない秘密のクラス。
ごにょごにょするとこんな感じの成果物が得られます。
ConstraintLayout2.0に期待ですね。
Helper
constraint-layout
で言うConstraintHelperクラス。
Barrier
Barrierクラス。Helper
を継承しています。
Guideline
Guidelineクラス。ConstraintWidget
を継承しています。
(他のConstraintWidgetを参照しないため、HelperではなくConstrantWidgetを継承している)
Chain
1.1.0-beta2
から追加されたクラス。
Chainクラスを実現するクラス。staticメソッドが2つあるだけ。
各ConstraintWidgetの関係からいい感じにArrayRowを作成してChainを実現しています。
ConstraintAnchor
ConstraintWidget同士の関係を表すクラス。
layout_constraintTop_toTopOf
などで定義した「ConstraintWidgetの各辺がどのConstraintWidgetのどの辺の位置に参考にレイアウトするか」の情報を表します。
Optimizer
レイアウトの最適化を行うクラス。
各ConstraintWidget同士の関係を、LinearSystemで簡単に解けるように最適化します。
DroidKaigi(1.1.0-beta5
参考)では「簡単なレイアウトを線形計画問題を解かずに計算するクラス」という説明をしましたが、1.1.0
では動作が変わっています。ご注意ください。
Optimizer#checkMatchParent
ConstraintLayoutの子ViewのLayoutParamsがmatch_parent
の場合、親と同じ幅or高さになるように設定して最適化します。
Optimizer#analyze
ConstraintWidgetの幅や高さが数値で設定されている場合や、match_constraint
になっている場合に最適化を行います。
Optimizer#applyChainOptimized
メソッド名の通り、ChainになっているConstraintWidgetの関係を最適化します。
ResolutionNode
1.1.0-beta6
から追加されたクラス。
ConstraintAnchor
は各辺の接続情報の値クラスでしたが、このクラスはinvalidate
やresolve
といったメソッドを持ちます。
ResolutionAnchor
1.1.0
から追加されたクラス。ResolutionNode
を継承しています。
各辺の接続情報をLinearSystem
へ追加したりもします。
ResolutionDimension
1.1.0
から追加されたクラス。ResolutionNode
を継承しています。
OptimizationLevel
がdimenstions
の時に使われます。
float型のvalue
を持ちます。