ComponentKit/Core/CKComponentLayout.h (71 lines of code) (raw):

/* * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #import <ComponentKit/CKDefines.h> #if CK_NOT_SWIFT #import <ComponentKit/CKComponent.h> #import <ComponentKit/CKBuildTrigger.h> #import <ComponentKit/RCLayout.h> #import <ComponentKit/CKOptional.h> #import <ComponentKit/CKComponentScopeTypes.h> #import <RenderCore/RCComputeRootLayout.h> @protocol CKAnalyticsListener; @class CKComponentScopeRoot; struct RCLayoutResult; struct RCLayoutCache; struct CKTreeLayoutCache { std::shared_ptr<RCLayoutCache> find(CKComponentScopeRootIdentifier key) const { auto match = map.find(key); if (match != map.end()) { return match->second; } return nullptr; } void update(CKComponentScopeRootIdentifier key, std::shared_ptr<RCLayoutCache> layoutCache) { map.emplace(std::make_pair(key, std::move(layoutCache))); } private: std::unordered_map<CKComponentScopeRootIdentifier, std::shared_ptr<RCLayoutCache>, RC::hash<CKComponentScopeRootIdentifier>> map; }; /** Recursively mounts the layout in the view, returning a set of the mounted components. This function is not for a generic use case of mounting every implementation of `CKMountable`, instead it's only for `CKComponent`. @param layout The layout to mount, usually returned from a call to -layoutThatFits:parentSize: @param view The view in which to mount the layout. @param previouslyMountedComponents If a previous layout was mounted, pass the return value of the previous call to CKMountComponentLayout; any components that are not present in the new layout will be unmounted. @param supercomponent Usually pass nil; if you are mounting a subtree of a layout, pass the parent component so the component responder chain can be connected correctly. @param analyticsListener analytics listener used to log mount time. */ NSSet<id<CKMountable>> *CKMountComponentLayout(const RCLayout &layout, UIView *view, NSSet<id<CKMountable>> *previouslyMountedComponents, id<CKMountable> supercomponent, id<CKAnalyticsListener> analyticsListener = nil); struct CKComponentRootLayout { // This is pending renaming /** Layout cache for components that have controller. */ using ComponentLayoutCache = std::unordered_map<id<CKMountable>, RCLayout, RC::hash<id<CKMountable>>, RC::is_equal<id<CKMountable>>>; using ComponentsByPredicateMap = std::unordered_map<CKMountablePredicate, std::vector<id<CKMountable>>>; CKComponentRootLayout() {} explicit CKComponentRootLayout(RCLayout layout) : CKComponentRootLayout({layout, nil}, {}, {}) {} explicit CKComponentRootLayout(RCLayoutResult layoutResult, ComponentLayoutCache layoutCache, ComponentsByPredicateMap componentsByPredicate) : _layoutResult(std::move(layoutResult)), _layoutCache(std::move(layoutCache)), _componentsByPredicate(std::move(componentsByPredicate)) {} /** This method returns a RCLayout from the cache for the component if it has a controller. @param component The component to look for the layout with. */ auto cachedLayoutForComponent(id<CKMountable> component) const { const auto it = _layoutCache.find(component); return it != _layoutCache.end() ? it->second : RCLayout {}; } auto componentsMatchingPredicate(const CKMountablePredicate p) const { const auto it = _componentsByPredicate.find(p); return it != _componentsByPredicate.end() ? it->second : std::vector<id<CKMountable>> {}; } void enumerateCachedLayout(void(^block)(const RCLayout &layout)) const; const auto &layout() const { return _layoutResult.layout; } const auto &cache() const { return _layoutResult.cache; } auto component() const { return _layoutResult.layout.component; } auto size() const { return _layoutResult.layout.size; } private: RCLayoutResult _layoutResult; ComponentLayoutCache _layoutCache; ComponentsByPredicateMap _componentsByPredicate; }; /** Safely computes the layout of the given root component by guarding against nil components. @param rootComponent The root component to compute the layout for. @param sizeRange The size range to compute the component layout within. @param analyticsListener analytics listener used to log layout time. @param buildTrigger Indicates the source that triggers this layout computation. @param scopeRoot The scope root of the current tree. @param layoutCache An optional layout cache for the current tree. */ CKComponentRootLayout CKComputeRootComponentLayout(id<CKMountable> rootComponent, const CKSizeRange &sizeRange, id<CKAnalyticsListener> analyticsListener = nil, CK::Optional<CKBuildTrigger> buildTrigger = CK::none, CKComponentScopeRoot *scopeRoot = nil, std::shared_ptr<RCLayoutCache> layoutCache = nullptr); /** Safely computes the layout of the given component by guarding against nil components. @param component The component to compute the layout for. @param sizeRange The size range to compute the component layout within. @param parentSize The parent size of the component to compute the layout for. */ RCLayout CKComputeComponentLayout(id<CKMountable> component, const CKSizeRange &sizeRange, const CGSize parentSize); #endif