flowlayout add header and footer:iOS implement

This commit is contained in:
pengfei.zhou 2021-10-11 15:58:46 +08:00 committed by osborn
parent 0dbab344d9
commit 9429c75834
7 changed files with 108 additions and 23 deletions

View File

@ -70,23 +70,20 @@ class FlowAdapter extends RecyclerView.Adapter<FlowAdapter.DoricViewHolder> {
holder.flowLayoutItemNode.blend(jsObject.getProperty("props").asObject());
}
if ((this.flowLayoutNode.hasHeader() && position == 0)
|| (this.flowLayoutNode.hasFooter() && position == this.getItemCount() - 1)) {
|| (this.flowLayoutNode.hasFooter() && position == this.getItemCount() - 1)
|| this.flowLayoutNode.loadMore
&& position == this.itemCount + (this.flowLayoutNode.hasHeader() ? 1 : 0)) {
StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
holder.itemView.getLayoutParams().height
);
layoutParams.setFullSpan(true);
holder.itemView.setLayoutParams(layoutParams);
} else if (this.flowLayoutNode.loadMore
}
if (this.flowLayoutNode.loadMore
&& position == this.itemCount + (this.flowLayoutNode.hasHeader() ? 1 : 0)
&& !TextUtils.isEmpty(this.flowLayoutNode.onLoadMoreFuncId)) {
callLoadMore();
StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
holder.itemView.getLayoutParams().height
);
layoutParams.setFullSpan(true);
holder.itemView.setLayoutParams(layoutParams);
}
}

View File

