flowlayout add header and footer:iOS implement
This commit is contained in:
parent
0dbab344d9
commit
9429c75834
@ -70,23 +70,20 @@ class FlowAdapter extends RecyclerView.Adapter<FlowAdapter.DoricViewHolder> {
|
|||||||
holder.flowLayoutItemNode.blend(jsObject.getProperty("props").asObject());
|
holder.flowLayoutItemNode.blend(jsObject.getProperty("props").asObject());
|
||||||
}
|
}
|
||||||
if ((this.flowLayoutNode.hasHeader() && position == 0)
|
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(
|
StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
holder.itemView.getLayoutParams().height
|
holder.itemView.getLayoutParams().height
|
||||||
);
|
);
|
||||||
layoutParams.setFullSpan(true);
|
layoutParams.setFullSpan(true);
|
||||||
holder.itemView.setLayoutParams(layoutParams);
|
holder.itemView.setLayoutParams(layoutParams);
|
||||||
} else if (this.flowLayoutNode.loadMore
|
}
|
||||||
|
if (this.flowLayoutNode.loadMore
|
||||||
&& position == this.itemCount + (this.flowLayoutNode.hasHeader() ? 1 : 0)
|
&& position == this.itemCount + (this.flowLayoutNode.hasHeader() ? 1 : 0)
|
||||||
&& !TextUtils.isEmpty(this.flowLayoutNode.onLoadMoreFuncId)) {
|
&& !TextUtils.isEmpty(this.flowLayoutNode.onLoadMoreFuncId)) {
|
||||||
callLoadMore();
|
callLoadMore();
|
||||||
StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
holder.itemView.getLayoutParams().height
|
|
||||||
);
|
|
||||||
layoutParams.setFullSpan(true);
|
|
||||||
holder.itemView.setLayoutParams(layoutParams);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class FlowDemo extends Panel {
|
|||||||
layoutConfig: layoutConfig().configWidth(LayoutSpec.MOST),
|
layoutConfig: layoutConfig().configWidth(LayoutSpec.MOST),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadMore: false,
|
loadMore: true,
|
||||||
onLoadMore: () => {
|
onLoadMore: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
flowView.itemCount += 20
|
flowView.itemCount += 20
|
||||||
|
@ -28,6 +28,8 @@ - (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath;
|
|||||||
|
|
||||||
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath;
|
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
|
- (BOOL)doricFlowLayoutItemFullSpan:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
- (CGFloat)doricFlowLayoutColumnSpace;
|
- (CGFloat)doricFlowLayoutColumnSpace;
|
||||||
|
|
||||||
- (CGFloat)doricFlowLayoutRowSpace;
|
- (CGFloat)doricFlowLayoutRowSpace;
|
||||||
@ -92,7 +94,7 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
|
|||||||
NSNumber *minYOfColumn = @(0);
|
NSNumber *minYOfColumn = @(0);
|
||||||
NSArray<NSNumber *> *keys = self.columnHeightInfo.allKeys;
|
NSArray<NSNumber *> *keys = self.columnHeightInfo.allKeys;
|
||||||
NSArray<NSNumber *> *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
|
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) {
|
for (NSNumber *key in sortedKeys) {
|
||||||
@ -100,17 +102,15 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
|
|||||||
minYOfColumn = key;
|
minYOfColumn = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CGFloat width = [self.delegate doricFlowLayoutItemWidthAtIndexPath:indexPath];
|
CGFloat width = [self.delegate doricFlowLayoutItemWidthAtIndexPath:indexPath];
|
||||||
CGFloat height = [self.delegate doricFlowLayoutItemHeightAtIndexPath:indexPath];
|
CGFloat height = [self.delegate doricFlowLayoutItemHeightAtIndexPath:indexPath];
|
||||||
CGFloat x = (width + self.columnSpace) * [minYOfColumn integerValue];
|
CGFloat x = 0;
|
||||||
CGFloat y = [self.columnHeightInfo[minYOfColumn] floatValue];
|
CGFloat y = [self.columnHeightInfo[minYOfColumn] floatValue];
|
||||||
if (y > 0) {
|
if (y > 0) {
|
||||||
y += self.rowSpace;
|
y += self.rowSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width == self.collectionView.width) {
|
if ([self.delegate doricFlowLayoutItemFullSpan:indexPath]) {
|
||||||
x = 0;
|
|
||||||
NSNumber *maxYColumn = @(0);
|
NSNumber *maxYColumn = @(0);
|
||||||
for (NSNumber *key in sortedKeys) {
|
for (NSNumber *key in sortedKeys) {
|
||||||
if ([self.columnHeightInfo[key] floatValue] > [self.columnHeightInfo[maxYColumn] floatValue]) {
|
if ([self.columnHeightInfo[key] floatValue] > [self.columnHeightInfo[maxYColumn] floatValue]) {
|
||||||
@ -119,8 +119,12 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
|
|||||||
}
|
}
|
||||||
CGFloat maxY = [self.columnHeightInfo[maxYColumn] floatValue];
|
CGFloat maxY = [self.columnHeightInfo[maxYColumn] floatValue];
|
||||||
y = maxY + self.rowSpace;
|
y = maxY + self.rowSpace;
|
||||||
self.columnHeightInfo[maxYColumn] = @(y + height);
|
for (NSNumber *key in self.columnHeightInfo.allKeys) {
|
||||||
|
self.columnHeightInfo[key] = @(y + height);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
CGFloat columnWidth = (self.collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
|
||||||
|
x = (columnWidth + self.columnSpace) * [minYOfColumn integerValue];
|
||||||
self.columnHeightInfo[minYOfColumn] = @(y + height);
|
self.columnHeightInfo[minYOfColumn] = @(y + height);
|
||||||
}
|
}
|
||||||
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
||||||
@ -163,6 +167,8 @@ @interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewD
|
|||||||
|
|
||||||
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
|
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
|
||||||
@property(nonatomic, copy) NSString *loadMoreViewId;
|
@property(nonatomic, copy) NSString *loadMoreViewId;
|
||||||
|
@property(nonatomic, copy) NSString *headerViewId;
|
||||||
|
@property(nonatomic, copy) NSString *footerViewId;
|
||||||
@property(nonatomic, assign) BOOL loadMore;
|
@property(nonatomic, assign) BOOL loadMore;
|
||||||
@property(nonatomic, strong) NSMutableSet <DoricDidScrollBlock> *didScrollBlocks;
|
@property(nonatomic, strong) NSMutableSet <DoricDidScrollBlock> *didScrollBlocks;
|
||||||
@property(nonatomic, copy) NSString *onScrollFuncId;
|
@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 {
|
- (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||||
if ([@"scrollable" isEqualToString:name]) {
|
if ([@"scrollable" isEqualToString:name]) {
|
||||||
self.view.scrollEnabled = [prop boolValue];
|
self.view.scrollEnabled = [prop boolValue];
|
||||||
@ -240,14 +254,35 @@ - (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValu
|
|||||||
self.onScrollFuncId = prop;
|
self.onScrollFuncId = prop;
|
||||||
} else if ([@"onScrollEnd" isEqualToString:name]) {
|
} else if ([@"onScrollEnd" isEqualToString:name]) {
|
||||||
self.onScrollEndFuncId = prop;
|
self.onScrollEndFuncId = prop;
|
||||||
|
} else if ([@"header" isEqualToString:name]) {
|
||||||
|
self.headerViewId = prop;
|
||||||
|
} else if ([@"footer" isEqualToString:name]) {
|
||||||
|
self.footerViewId = prop;
|
||||||
} else {
|
} else {
|
||||||
[super blendView:view forPropName:name propValue:prop];
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)itemModelAt:(NSUInteger)position {
|
- (NSDictionary *)itemModelAt:(NSUInteger)position {
|
||||||
if (position >= self.itemCount) {
|
if (self.hasHeader && position == 0) {
|
||||||
return [self subModelOf:self.loadMoreViewId];
|
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)];
|
NSString *viewId = self.itemViewIds[@(position)];
|
||||||
if (viewId && viewId.length > 0) {
|
if (viewId && viewId.length > 0) {
|
||||||
@ -331,7 +366,7 @@ - (void)callLoadMore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
- (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 {
|
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
@ -339,7 +374,18 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
|
|||||||
NSDictionary *model = [self itemModelAt:position];
|
NSDictionary *model = [self itemModelAt:position];
|
||||||
NSDictionary *props = model[@"props"];
|
NSDictionary *props = model[@"props"];
|
||||||
NSString *identifier = props[@"identifier"] ?: @"doricCell";
|
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";
|
identifier = @"doricLoadMoreCell";
|
||||||
[self callLoadMore];
|
[self callLoadMore];
|
||||||
}
|
}
|
||||||
@ -355,7 +401,16 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
|
|||||||
DoricFlowLayoutItemNode *node = cell.viewNode;
|
DoricFlowLayoutItemNode *node = cell.viewNode;
|
||||||
node.viewId = model[@"id"];
|
node.viewId = model[@"id"];
|
||||||
[node blend:props];
|
[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;
|
node.view.width = collectionView.width;
|
||||||
} else {
|
} else {
|
||||||
node.view.width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
|
node.view.width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
|
||||||
@ -399,6 +454,19 @@ - (NSInteger)doricFlowLayoutColumnCount {
|
|||||||
return self.columnCount;
|
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 {
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||||
for (DoricDidScrollBlock block in self.didScrollBlocks) {
|
for (DoricDidScrollBlock block in self.didScrollBlocks) {
|
||||||
block(scrollView);
|
block(scrollView);
|
||||||
|
@ -168,7 +168,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
|
|||||||
&& position == self.itemCount
|
&& position == self.itemCount
|
||||||
+ (self.loadMore ? 1 : 0)
|
+ (self.loadMore ? 1 : 0)
|
||||||
+ (self.hasHeader ? 1 : 0)
|
+ (self.hasHeader ? 1 : 0)
|
||||||
+ (self.hasFooter ? 1 : 0)) {
|
+ (self.hasFooter ? 1 : 0)
|
||||||
|
- 1) {
|
||||||
reuseId = @"doricFooterCell";
|
reuseId = @"doricFooterCell";
|
||||||
} else if (self.loadMore
|
} else if (self.loadMore
|
||||||
&& position == self.itemCount + (self.hasHeader ? 1 : 0)
|
&& position == self.itemCount + (self.hasHeader ? 1 : 0)
|
||||||
@ -269,8 +270,12 @@ - (NSDictionary *)itemModelAt:(NSUInteger)position {
|
|||||||
- 1) {
|
- 1) {
|
||||||
return [self subModelOf:self.footerViewId];
|
return [self subModelOf:self.footerViewId];
|
||||||
}
|
}
|
||||||
if (position >= self.itemCount + (self.hasHeader ? 1 : 0)) {
|
if (self.loadMore && position >= self.itemCount + (self.hasHeader ? 1 : 0)) {
|
||||||
return [self subModelOf:self.loadMoreViewId];
|
if (self.loadMoreViewId && self.loadMoreViewId.length > 0) {
|
||||||
|
return [self subModelOf:self.loadMoreViewId];
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (self.hasHeader) {
|
if (self.hasHeader) {
|
||||||
position--;
|
position--;
|
||||||
|
5
doric-js/index.d.ts
vendored
5
doric-js/index.d.ts
vendored
@ -143,6 +143,11 @@ declare module 'doric/lib/src/ui/panel' {
|
|||||||
onShow(): void;
|
onShow(): void;
|
||||||
onHidden(): void;
|
onHidden(): void;
|
||||||
onEnvChanged(): 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;
|
abstract build(rootView: Group): void;
|
||||||
addHeadView(type: string, v: View): void;
|
addHeadView(type: string, v: View): void;
|
||||||
allHeadViews(): IterableIterator<Map<string, View>>;
|
allHeadViews(): IterableIterator<Map<string, View>>;
|
||||||
|
5
doric-js/lib/src/ui/panel.d.ts
vendored
5
doric-js/lib/src/ui/panel.d.ts
vendored
@ -10,6 +10,11 @@ export declare abstract class Panel {
|
|||||||
onShow(): void;
|
onShow(): void;
|
||||||
onHidden(): void;
|
onHidden(): void;
|
||||||
onEnvChanged(): 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;
|
abstract build(rootView: Group): void;
|
||||||
private __data__?;
|
private __data__?;
|
||||||
private __root__;
|
private __root__;
|
||||||
|
@ -43,6 +43,11 @@ export abstract class Panel {
|
|||||||
this.__root__.children.length = 0
|
this.__root__.children.length = 0
|
||||||
this.build(this.__root__)
|
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
|
abstract build(rootView: Group): void
|
||||||
|
|
||||||
private __data__?: object
|
private __data__?: object
|
||||||
|
Reference in New Issue
Block a user