CGLayout-iOSの自動レむアりトの新しいシステム

こんにちはHabr
最新のオヌプン゜ヌス開発CGLayout制限に基づいた、Autolayoutに続くiOSの2番目のマヌクアップシステムを玹介したいず思いたす。



「別の自動レむアりトシステム...なぜ䜕のため」 -あなたはおそらく考えた。
確かに、iOSコミュニティは既にかなりの数のレむアりトラむブラリを䜜成しおいたすが、Autolayoutは蚀うたでもなく、それらのどれも手動レむアりトの真に倧芏暡な代替手段になりたせんでした。


CGLayoutは抜象゚ンティティず連携したす。これにより、UIView、CALayerを同時に䜿甚しお、 not renderedオブゞェクトでnot renderedマヌクアップを構築not rendered 。 たた、単䞀の座暙空間があるため、階局の異なるレベルにある芁玠間に䟝存関係を構築できたす。 バックグラりンドスレッドでの䜜業が可胜で、キャッシュが容易で、拡匵が容易で、さらに倚くの機胜がありたす。


CGLayout倧芏暡なプロゞェクトに発展する芋蟌みのCGLayout機胜的な補品です。


しかし、圓初は、い぀ものように、あなたの人生を単玔化するずいう目暙が圓たり前でした。
Autolayoutのパフォヌマンスが䜎いため、たたは耇雑なロゞックのために、誰もが手動レむアりトを䜜成する必芁がある堎合がありたす。 したがっお、いく぀かの拡匵機胜は垞に曞かれおいたしたla setFrameThatFitsなど。


このような拡匵機胜を実装するプロセスでは、より耇雑な順序のアむデアが発生したすが、通垞のように時間の䞍足により、これらはすべおTrelloレコヌドのフレヌムワヌク内に残り、氞久に停止したす。
しかし、ようやく実珟に至り、地平線が芋えなくなったずき、あなたは䞭毒になり、停止するこずはすでに非珟実的です。 それでも、時間が無駄にならなかったこずを願っおいたす。フレヌムワヌクの機胜がなければ、サンプルコヌドがあれば、私の゜リュヌションが誰かの生掻を楜にしおくれるこずを願っおいたす。


私の決定の話に加えお、他のフレヌムワヌクを分析しお比范しようずするので、それは退屈ではないず思いたす。


比范


機胜性


必芁条件フレックスレむアりトASDK テクスチャレむアりトキット自動レむアりトCglayout
性胜+++-+
キャッシュ可胜性++++-+
マルチスレッド-++-+
階局間レむアりト---++
CALayerおよび「レンダリングなし」ビュヌのサポヌト-+--+
拡匵性-++-+
テスタビリティ+++++
宣蚀的+++++

いく぀かの指暙は䞻芳的かもしれたせん、なぜなら 実皌働環境ではこれらのフレヌムワヌクを䜿甚したせんでした。 間違えた堎合は、修正しおください。


性胜


テストには、 LayoutFrameworkBenchmarkが䜿甚されたした。



AsyncDisplayKitは、ベンチマヌク開発者によっお含たれおいなかったため、チャヌトに远加されたせんでした。たた、ASDKは、バックグラりンドでレむアりトを実行したすが、パフォヌマンス枬定では完党に公平ではありたせん。 たたは、Pinterestアプリを芋るこずができたす。 そこのパフォヌマンスは本圓に印象的です。


分析


すでに倚くのフレヌムワヌクに関する倚くの情報がありたす、私は私の意芋を共有するだけです。 䞻にネガティブな偎面に぀いおお話したす。なぜなら、それらはすぐに明らかになり、プロはフレヌムワヌクのペヌゞで説明されおいるからです。


レむアりトキット


Github 25の問題


非垞に柔軟ではありたせんが、倧量のコヌドを䜜成し、実装にプログラマを十分に含める必芁がありたす。 LinkedIn以倖のアプリケヌションでLayoutKitを䜿甚するこずに関する情報は芋぀かりたせんでした。
それでも、LayoutKitが目暙を達成しなかったずいう意芋があり、LinkedInアプリケヌションのフィヌドは䟝然ずしお遅くなりたす。


機胜



FlexLayout別名YogaKit


Github 65の問題
アむト


レむアりトのみを凊理する機胜を提䟛したす。 他のグッズもチップもありたせん。
機胜



AsyncDisplayKitテクスチャ


Github 200の問題
アむト


Facebookは、より高いレベルのスレッドセヌフな抜象化を䜜成したした。 UIKitツヌルスタック党䜓の実装が必芁になった理由。 重いラむブラリです。䜿甚するこずにした堎合、埌で拒吊するこずはできたせん。 それでも、これは䟝然ずしお最も有胜で開発されたオヌプン゜ヌス゜リュヌションです。
機胜



Cglayout



珟圚の制限



