Skip to content

Commit

Permalink
feat(ios): waterfall component support footer view (#4098)
Browse files Browse the repository at this point in the history
refactor waterfall component
  • Loading branch information
wwwcg authored Oct 30, 2024
1 parent 950a782 commit 0c2a5dd
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 133 deletions.
3 changes: 2 additions & 1 deletion docs/api/hippy-react/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ import icon from './qb_icon_new.png';
| interItemSpacing | item 间的垂直间距 | `number` | `Android、iOS、Voltron` |
| contentInset | 内容缩进 ,默认值 `{ top:0, left:0, bottom:0, right:0 }` | `Object` | `Android、iOS、Voltron` |
| renderItem | 这里的入参是当前 item 的 index,在这里可以凭借 index 获取到瀑布流一个具体单元格的数据,从而决定如何渲染这个单元格。 | `(index: number) => React.ReactElement` | `Android、iOS、Voltron` |
| renderBanner | 如何渲染 Banner。 | `() => React.ReactElement` | `Android、iOS、Voltron`
| renderBanner | 如何渲染 Banner (即Header,显示在内容顶部) | `() => React.ReactElement` | `Android、iOS、Voltron` |
| renderFooter | 如何渲染 Footer(与renderBanner对应,Footer显示在内容底部) | `() => React.ReactElement` | `iOS`(3.3.2版本起支持) |
| getItemStyle | 设置`WaterfallItem`容器的样式。 | `(index: number) => styleObject` | `Android、iOS、Voltron` |
| getItemType | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升list 性能。 | `(index: number) => number` | `Android、iOS、Voltron` |
| getItemKey | 指定一个函数,在其中返回对应条目的 Key 值,详见 [React 官文](//reactjs.org/docs/lists-and-keys.html) | `(index: number) => any` | `Android、iOS、Voltron` |
Expand Down
4 changes: 3 additions & 1 deletion docs/api/hippy-vue/external-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ export default {
| columnSpacing | 瀑布流每列之前的水平间距 | `number` | `Android、iOS、Voltron` |
| interItemSpacing | item 间的垂直间距 | `number` | `Android、iOS、Voltron` |
| contentInset | 内容缩进 ,默认值 `{ top:0, left:0, bottom:0, right:0 }` | `Object` | `Android、iOS、Voltron` |
| containBannerView | 是否包含`bannerView`,只能有一个bannerView,`Android` 暂不支持 | `boolean` | `iOS、Voltron` |
| containBannerView | 是否包含`bannerView`,只能有一个bannerView, (`Android` 暂不支持`iOS` 3.3.2版本起已废弃该属性,请使用`waterfall-item`组件`isHeader/isFooter`属性代替) | `boolean` | `iOS、Voltron` |
| containPullHeader | 是否包含`pull-header``Android` 暂不支持,可以用 `ul-refresh` 组件替代 | `boolean` | `iOS、Voltron` |
| containPullFooter | 是否包含 `pull-footer` | `boolean` | `Android、iOS、Voltron` |
| numberOfColumns | 瀑布流列数量,Default: 2 | `number` | `Android、iOS、Voltron` |
Expand Down Expand Up @@ -323,3 +323,5 @@ export default {
| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | -------- |
| type | 指定一个函数,在其中返回对应条目的类型(返回Number类型的自然数,默认是0),List 将对同类型条目进行复用,所以合理的类型拆分,可以很好地提升 List 性能。 | `number` | `Android、iOS、Voltron` |
| key | 指定一个函数,在其中返回对应条目的 Key 值,详见 [Vue 官网](//vuejs.org/v2/guide/list.html) | `string` | `Android、iOS、Voltron` |
| isHeader | 指定该Item是否为Header(即bannerView,显示在内容区顶部) | `boolean` | `iOS`(3.3.2版本起支持) |
| isFooter | 指定该Item是否为Footer(显示在内容区底部) | `boolean` | `iOS`(3.3.2版本起支持) |
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default class ListExample extends React.Component {
this.onHeaderPulling = this.onHeaderPulling.bind(this);
this.onFooterPulling = this.onFooterPulling.bind(this);
this.renderBanner = this.renderBanner.bind(this);
this.renderFooter = this.renderFooter.bind(this);
this.getItemStyle = this.getItemStyle.bind(this);
this.getHeaderStyle = this.getHeaderStyle.bind(this);
this.onScroll = this.onScroll.bind(this);
Expand Down Expand Up @@ -236,10 +237,10 @@ export default class ListExample extends React.Component {
}

onScroll(obj) {

console.log('onScroll', obj);
}

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

// render footer (currently only iOS support)
renderFooter() {
if (this.state.dataSource.length === 0) return null;
return (<View style={{
backgroundColor: 'grey',
height: 100,
justifyContent: 'center',
alignItems: 'center',
}}>
<Text style={{
fontSize: 20,
color: 'white',
lineHeight: 100,
height: 100,
}}>Footer View</Text>
</View>);
}

renderItem(index) {
const { dataSource } = this.state;
let styleUI = null;
Expand Down Expand Up @@ -362,7 +381,9 @@ export default class ListExample extends React.Component {
style={{ flex: 1 }}
onScroll={this.onScroll}
renderBanner={this.renderBanner}
renderFooter={this.renderFooter}
renderPullHeader={this.renderPullHeader}
renderPullFooter={this.renderPullFooter}
onEndReached={this.onEndReached}
onFooterReleased={this.onEndReached}
onHeaderReleased={this.onHeaderReleased}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@
</p>
</pull-header>
<div
v-if="!isAndroid"
v-if="!isAndroid && !isiOS"
class="banner-view"
>
<span>BannerView</span>
</div>
</div>
<waterfall-item
v-else
v-else
:fullSpan="true",
:isHeader="true",
class="banner-view"
>
<span>BannerView</span>
<span>Banner View</span>
</waterfall-item>
<waterfall-item
v-for="(ui, index) in dataSource"
Expand All @@ -57,6 +58,13 @@
:item-bean="ui.itemBean"
/>
</waterfall-item>
<waterfall-item
:fullSpan="true",
:isFooter="true",
class="banner-view"
>
<span>Footer View</span>
</waterfall-item>
<pull-footer
ref="pullFooter"
class="pull-footer"
Expand Down Expand Up @@ -91,6 +99,7 @@ export default {
footerRefreshText: '正在加载...',
isLoading: false,
isAndroid: Vue.Native.Platform === 'android',
isiOS: Vue.Native.Platform === 'android',
};
},
mounted() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
ref="gridView"
:content-inset="contentInset"
:column-spacing="columnSpacing"
:contain-banner-view="!isAndroid"
:contain-pull-footer="true"
:inter-item-spacing="interItemSpacing"
:number-of-columns="numberOfColumns"
Expand All @@ -25,17 +24,18 @@
</p>
</pull-header>
<div
v-if="!isAndroid"
v-if="!isAndroid && !isiOS"
class="banner-view"
>
<span>BannerView</span>
</div>
<waterfall-item
v-else
:full-span="true"
:isHeader="true"
class="banner-view"
>
<span>BannerView</span>
<span>Banner View</span>
</waterfall-item>
<waterfall-item
v-for="(ui, index) in dataSource"
Expand All @@ -57,6 +57,12 @@
:item-bean="ui.itemBean"
/>
</waterfall-item>
<waterfall-item
:isFooter="true"
class="banner-view"
>
<span>Footer View</span>
</waterfall-item>
<pull-footer
ref="pullFooter"
class="pull-footer"
Expand Down Expand Up @@ -95,6 +101,7 @@ const numberOfColumns = 2;
// inner content padding
const contentInset = { top: 0, left: 5, bottom: 0, right: 5 };
const isAndroid = Native.Platform === 'android';
const isiOS = Native.Platform === 'ios';
const mockFetchData = async (): Promise<any> => new Promise((resolve) => {
setTimeout(() => {
Expand Down Expand Up @@ -249,6 +256,7 @@ export default defineComponent({
onEndReached,
onClickItem,
isAndroid,
isiOS,
onHeaderPulling,
onFooterPulling,
onHeaderIdle,
Expand Down
30 changes: 26 additions & 4 deletions driver/js/packages/hippy-react/src/components/waterfall-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ interface WaterfallViewProps {
// Declare whether banner view exists
containBannerView?: boolean

// Return banner view element
// Return banner view element (header)
renderBanner?: () => React.ReactElement;

// Return footer banner view element
renderFooter?: () => React.ReactElement;

/**
* Passing the data and returns the row component.
*
Expand Down Expand Up @@ -253,6 +256,7 @@ class WaterfallView extends React.Component<WaterfallViewProps> {
const {
style = {},
renderBanner,
renderFooter,
numberOfColumns = 2,
columnSpacing = 0,
interItemSpacing = 0,
Expand Down Expand Up @@ -293,17 +297,18 @@ class WaterfallView extends React.Component<WaterfallViewProps> {
if (typeof renderBanner === 'function') {
const banner = renderBanner();
if (banner) {
if (Device.platform.OS === 'ios' || Device.platform.OS === 'ohos') {
if (Device.platform.OS === 'ohos') {
itemList.push((
<View key="bannerView">
{React.cloneElement(banner)}
</View>
));
nativeProps.containBannerView = true;
} else if (Device.platform.OS === 'android') {
} else {
const itemProps = {
key: 'bannerView',
fullSpan: true,
isHeader: true,
fullSpan: true, // only for android
style: {},
};
itemList.push((
Expand Down Expand Up @@ -357,6 +362,23 @@ class WaterfallView extends React.Component<WaterfallViewProps> {
warn('Waterfall attribute [renderItem] is not Function');
}

// only ios support currently
if (typeof renderFooter === 'function') {
const footer = renderFooter();
if (footer) {
const itemProps = {
key: 'WaterfallFooterView',
isFooter: true,
style: {},
};
itemList.push((
<WaterfallViewItem{...itemProps}>
{React.cloneElement(footer)}
</WaterfallViewItem>
));
}
}

return (
// @ts-ignore
<ul
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ NS_ASSUME_NONNULL_BEGIN
/// Waterfall item's shadowView
@interface HippyShadowWaterfallItem : HippyShadowView

/// Whether is header view
@property (nonatomic, assign) BOOL isHeader;

/// Whether is footer view
@property (nonatomic, assign) BOOL isFooter;

/// frame change observer, usually is shadowListView
@property (nonatomic, weak) id<HippyShadowWaterfallItemFrameChangedProtocol> observer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ @implementation HippyWaterfallItemViewManager

HIPPY_EXPORT_MODULE(WaterfallItem)

HIPPY_EXPORT_SHADOW_PROPERTY(isHeader, BOOL)
HIPPY_EXPORT_SHADOW_PROPERTY(isFooter, BOOL)

- (UIView *)view {
return [HippyWaterfallItemView new];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ typedef NS_ENUM(NSInteger, NativeRenderScrollState) {
BOOL _allowNextScrollNoMatterWhat;
}

/**
* Content inset for HippyWaterfallView
*/
@property(nonatomic, assign) UIEdgeInsets contentInset;
/// inset for items
@property (nonatomic, assign) UIEdgeInsets contentInset;

/// inset for Header
@property (nonatomic, assign) UIEdgeInsets headerInset;

/// inset for Footer
@property (nonatomic, assign) UIEdgeInsets footerInset;

/**
* Number of columns for HippyWaterfallView
Expand Down
Loading

0 comments on commit 0c2a5dd

Please sign in to comment.