diff --git a/iOS/Pod/Classes/Shader/DoricSliderNode.m b/iOS/Pod/Classes/Shader/DoricSliderNode.m index 98c49081..78be0e6f 100644 --- a/iOS/Pod/Classes/Shader/DoricSliderNode.m +++ b/iOS/Pod/Classes/Shader/DoricSliderNode.m @@ -19,10 +19,150 @@ // // Created by pengfei.zhou on 2019/11/19. // +#import #import "DoricSliderNode.h" +#import "Doric.h" +#import "DoricSlideItemNode.h" +@interface DoricCollectionViewCell : UICollectionViewCell +@property(nonatomic, strong) DoricSlideItemNode *doricSlideItemNode; +@end -@implementation DoricSliderNode { +@implementation DoricCollectionViewCell +@end +@interface DoricSliderNode () +@property(nonatomic, strong) NSMutableDictionary *itemViewIds; +@property(nonatomic, assign) NSUInteger itemCount; +@property(nonatomic, assign) NSUInteger batchCount; +@end + +@implementation DoricSliderNode +- (instancetype)initWithContext:(DoricContext *)doricContext { + if (self = [super initWithContext:doricContext]) { + _itemViewIds = [NSMutableDictionary new]; + _batchCount = 15; + } + return self; +} + +- (UICollectionView *)build { + UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init]; + [flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal]; + + return [[[UICollectionView alloc] initWithFrame:CGRectZero + collectionViewLayout:flowLayout] + also:^(UICollectionView *it) { + it.backgroundColor = [UIColor whiteColor]; + it.delegate = self; + it.dataSource = self; + [it registerClass:[DoricCollectionViewCell class] forCellWithReuseIdentifier:@"doricCell"]; + }]; +} + +- (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop { + if ([@"itemCount" isEqualToString:name]) { + self.itemCount = [prop unsignedIntegerValue]; + } else if ([@"renderPage" isEqualToString:name]) { + [self.itemViewIds removeAllObjects]; + [self clearSubModel]; + } else if ([@"batchCount" isEqualToString:name]) { + self.batchCount = [prop unsignedIntegerValue]; + } else { + [super blendView:view forPropName:name propValue:prop]; + } +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.itemCount; +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(self.view.width, self.view.height); +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 0; +} + +- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + NSUInteger position = (NSUInteger) indexPath.row; + NSDictionary *model = [self itemModelAt:position]; + NSDictionary *props = model[@"props"]; + DoricCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"doricCell" forIndexPath:indexPath]; + if (!cell.doricSlideItemNode) { + DoricSlideItemNode *slideItemNode = [[DoricSlideItemNode alloc] initWithContext:self.doricContext]; + [slideItemNode initWithSuperNode:self]; + cell.doricSlideItemNode = slideItemNode; + [cell.contentView addSubview:slideItemNode.view]; + } + DoricSlideItemNode *node = cell.doricSlideItemNode; + node.viewId = model[@"id"]; + [node blend:props]; + [node.view setNeedsLayout]; + return cell; +} + +- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { + return NO; +} + +- (NSDictionary *)itemModelAt:(NSUInteger)position { + NSString *viewId = self.itemViewIds[@(position)]; + if (viewId && viewId.length > 0) { + return [self subModelOf:viewId]; + } else { + DoricAsyncResult *result = [self callJSResponse:@"renderBunchedItems", @(position), @(self.batchCount), nil]; + JSValue *models = [result waitUntilResult]; + NSArray *array = [models toArray]; + [array enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) { + NSString *thisViewId = obj[@"id"]; + [self setSubModel:obj in:thisViewId]; + NSUInteger pos = position + idx; + self.itemViewIds[@(pos)] = thisViewId; + }]; + return array[0]; + } +} + +- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId { + __block DoricViewNode *ret = nil; + [self.doricContext.driver ensureSyncInMainQueue:^{ + for (UICollectionViewCell *collectionViewCell in self.view.visibleCells) { + if ([collectionViewCell isKindOfClass:[DoricCollectionViewCell class]]) { + DoricSlideItemNode *node = ((DoricCollectionViewCell *) collectionViewCell).doricSlideItemNode; + if ([viewId isEqualToString:node.viewId]) { + ret = node; + break; + } + } + } + }]; + return ret; +} + +- (void)blendSubNode:(NSDictionary *)subModel { + NSString *viewId = subModel[@"id"]; + DoricViewNode *viewNode = [self subNodeWithViewId:viewId]; + if (viewNode) { + [viewNode blend:subModel[@"props"]]; + } else { + NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy]; + [self recursiveMixin:subModel to:model]; + [self setSubModel:model in:viewId]; + [self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) { + if ([viewId isEqualToString:obj]) { + *stop = YES; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0]; + [UIView performWithoutAnimation:^{ + [self.view reloadItemsAtIndexPaths:@[indexPath]]; + }]; + } + }]; + } } @end \ No newline at end of file