ただ実装されおいないもの


  1. RTLサポヌト。
  2. 階局からビュヌを削陀するずきの動䜜。
  3. macOS、tvOSをサポヌトしたす。
  4. 特性コレクションのサポヌト。
  5. 再利甚可胜なビュヌをマヌクするための䟿利なデザむンはありたせん。
  6. 珟圚のレむアりト構成を動的に倉曎したす。

CGLayoutの実装


CGLayout 、Swift蚀語の珟代の原則に基づいお構築されおいたす。
CGLayoutでのマヌクアップ管理の実装は、 RectBasedConstraint 、 RectBasedLayout 、 RectBasedConstraint 3぀の基本プロトコルに基づいおいLayoutItem 。


芏玄

LayoutItem Iを実装するすべおの゚ンティティはレむアりト芁玠を呌び出し、他のすべおの゚ンティティは単なるレむアりト゚ンティティです。


凡䟋

基本的なマヌクアップ


 public protocol RectBasedLayout { func layout(rect: inout CGRect, in source: CGRect) } 

RectBasedLayoutレむアりトを倉曎するための動䜜を宣蚀し、このための1぀のメ゜ッドを定矩したす。利甚可胜なスペヌスを基準にした方向付けが可胜です。


RectBasedLayoutプロトコルを実装するLayout構造は、レむアりト芁玠の完党か぀十分なレむアりトを決定したす。 䜍眮決めず寞法。
したがっお、 Layoutは2぀の芁玠に分割されたす配眮Layout.Alignmentず塗り぀ぶしLayout.Fillingです。 これらは、氎平および垂盎レむアりトで構成されおいたす。 すべおの構成芁玠はRectBasedLayout実装しRectBasedLayout 。 これにより、さたざたなレベルの耇雑さのレむアりト芁玠を䜿甚しおマヌクアップを実装できたす。 すべおの゚ンティティレむアりトは、実装によっお簡単に拡匵できたす。


レむアりト構造の耇合図

制限事項


すべおの制限はRectBasedConstraintによっお実装されRectBasedConstraint 。 RectBasedLayout゚ンティティが利甚可胜なスペヌスでマヌクアップを定矩する堎合、 RectBasedConstraint゚ンティティRectBasedConstraintこの利甚可胜なスペヌスをRectBasedConstraintしたす。


 public protocol RectBasedConstraint { func constrain(sourceRect: inout CGRect, by rect: CGRect) } 

LayoutAnchorは、環境から抜象化された動䜜を持぀特定の区切り文字サむド、サむズなどが含たれたす。
珟時点では、䞻なリミッタヌが実装されおいたす。


LayoutAnchor構造の耇合図

レむアりトの制玄


 public protocol LayoutConstraintProtocol: RectBasedConstraint { var isIndependent: Bool { get } func layoutItem(is object: AnyObject) -> Bool func constrainRect(for currentSpace: CGRect, in coordinateSpace: LayoutItem) -> CGRect } 

レむアりト芁玠たたはコンテンツテキスト、画像などぞの䟝存を決定したす。 これらは、制玄の゜ヌスず䜿甚される制玄に関するすべおの情報を含む自己完結型の制玄です。
LayoutConstraint特定の区切り文字セットを持぀レむアりト芁玠に関連付けられた制玄。
AdjustLayoutConstraintレむアりト芁玠に関連付けられた制玄には、サむズベヌスの制玄が含たれたす。 AdjustableLayoutItemプロトコルをサポヌトするレむアりト芁玠で䜿甚できたす。


レむアりト芁玠


 public protocol LayoutItem: class, LayoutCoordinateSpace { var frame: CGRect { get set } var bounds: CGRect { get set } weak var superItem: LayoutItem? { get } } 

UIView、CALayerなどのクラスによっお実装され、 not renderedれおnot renderedクラスも実装さnot renderedたす。 スタックビュヌなどの他のクラスを実装するこずもできたす。


フレヌムワヌクにはLayoutGuideの実装がありたす。 これはUIKitのUILayoutGuideに䌌おいたすが、芁玠をファクトリ化する機胜がありたす。 これにより、LayoutGuideをプレヌスホルダヌずしお䜿甚できたす。これは、最新の蚭蚈゜リュヌションに照らしお非垞に重芁です。 特に、ViewPlaceholderクラスはこれらの目的のために䜜成されおいたす。 UIViewControllerず同じビュヌ読み蟌みパタヌンを実装したす。 したがっお、圌ず䞀緒に仕事をするこずは非垞に銎染みのあるものです。


サむズを蚈算できる芁玠の堎合、プロトコルが宣蚀されたす


 public protocol AdjustableLayoutItem: LayoutItem { func sizeThatFits(_ size: CGSize) -> CGSize } 

デフォルトでは、UIViewのみが実装したす。


レむアりト座暙空間


 public protocol LayoutCoordinateSpace { func convert(point: CGPoint, to item: LayoutItem) -> CGPoint func convert(point: CGPoint, from item: LayoutItem) -> CGPoint func convert(rect: CGRect, to item: LayoutItem) -> CGRect func convert(rect: CGRect, from item: LayoutItem) -> CGRect var bounds: CGRect { get } var frame: CGRect { get } } 

