Skip to content

Commit 8e59529

Browse files
committed
feat(ios): waterfall component support footer view (#4098)
refactor waterfall component
1 parent 2d07005 commit 8e59529

File tree

13 files changed

+238
-136
lines changed

13 files changed

+238
-136
lines changed

docs/api/hippy-react/components.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,8 @@ import icon from './qb_icon_new.png';
541541
| interItemSpacing | item 间的垂直间距 | `number` | `Android、iOS、Voltron` |
542542
| contentInset | 内容缩进 ,默认值 `{ top:0, left:0, bottom:0, right:0 }` | `Object` | `Android、iOS、Voltron` |
543543
| renderItem | 这里的入参是当前 item 的 index,在这里可以凭借 index 获取到瀑布流一个具体单元格的数据,从而决定如何渲染这个单元格。 | `(index: number) => React.ReactElement` | `Android、iOS、Voltron` |
544-
| renderBanner | 如何渲染 Banner。 | `() => React.ReactElement` | `Android、iOS、Voltron`
544+
| renderBanner | 如何渲染 Banner (即Header,显示在内容顶部) | `() => React.ReactElement` | `Android、iOS、Voltron` |
545+
| renderFooter | 如何渲染 Footer(与renderBanner对应,Footer显示在内容底部) | `() => React.ReactElement` | `iOS`(3.3.2版本起支持) |
545546
| getItemStyle | 设置`WaterfallItem`容器的样式。 | `(index: number) => styleObject` | `Android、iOS、Voltron` |
546547
| getItemType | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升list 性能。 | `(index: number) => number` | `Android、iOS、Voltron` |
547548
| getItemKey | 指定一个函数,在其中返回对应条目的 Key 值,详见 [React 官文](//reactjs.org/docs/lists-and-keys.html) | `(index: number) => any` | `Android、iOS、Voltron` |

docs/api/hippy-vue/external-components.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ export default {
280280
| columnSpacing | 瀑布流每列之前的水平间距 | `number` | `Android、iOS、Voltron` |
281281
| interItemSpacing | item 间的垂直间距 | `number` | `Android、iOS、Voltron` |
282282
| contentInset | 内容缩进 ,默认值 `{ top:0, left:0, bottom:0, right:0 }` | `Object` | `Android、iOS、Voltron` |
283-
| containBannerView | 是否包含`bannerView`,只能有一个bannerView,`Android` 暂不支持 | `boolean` | `iOS、Voltron` |
283+
| containBannerView | 是否包含`bannerView`,只能有一个bannerView, (`Android` 暂不支持`iOS` 3.3.2版本起已废弃该属性,请使用`waterfall-item`组件`isHeader/isFooter`属性代替) | `boolean` | `iOS、Voltron` |
284284
| containPullHeader | 是否包含`pull-header``Android` 暂不支持,可以用 `ul-refresh` 组件替代 | `boolean` | `iOS、Voltron` |
285285
| containPullFooter | 是否包含 `pull-footer` | `boolean` | `Android、iOS、Voltron` |
286286
| numberOfColumns | 瀑布流列数量,Default: 2 | `number` | `Android、iOS、Voltron` |
@@ -323,3 +323,5 @@ export default {
323323
| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | -------- |
324324
| type | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升 List 性能。 | `number` | `Android、iOS、Voltron` |
325325
| key | 指定一个函数,在其中返回对应条目的 Key 值,详见 [Vue 官网](//vuejs.org/v2/guide/list.html) | `string` | `Android、iOS、Voltron` |
326+
| isHeader | 指定该Item是否为Header(即bannerView,显示在内容区顶部) | `boolean` | `iOS`(3.3.2版本起支持) |
327+
| isFooter | 指定该Item是否为Footer(显示在内容区底部) | `boolean` | `iOS`(3.3.2版本起支持) |

driver/js/examples/hippy-react-demo/src/components/WaterfallView/index.jsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export default class ListExample extends React.Component {
7474
this.onHeaderPulling = this.onHeaderPulling.bind(this);
7575
this.onFooterPulling = this.onFooterPulling.bind(this);
7676
this.renderBanner = this.renderBanner.bind(this);
77+
this.renderFooter = this.renderFooter.bind(this);
7778
this.getItemStyle = this.getItemStyle.bind(this);
7879
this.getHeaderStyle = this.getHeaderStyle.bind(this);
7980
this.onScroll = this.onScroll.bind(this);
@@ -236,10 +237,10 @@ export default class ListExample extends React.Component {
236237
}
237238

238239
onScroll(obj) {
239-
240+
console.log('onScroll', obj);
240241
}
241242

242-
// render banner(it is not supported on Android yet)
243+
// render banner
243244
renderBanner() {
244245
if (this.state.dataSource.length === 0) return null;
245246
return (<View style={{
@@ -257,6 +258,24 @@ export default class ListExample extends React.Component {
257258
</View>);
258259
}
259260

261+
// render footer (currently only iOS support)
262+
renderFooter() {
263+
if (this.state.dataSource.length === 0) return null;
264+
return (<View style={{
265+
backgroundColor: 'grey',
266+
height: 100,
267+
justifyContent: 'center',
268+
alignItems: 'center',
269+
}}>
270+
<Text style={{
271+
fontSize: 20,
272+
color: 'white',
273+
lineHeight: 100,
274+
height: 100,
275+
}}>Footer View</Text>
276+
</View>);
277+
}
278+
260279
renderItem(index) {
261280
const { dataSource } = this.state;
262281
let styleUI = null;
@@ -361,7 +380,9 @@ export default class ListExample extends React.Component {
361380
style={{ flex: 1 }}
362381
onScroll={this.onScroll}
363382
renderBanner={this.renderBanner}
383+
renderFooter={this.renderFooter}
364384
renderPullHeader={this.renderPullHeader}
385+
renderPullFooter={this.renderPullFooter}
365386
onEndReached={this.onEndReached}
366387
onFooterReleased={this.onEndReached}
367388
onHeaderReleased={this.onHeaderReleased}

driver/js/examples/hippy-vue-demo/src/components/native-demos/demo-waterfall.vue

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
ref="gridView"
55
:content-inset="contentInset"
66
:column-spacing="columnSpacing"
7-
:contain-banner-view="isIos"
87
:contain-pull-footer="true"
98
:inter-item-spacing="interItemSpacing"
109
:number-of-columns="numberOfColumns"
@@ -25,16 +24,17 @@
2524
</p>
2625
</pull-header>
2726
<div
28-
v-if="isIos"
27+
v-if="!isAndroid && !isiOS"
2928
class="banner-view"
3029
>
3130
<span>BannerView</span>
32-
</div>
31+
</div>
3332
<waterfall-item
3433
:fullSpan="true",
34+
:isHeader="true",
3535
class="banner-view"
3636
>
37-
<span>BannerView</span>
37+
<span>Banner View</span>
3838
</waterfall-item>
3939
<waterfall-item
4040
v-for="(ui, index) in dataSource"
@@ -56,6 +56,13 @@
5656
:item-bean="ui.itemBean"
5757
/>
5858
</waterfall-item>
59+
<waterfall-item
60+
:fullSpan="true",
61+
:isFooter="true",
62+
class="banner-view"
63+
>
64+
<span>Footer View</span>
65+
</waterfall-item>
5966
<pull-footer
6067
ref="pullFooter"
6168
class="pull-footer"
@@ -89,7 +96,8 @@ export default {
8996
headerRefreshText: '继续下拉触发刷新',
9097
footerRefreshText: '正在加载...',
9198
isLoading: false,
92-
isIos: Vue.Native.Platform === 'ios',
99+
isAndroid: Vue.Native.Platform === 'android',
100+
isiOS: Vue.Native.Platform === 'android',
93101
};
94102
},
95103
mounted() {

driver/js/examples/hippy-vue-next-demo/src/components/native-demo/demo-waterfall.vue

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
ref="gridView"
55
:content-inset="contentInset"
66
:column-spacing="columnSpacing"
7-
:contain-banner-view="true"
87
:contain-pull-footer="true"
98
:inter-item-spacing="interItemSpacing"
109
:number-of-columns="numberOfColumns"
@@ -25,17 +24,18 @@
2524
</p>
2625
</pull-header>
2726
<div
28-
v-if="isIos"
27+
v-if="!isAndroid && !isiOS"
2928
class="banner-view"
3029
>
3130
<span>BannerView</span>
3231
</div>
3332
<waterfall-item
3433
v-else
3534
:full-span="true"
35+
:isHeader="true"
3636
class="banner-view"
3737
>
38-
<span>BannerView</span>
38+
<span>Banner View</span>
3939
</waterfall-item>
4040
<waterfall-item
4141
v-for="(ui, index) in dataSource"
@@ -57,6 +57,12 @@
5757
:item-bean="ui.itemBean"
5858
/>
5959
</waterfall-item>
60+
<waterfall-item
61+
:isFooter="true"
62+
class="banner-view"
63+
>
64+
<span>Footer View</span>
65+
</waterfall-item>
6066
<pull-footer
6167
ref="pullFooter"
6268
class="pull-footer"
@@ -94,7 +100,8 @@ const interItemSpacing = 6;
94100
const numberOfColumns = 2;
95101
// inner content padding
96102
const contentInset = { top: 0, left: 5, bottom: 0, right: 5 };
97-
const isIos = Native.Platform === 'ios';
103+
const isAndroid = Native.Platform === 'android';
104+
const isiOS = Native.Platform === 'ios';
98105
99106
const mockFetchData = async (): Promise<any> => new Promise((resolve) => {
100107
setTimeout(() => {
@@ -248,7 +255,8 @@ export default defineComponent({
248255
onRefresh,
249256
onEndReached,
250257
onClickItem,
251-
isIos,
258+
isAndroid,
259+
isiOS,
252260
onHeaderPulling,
253261
onFooterPulling,
254262
onHeaderIdle,

driver/js/packages/hippy-react/src/components/waterfall-view.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,12 @@ interface WaterfallViewProps {
6464
// Declare whether banner view exists
6565
containBannerView?: boolean
6666

67-
// Return banner view element
67+
// Return banner view element (header)
6868
renderBanner?: () => React.ReactElement;
6969

70+
// Return footer banner view element
71+
renderFooter?: () => React.ReactElement;
72+
7073
/**
7174
* Passing the data and returns the row component.
7275
*
@@ -253,6 +256,7 @@ class WaterfallView extends React.Component<WaterfallViewProps> {
253256
const {
254257
style = {},
255258
renderBanner,
259+
renderFooter,
256260
numberOfColumns = 2,
257261
columnSpacing = 0,
258262
interItemSpacing = 0,
@@ -293,17 +297,18 @@ class WaterfallView extends React.Component<WaterfallViewProps> {
293297
if (typeof renderBanner === 'function') {
294298
const banner = renderBanner();
295299
if (banner) {
296-
if (Device.platform.OS === 'ios') {
300+
if (Device.platform.OS === 'ohos') {
297301
itemList.push((
298302
<View key="bannerView">
299303
{React.cloneElement(banner)}
300304
</View>
301305
));
302306
nativeProps.containBannerView = true;
303-
} else if (Device.platform.OS === 'android') {
307+
} else {
304308
const itemProps = {
305309
key: 'bannerView',
306-
fullSpan: true,
310+
isHeader: true,
311+
fullSpan: true, // only for android
307312
style: {},
308313
};
309314
itemList.push((
@@ -357,6 +362,23 @@ class WaterfallView extends React.Component<WaterfallViewProps> {
357362
warn('Waterfall attribute [renderItem] is not Function');
358363
}
359364

365+
// only ios support currently
366+
if (typeof renderFooter === 'function') {
367+
const footer = renderFooter();
368+
if (footer) {
369+
const itemProps = {
370+
key: 'WaterfallFooterView',
371+
isFooter: true,
372+
style: {},
373+
};
374+
itemList.push((
375+
<WaterfallViewItem{...itemProps}>
376+
{React.cloneElement(footer)}
377+
</WaterfallViewItem>
378+
));
379+
}
380+
}
381+
360382
return (
361383
// @ts-ignore
362384
<ul

renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ NS_ASSUME_NONNULL_BEGIN
3838
/// Waterfall item's shadowView
3939
@interface HippyShadowWaterfallItem : HippyShadowView
4040

41+
/// Whether is header view
42+
@property (nonatomic, assign) BOOL isHeader;
43+
44+
/// Whether is footer view
45+
@property (nonatomic, assign) BOOL isFooter;
46+
4147
/// frame change observer, usually is shadowListView
4248
@property (nonatomic, weak) id<HippyShadowWaterfallItemFrameChangedProtocol> observer;
4349

renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallItemViewManager.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ @implementation HippyWaterfallItemViewManager
2828

2929
HIPPY_EXPORT_MODULE(WaterfallItem)
3030

31+
HIPPY_EXPORT_SHADOW_PROPERTY(isHeader, BOOL)
32+
HIPPY_EXPORT_SHADOW_PROPERTY(isFooter, BOOL)
33+
3134
- (UIView *)view {
3235
return [HippyWaterfallItemView new];
3336
}

renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,14 @@ typedef NS_ENUM(NSInteger, NativeRenderScrollState) {
5656
BOOL _allowNextScrollNoMatterWhat;
5757
}
5858

59-
/**
60-
* Content inset for HippyWaterfallView
61-
*/
62-
@property(nonatomic, assign) UIEdgeInsets contentInset;
59+
/// inset for items
60+
@property (nonatomic, assign) UIEdgeInsets contentInset;
61+
62+
/// inset for Header
63+
@property (nonatomic, assign) UIEdgeInsets headerInset;
64+
65+
/// inset for Footer
66+
@property (nonatomic, assign) UIEdgeInsets footerInset;
6367

6468
/**
6569
* Number of columns for HippyWaterfallView

0 commit comments

Comments
 (0)