@ -43,7 +43,7 @@ class FlowDemo extends Panel {
layoutConfig: layoutConfig().configWidth(LayoutSpec.MOST),
})
},
loadMore: false,
loadMore: true,
onLoadMore: () => {
setTimeout(() => {
flowView.itemCount += 20

View File

@ -28,6 +28,8 @@ - (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)doricFlowLayoutItemFullSpan:(NSIndexPath *)indexPath;
- (CGFloat)doricFlowLayoutColumnSpace;
- (CGFloat)doricFlowLayoutRowSpace;
@ -92,7 +94,7 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
NSNumber *minYOfColumn = @(0);
NSArray<NSNumber *> *keys = self.columnHeightInfo.allKeys;
NSArray<NSNumber *> *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
return [obj1 intValue] <= [obj2 intValue] ? -1 : 1;
return ([obj1 intValue] <= [obj2 intValue] ? NSOrderedAscending : NSOrderedDescending);
}];
for (NSNumber *key in sortedKeys) {
@ -100,17 +102,15 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
minYOfColumn = key;
}
}
CGFloat width = [self.delegate doricFlowLayoutItemWidthAtIndexPath:indexPath];
CGFloat height = [self.delegate doricFlowLayoutItemHeightAtIndexPath:indexPath];
CGFloat x = (width + self.columnSpace) * [minYOfColumn integerValue];
CGFloat x = 0;
CGFloat y = [self.columnHeightInfo[minYOfColumn] floatValue];
if (y > 0) {
y += self.rowSpace;
}
if (width == self.collectionView.width) {
x = 0;
if ([self.delegate doricFlowLayoutItemFullSpan:indexPath]) {
NSNumber *maxYColumn = @(0);
for (NSNumber *key in sortedKeys) {
if ([self.columnHeightInfo[key] floatValue] > [self.columnHeightInfo[maxYColumn] floatValue]) {
@ -119,8 +119,12 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
}
CGFloat maxY = [self.columnHeightInfo[maxYColumn] floatValue];
y = maxY + self.rowSpace;
self.columnHeightInfo[maxYColumn] = @(y + height);
for (NSNumber *key in self.columnHeightInfo.allKeys) {
self.columnHeightInfo[key] = @(y + height);
}
} else {
CGFloat columnWidth = (self.collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
x = (columnWidth + self.columnSpace) * [minYOfColumn integerValue];
self.columnHeightInfo[minYOfColumn] = @(y + height);
}
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
@ -163,6 +167,8 @@ @interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewD
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
@property(nonatomic, copy) NSString *loadMoreViewId;
@property(nonatomic, copy) NSString *headerViewId;
@property(nonatomic, copy) NSString *footerViewId;
@property(nonatomic, assign) BOOL loadMore;
@property(nonatomic, strong) NSMutableSet <DoricDidScrollBlock> *didScrollBlocks;
@property(nonatomic, copy) NSString *onScrollFuncId;
@ -201,6 +207,14 @@ - (UICollectionView *)build {
}];
}
- (BOOL)hasHeader {
return self.headerViewId && self.headerViewId.length > 0;
}
- (BOOL)hasFooter {
return self.footerViewId && self.footerViewId.length > 0;
}
- (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"scrollable" isEqualToString:name]) {
self.view.scrollEnabled = [prop boolValue];
@ -240,14 +254,35 @@ - (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValu
self.onScrollFuncId = prop;
} else if ([@"onScrollEnd" isEqualToString:name]) {
self.onScrollEndFuncId = prop;
} else if ([@"header" isEqualToString:name]) {
self.headerViewId = prop;
} else if ([@"footer" isEqualToString:name]) {
self.footerViewId = prop;
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (NSDictionary *)itemModelAt:(NSUInteger)position {
if (position >= self.itemCount) {
return [self subModelOf:self.loadMoreViewId];
if (self.hasHeader && position == 0) {
return [self subModelOf:self.headerViewId];
}
if (self.hasFooter && position == self.itemCount
+ (self.loadMore ? 1 : 0)
+ (self.hasHeader ? 1 : 0)
+ (self.hasFooter ? 1 : 0)
- 1) {
return [self subModelOf:self.footerViewId];
}
if (self.loadMore && position >= self.itemCount + (self.hasHeader ? 1 : 0)) {
if (self.loadMoreViewId && self.loadMoreViewId.length > 0) {
return [self subModelOf:self.loadMoreViewId];
} else {
return nil;
}
}
if (self.hasHeader) {
position--;
}
NSString *viewId = self.itemViewIds[@(position)];
if (viewId && viewId.length > 0) {
@ -331,7 +366,7 @@ - (void)callLoadMore {
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.itemCount + (self.loadMore ? 1 : 0);
return self.itemCount + (self.loadMore ? 1 : 0) + (self.hasHeader ? 1 : 0) + (self.hasFooter ? 1 : 0);
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
@ -339,7 +374,18 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
NSDictionary *model = [self itemModelAt:position];
NSDictionary *props = model[@"props"];
NSString *identifier = props[@"identifier"] ?: @"doricCell";
if (position >= self.itemCount && self.onLoadMoreFuncId) {
if (self.hasHeader && position == 0) {
identifier = @"doricHeaderCell";
} else if (self.hasFooter
&& position == self.itemCount
+ (self.loadMore ? 1 : 0)
+ (self.hasHeader ? 1 : 0)
+ (self.hasFooter ? 1 : 0)
- 1) {
identifier = @"doricFooterCell";
} else if (self.loadMore
&& position == self.itemCount + (self.hasHeader ? 1 : 0)
&& self.onLoadMoreFuncId) {
identifier = @"doricLoadMoreCell";
[self callLoadMore];
}
@ -355,7 +401,16 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
DoricFlowLayoutItemNode *node = cell.viewNode;
node.viewId = model[@"id"];
[node blend:props];
if (position >= self.itemCount) {
BOOL fillWidth = (self.hasHeader && position == 0)
|| (self.hasFooter
&& position == self.itemCount
+ (self.loadMore ? 1 : 0)
+ (self.hasHeader ? 1 : 0)
+ (self.hasFooter ? 1 : 0)
- 1)
|| (self.loadMore
&& position == self.itemCount + (self.hasHeader ? 1 : 0));
if (fillWidth) {
node.view.width = collectionView.width;
} else {
node.view.width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
@ -399,6 +454,19 @@ - (NSInteger)doricFlowLayoutColumnCount {
return self.columnCount;
}
- (BOOL)doricFlowLayoutItemFullSpan:(NSIndexPath *)indexPath {
NSUInteger position = (NSUInteger) indexPath.row;
return (self.hasHeader && position == 0)
|| (self.hasFooter
&& position == self.itemCount
+ (self.loadMore ? 1 : 0)
+ (self.hasHeader ? 1 : 0)
+ (self.hasFooter ? 1 : 0)
- 1)
|| (self.loadMore
&& position == self.itemCount + (self.hasHeader ? 1 : 0));
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
for (DoricDidScrollBlock block in self.didScrollBlocks) {
block(scrollView);

View File

@ -168,7 +168,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
&& position == self.itemCount
+ (self.loadMore ? 1 : 0)
+ (self.hasHeader ? 1 : 0)
+ (self.hasFooter ? 1 : 0)) {
+ (self.hasFooter ? 1 : 0)
- 1) {
reuseId = @"doricFooterCell";
} else if (self.loadMore
&& position == self.itemCount + (self.hasHeader ? 1 : 0)
@ -269,8 +270,12 @@ - (NSDictionary *)itemModelAt:(NSUInteger)position {
- 1) {
return [self subModelOf:self.footerViewId];
}
if (position >= self.itemCount + (self.hasHeader ? 1 : 0)) {
return [self subModelOf:self.loadMoreViewId];
if (self.loadMore && position >= self.itemCount + (self.hasHeader ? 1 : 0)) {
if (self.loadMoreViewId && self.loadMoreViewId.length > 0) {
return [self subModelOf:self.loadMoreViewId];
} else {
return nil;
}
}
if (self.hasHeader) {
position--;

5
doric-js/index.d.ts vendored
View File

@ -143,6 +143,11 @@ declare module 'doric/lib/src/ui/panel' {
onShow(): void;
onHidden(): void;
onEnvChanged(): void;
/**
* Build view of the current Panel
* This could be called any times at any time when necessary.
* @param rootView root view of this panel
*/
abstract build(rootView: Group): void;
addHeadView(type: string, v: View): void;
allHeadViews(): IterableIterator<Map<string, View>>;

View File

@ -10,6 +10,11 @@ export declare abstract class Panel {
onShow(): void;
onHidden(): void;
onEnvChanged(): void;
/**
* Build view of the current Panel
* This could be called any times at any time when necessary.
* @param rootView root view of this panel
*/
abstract build(rootView: Group): void;
private __data__?;
private __root__;

View File

@ -43,6 +43,11 @@ export abstract class Panel {
this.__root__.children.length = 0
this.build(this.__root__)
}
/**
* Build view of the current Panel
* This could be called any times at any time when necessary.
* @param rootView root view of this panel
*/
abstract build(rootView: Group): void
private __data__?: object