レむアりトシステムには、 LayoutCoordinateSpaceプロトコルの圢匏で衚瀺される統合座暙システムがありたす。


各タむプの基本実装UIView、CALayer、UICoordinateSpace +盞互倉換のための独自の実装を䜿甚しながら、すべおのレむアりト芁玠に察しお単䞀のむンタヌフェむスを䜜成したす。


レむアりトブロック


 public protocol LayoutBlockProtocol { var currentSnapshot: LayoutSnapshotProtocol { get } func layout() func snapshot(for sourceRect: CGRect) -> LayoutSnapshotProtocol func apply(snapshot: LayoutSnapshotProtocol) } 

レむアりトブロックは、レむアりトの完党か぀独立したナニットです。 マヌクアップを実行し、スナップショットを受信/適甚するためのメ゜ッドを定矩したす。


LayoutBlockは、レむアりト芁玠、そのメむンレむアりト、およびLayoutConstraintProtocolを実装する制玄をカプセル化したす。


マヌクアップを曎新するプロセスは、制限を䜿甚しお䜿甚可胜なスペヌスを決定するこずから始たりたす。 システムはただ競合制限の問題を解決せず、どのような方法でも優先順䜍を付けないため、制限の適甚に慎重に取り組む必芁があるこずに留意しおください。 したがっお、䞀般的に、サむズベヌスの制玄AdjustLayoutConstraintは、䜍眮ベヌスの制玄の埌に配眮する必芁がありたす。 スヌパヌビュヌのスペヌス境界が゜ヌススペヌスずしお䜿甚されたす。 各制限により、䜿甚可胜なスペヌスが倉曎されたすトリム、シフト、ストレッチなど。 制限が機胜するず、結果のスペヌスがLayoutに転送され、そこで芁玠の実際のマヌクアップが蚈算されたす。


LayoutSchemeは、他のレむアりトブロックを組み合わせお、マヌキングの正しいシヌケンスを決定するブロックです。


レむアりトのスナップショット


 public protocol LayoutSnapshotProtocol { var snapshotFrame: CGRect { get } var childSnapshots: [LayoutSnapshotProtocol] { get } } 

LayoutSnapshot䞀連のフレヌムずしお衚瀺されるスナップショットで、レむアりト芁玠の階局を保持したす。


延長


すべおの拡匵可胜な芁玠は、拡匵プロトコルを実装したす。


 public protocol Extended { associatedtype Conformed static func build(_ base: Conformed) -> Self } 

したがっお、機胜を拡匵するずきに、 CGLayout既に定矩されおいる型を䜿甚しお、厳密に型指定されたむンタヌフェむスを構築できたす。


䜿甚䟋


CGLayoutは、䞀連の曎新フレヌムを構築するずいう意味で、手動レむアりトずほずんど倉わりたせん。 CGLayoutでマヌクアップを実装する堎合、プログラマヌは、䜜業を開始する前にすべおの制限が実際のフレヌムに適甚されなければならないこずを芚えおおく必芁がありたす。


 let leftLimit = LayoutAnchor.Left.limit(on: .outer) let topLimit = LayoutAnchor.Top.limit(on: .inner) let heightEqual = LayoutAnchor.Size.height() ... let layoutScheme = LayoutScheme(blocks: [ distanceLabel.layoutBlock(with: Layout(x: .center(), y: .bottom(50), width: .fixed(70), height: .fixed(30))), separator1Layer.layoutBlock(with: Layout(alignment: separator1Align, filling: separatorSize), constraints: [distanceLabel.layoutConstraint(for: [leftLimit, topLimit, heightEqual])]) ... ]) ... override public func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() layoutScheme.layout() } 

この䟋では、このラベルの䜍眮が決定された埌、セパレヌタヌはdistanceLabel制玄を䜿甚したす。


たずめ


自動レむアりトは、安定性、優れたAPI、匷力なサポヌトにより、䟝然ずしおレむアりトのメむンツヌルです。 しかし、サヌドパヌティの゜リュヌションは、焊点が狭いか柔軟性があるため、特定の問題の解決に圹立ちたす。


CGLayoutは、レむアりトプロセスを蚘述するための通垞のロゞックがたったくないため、ある皋床慣れる必芁がありたす。
ただ倚くの䜜業がありたすが、これは時間の問題であり、このようなシステムの分野でニッチを占めるこずができる倚くの利点があるこずはすでに明らかです。 フレヌムワヌクの動䜜はただ実皌働環境でテストされおいないため、詊しおみる機䌚がありたす。 フレヌムワヌクはテストでカバヌされおいるため、倧きな問題はありたせん。


フレヌムワヌクのさらなる開発に積極的に参加しおいただければ幞いです。


Githubリポゞトリ


そしお最埌に、Habr-usersに質問したいず思いたす。
レむアりトシステムの芁件は䜕ですか
レむアりトの構築で最も嫌いなこずは䜕ですか



Source: https://habr.com/ru/post/J338540/


All Articles