mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-20 21:29:00 +00:00
[ASScrollNode] Fix small bugs and add unit tests (#637)
* Add unit tests for ASScrollNode * Make sure ASScrollNode's size is clamped against its size range * Invalidate ASScrollNode's calculated layout if its scrollable directions changed * Update comment * Update CHANGELOG * Address Adlai's comments
This commit is contained in:
parent
b01fac35b6
commit
bccde6cf0f
@ -443,6 +443,7 @@
|
|||||||
E5775B041F16759F00CAC9BC /* ASCollectionLayoutCache.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5775B031F16759F00CAC9BC /* ASCollectionLayoutCache.mm */; };
|
E5775B041F16759F00CAC9BC /* ASCollectionLayoutCache.mm in Sources */ = {isa = PBXBuildFile; fileRef = E5775B031F16759F00CAC9BC /* ASCollectionLayoutCache.mm */; };
|
||||||
E5855DEF1EBB4D83003639AE /* ASCollectionLayoutDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = E5855DED1EBB4D83003639AE /* ASCollectionLayoutDefines.m */; };
|
E5855DEF1EBB4D83003639AE /* ASCollectionLayoutDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = E5855DED1EBB4D83003639AE /* ASCollectionLayoutDefines.m */; };
|
||||||
E5855DF01EBB4D83003639AE /* ASCollectionLayoutDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = E5855DEE1EBB4D83003639AE /* ASCollectionLayoutDefines.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
E5855DF01EBB4D83003639AE /* ASCollectionLayoutDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = E5855DEE1EBB4D83003639AE /* ASCollectionLayoutDefines.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||||
|
E586F96C1F9F9E2900ECE00E /* ASScrollNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E586F96B1F9F9E2900ECE00E /* ASScrollNodeTests.m */; };
|
||||||
E58E9E421E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = E58E9E3D1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
E58E9E421E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = E58E9E3D1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
E58E9E431E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E58E9E3E1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.m */; };
|
E58E9E431E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E58E9E3E1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.m */; };
|
||||||
E58E9E441E941D74004CFC59 /* ASCollectionLayoutContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E58E9E3F1E941D74004CFC59 /* ASCollectionLayoutContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
E58E9E441E941D74004CFC59 /* ASCollectionLayoutContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E58E9E3F1E941D74004CFC59 /* ASCollectionLayoutContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
@ -936,6 +937,7 @@
|
|||||||
E5775B031F16759F00CAC9BC /* ASCollectionLayoutCache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionLayoutCache.mm; sourceTree = "<group>"; };
|
E5775B031F16759F00CAC9BC /* ASCollectionLayoutCache.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionLayoutCache.mm; sourceTree = "<group>"; };
|
||||||
E5855DED1EBB4D83003639AE /* ASCollectionLayoutDefines.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionLayoutDefines.m; sourceTree = "<group>"; };
|
E5855DED1EBB4D83003639AE /* ASCollectionLayoutDefines.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionLayoutDefines.m; sourceTree = "<group>"; };
|
||||||
E5855DEE1EBB4D83003639AE /* ASCollectionLayoutDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionLayoutDefines.h; sourceTree = "<group>"; };
|
E5855DEE1EBB4D83003639AE /* ASCollectionLayoutDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionLayoutDefines.h; sourceTree = "<group>"; };
|
||||||
|
E586F96B1F9F9E2900ECE00E /* ASScrollNodeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASScrollNodeTests.m; sourceTree = "<group>"; };
|
||||||
E58E9E3D1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionFlowLayoutDelegate.h; sourceTree = "<group>"; };
|
E58E9E3D1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionFlowLayoutDelegate.h; sourceTree = "<group>"; };
|
||||||
E58E9E3E1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionFlowLayoutDelegate.m; sourceTree = "<group>"; };
|
E58E9E3E1E941D74004CFC59 /* ASCollectionFlowLayoutDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionFlowLayoutDelegate.m; sourceTree = "<group>"; };
|
||||||
E58E9E3F1E941D74004CFC59 /* ASCollectionLayoutContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionLayoutContext.h; sourceTree = "<group>"; };
|
E58E9E3F1E941D74004CFC59 /* ASCollectionLayoutContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionLayoutContext.h; sourceTree = "<group>"; };
|
||||||
@ -1219,6 +1221,7 @@
|
|||||||
E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.m */,
|
E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.m */,
|
||||||
052EE0651A159FEF002C6279 /* ASMultiplexImageNodeTests.m */,
|
052EE0651A159FEF002C6279 /* ASMultiplexImageNodeTests.m */,
|
||||||
058D0A32195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m */,
|
058D0A32195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m */,
|
||||||
|
E586F96B1F9F9E2900ECE00E /* ASScrollNodeTests.m */,
|
||||||
3C9C128419E616EF00E942A0 /* ASTableViewTests.mm */,
|
3C9C128419E616EF00E942A0 /* ASTableViewTests.mm */,
|
||||||
CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.m */,
|
CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.m */,
|
||||||
058D0A33195D057000B7D73C /* ASTextKitCoreTextAdditionsTests.m */,
|
058D0A33195D057000B7D73C /* ASTextKitCoreTextAdditionsTests.m */,
|
||||||
@ -2177,6 +2180,7 @@
|
|||||||
CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */,
|
CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.m in Sources */,
|
||||||
052EE0661A159FEF002C6279 /* ASMultiplexImageNodeTests.m in Sources */,
|
052EE0661A159FEF002C6279 /* ASMultiplexImageNodeTests.m in Sources */,
|
||||||
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */,
|
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */,
|
||||||
|
E586F96C1F9F9E2900ECE00E /* ASScrollNodeTests.m in Sources */,
|
||||||
CC8B05D81D73979700F54286 /* ASTextNodePerformanceTests.m in Sources */,
|
CC8B05D81D73979700F54286 /* ASTextNodePerformanceTests.m in Sources */,
|
||||||
CC583AD91EF9BDC600134156 /* ASDisplayNode+OCMock.m in Sources */,
|
CC583AD91EF9BDC600134156 /* ASDisplayNode+OCMock.m in Sources */,
|
||||||
697B315A1CFE4B410049936F /* ASEditableTextNodeTests.m in Sources */,
|
697B315A1CFE4B410049936F /* ASEditableTextNodeTests.m in Sources */,
|
||||||
|
|||||||
@ -12,6 +12,8 @@
|
|||||||
- [Collection/Table] Added direct support for mapping section indexes between data spaces. [Adlai Holler](https://github.com/Adlai-Holler) [#651](https://github.com/TextureGroup/Texture/pull/660)
|
- [Collection/Table] Added direct support for mapping section indexes between data spaces. [Adlai Holler](https://github.com/Adlai-Holler) [#651](https://github.com/TextureGroup/Texture/pull/660)
|
||||||
- [ASCornerLayoutSpec] New layout spec class for declarative corner element layout. [#657](https://github.com/TextureGroup/Texture/pull/657) [huangkun](https://github.com/huang-kun)
|
- [ASCornerLayoutSpec] New layout spec class for declarative corner element layout. [#657](https://github.com/TextureGroup/Texture/pull/657) [huangkun](https://github.com/huang-kun)
|
||||||
- [Layout] Fix an issue that causes a pending layout to be applied multiple times. [Huy Nguyen](https://github.com/nguyenhuy) [#695](https://github.com/TextureGroup/Texture/pull/695)
|
- [Layout] Fix an issue that causes a pending layout to be applied multiple times. [Huy Nguyen](https://github.com/nguyenhuy) [#695](https://github.com/TextureGroup/Texture/pull/695)
|
||||||
|
- [ASScrollNode] Ensure the node respects the given size range while calculating its layout. [#637](https://github.com/TextureGroup/Texture/pull/637) [Huy Nguyen](https://github.com/nguyenhuy)
|
||||||
|
- [ASScrollNode] Invalidate the node's calculated layout if its scrollable directions changed. Also add unit tests for the class. [#637](https://github.com/TextureGroup/Texture/pull/637) [Huy Nguyen](https://github.com/nguyenhuy)
|
||||||
|
|
||||||
## 2.6
|
## 2.6
|
||||||
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
|
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
|
||||||
|
|||||||
@ -99,10 +99,12 @@
|
|||||||
// To understand this code, imagine we're containing a horizontal stack set within a vertical table node.
|
// To understand this code, imagine we're containing a horizontal stack set within a vertical table node.
|
||||||
// Our parentSize is fixed ~375pt width, but 0 - INF height. Our stack measures 1000pt width, 50pt height.
|
// Our parentSize is fixed ~375pt width, but 0 - INF height. Our stack measures 1000pt width, 50pt height.
|
||||||
// In this case, we want our scrollNode.bounds to be 375pt wide, and 50pt high. ContentSize 1000pt, 50pt.
|
// In this case, we want our scrollNode.bounds to be 375pt wide, and 50pt high. ContentSize 1000pt, 50pt.
|
||||||
// We can achieve this behavior by: 1. Always set contentSize to layout.size. 2. Set bounds to parentSize,
|
// We can achieve this behavior by:
|
||||||
|
// 1. Always set contentSize to layout.size.
|
||||||
|
// 2. Set bounds to a size that is calculated by clamping parentSize against constrained size,
|
||||||
// unless one dimension is not defined, in which case adopt the contentSize for that dimension.
|
// unless one dimension is not defined, in which case adopt the contentSize for that dimension.
|
||||||
_contentCalculatedSizeFromLayout = layout.size;
|
_contentCalculatedSizeFromLayout = layout.size;
|
||||||
CGSize selfSize = parentSize;
|
CGSize selfSize = ASSizeRangeClamp(constrainedSize, parentSize);
|
||||||
if (ASPointsValidForLayout(selfSize.width) == NO) {
|
if (ASPointsValidForLayout(selfSize.width) == NO) {
|
||||||
selfSize.width = _contentCalculatedSizeFromLayout.width;
|
selfSize.width = _contentCalculatedSizeFromLayout.width;
|
||||||
}
|
}
|
||||||
@ -161,7 +163,10 @@
|
|||||||
- (void)setScrollableDirections:(ASScrollDirection)scrollableDirections
|
- (void)setScrollableDirections:(ASScrollDirection)scrollableDirections
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(__instanceLock__);
|
ASDN::MutexLocker l(__instanceLock__);
|
||||||
_scrollableDirections = scrollableDirections;
|
if (_scrollableDirections != scrollableDirections) {
|
||||||
|
_scrollableDirections = scrollableDirections;
|
||||||
|
[self setNeedsLayout];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
139
Tests/ASScrollNodeTests.m
Normal file
139
Tests/ASScrollNodeTests.m
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
//
|
||||||
|
// ASScrollNodeTests.m
|
||||||
|
// Texture
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||||
|
#import "ASXCTExtensions.h"
|
||||||
|
|
||||||
|
@interface ASScrollNodeTests : XCTestCase
|
||||||
|
|
||||||
|
@property (nonatomic) ASScrollNode *scrollNode;
|
||||||
|
@property (nonatomic) ASDisplayNode *subnode;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASScrollNodeTests
|
||||||
|
|
||||||
|
- (void)setUp
|
||||||
|
{
|
||||||
|
ASDisplayNode *subnode = [[ASDisplayNode alloc] init];
|
||||||
|
self.subnode = subnode;
|
||||||
|
|
||||||
|
self.scrollNode = [[ASScrollNode alloc] init];
|
||||||
|
self.scrollNode.scrollableDirections = ASScrollDirectionVerticalDirections;
|
||||||
|
self.scrollNode.automaticallyManagesContentSize = YES;
|
||||||
|
self.scrollNode.automaticallyManagesSubnodes = YES;
|
||||||
|
self.scrollNode.layoutSpecBlock = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
|
||||||
|
return [[ASWrapperLayoutSpec alloc] initWithLayoutElement:subnode];
|
||||||
|
};
|
||||||
|
[self.scrollNode view];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testSubnodeLayoutCalculatedWithUnconstrainedMaxSizeInScrollableDirection
|
||||||
|
{
|
||||||
|
CGSize parentSize = CGSizeMake(100, 100);
|
||||||
|
ASSizeRange sizeRange = ASSizeRangeMake(parentSize);
|
||||||
|
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
|
||||||
|
ASSizeRange subnodeSizeRange = sizeRange;
|
||||||
|
subnodeSizeRange.max.height = CGFLOAT_MAX;
|
||||||
|
XCTAssertEqual(self.scrollNode.scrollableDirections, ASScrollDirectionVerticalDirections);
|
||||||
|
ASXCTAssertEqualSizeRanges(self.subnode.constrainedSizeForCalculatedLayout, subnodeSizeRange);
|
||||||
|
|
||||||
|
// Same test for horizontal scrollable directions
|
||||||
|
self.scrollNode.scrollableDirections = ASScrollDirectionHorizontalDirections;
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
|
||||||
|
subnodeSizeRange = sizeRange;
|
||||||
|
subnodeSizeRange.max.width = CGFLOAT_MAX;
|
||||||
|
|
||||||
|
ASXCTAssertEqualSizeRanges(self.subnode.constrainedSizeForCalculatedLayout, subnodeSizeRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testAutomaticallyManagesContentSizeUnderflow
|
||||||
|
{
|
||||||
|
CGSize subnodeSize = CGSizeMake(100, 100);
|
||||||
|
CGSize parentSize = CGSizeMake(100, 200);
|
||||||
|
ASSizeRange sizeRange = ASSizeRangeUnconstrained;
|
||||||
|
|
||||||
|
self.subnode.style.preferredSize = subnodeSize;
|
||||||
|
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
[self.scrollNode layout];
|
||||||
|
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.calculatedSize, parentSize);
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.view.contentSize, subnodeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testAutomaticallyManagesContentSizeOverflow
|
||||||
|
{
|
||||||
|
CGSize subnodeSize = CGSizeMake(100, 500);
|
||||||
|
CGSize parentSize = CGSizeMake(100, 200);
|
||||||
|
ASSizeRange sizeRange = ASSizeRangeUnconstrained;
|
||||||
|
|
||||||
|
self.subnode.style.preferredSize = subnodeSize;
|
||||||
|
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
[self.scrollNode layout];
|
||||||
|
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.calculatedSize, parentSize);
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.view.contentSize, subnodeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testAutomaticallyManagesContentSizeWithSizeRangeSmallerThanParentSize
|
||||||
|
{
|
||||||
|
CGSize subnodeSize = CGSizeMake(100, 100);
|
||||||
|
CGSize parentSize = CGSizeMake(100, 500);
|
||||||
|
ASSizeRange sizeRange = ASSizeRangeMake(CGSizeMake(100, 100), CGSizeMake(100, 200));
|
||||||
|
|
||||||
|
self.subnode.style.preferredSize = subnodeSize;
|
||||||
|
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
[self.scrollNode layout];
|
||||||
|
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.calculatedSize, sizeRange.max);
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.view.contentSize, subnodeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testAutomaticallyManagesContentSizeWithSizeRangeBiggerThanParentSize
|
||||||
|
{
|
||||||
|
CGSize subnodeSize = CGSizeMake(100, 200);
|
||||||
|
CGSize parentSize = CGSizeMake(100, 100);
|
||||||
|
ASSizeRange sizeRange = ASSizeRangeMake(CGSizeMake(100, 150));
|
||||||
|
|
||||||
|
self.subnode.style.preferredSize = subnodeSize;
|
||||||
|
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
[self.scrollNode layout];
|
||||||
|
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.calculatedSize, sizeRange.min);
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.view.contentSize, subnodeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testAutomaticallyManagesContentSizeWithInvalidCalculatedSizeForLayout
|
||||||
|
{
|
||||||
|
CGSize subnodeSize = CGSizeMake(100, 200);
|
||||||
|
CGSize parentSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
|
||||||
|
ASSizeRange sizeRange = ASSizeRangeUnconstrained;
|
||||||
|
|
||||||
|
self.subnode.style.preferredSize = subnodeSize;
|
||||||
|
|
||||||
|
[self.scrollNode layoutThatFits:sizeRange parentSize:parentSize];
|
||||||
|
[self.scrollNode layout];
|
||||||
|
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.calculatedSize, subnodeSize);
|
||||||
|
ASXCTAssertEqualSizes(self.scrollNode.view.contentSize, subnodeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
Loading…
x
Reference in New Issue
Block a user