Skip to content

Commit

Permalink
feat(ios,js): refreshWrapper support viewPager (#3974)
Browse files Browse the repository at this point in the history
* feat(ios): refreshWrapper support viewPager

* feat(react): refresh wrapper support horizontal and update demo

* feat(react): add refresh wrapper footer

* feat(react): modify refresh-wrapper refreshFooterCompleted

* feat(ios): add footer support to refreshWrapper

* docs(react): add footer to refresh wrapper component

---------

Co-authored-by: zealotchen <[email protected]>
  • Loading branch information
wwwcg and zealotchen0 authored Oct 16, 2024
1 parent 7ef301c commit 053a116
Show file tree
Hide file tree
Showing 14 changed files with 499 additions and 89 deletions.
13 changes: 8 additions & 5 deletions docs/hippy-react/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,21 @@ import icon from './qb_icon_new.png';

[[RefreshWrapper 范例]](//github.com/Tencent/Hippy/tree/master/examples/hippy-react-demo/src/components/RefreshWrapper)

包裹住 `ListView` 提供下滑刷新功能的组件.

> `RefreshWrapper` 现在只支持包裹一个 `ListView` 组件,暂不支持别的组件的下滑刷新功能。
包裹住 `ListView``ViewPager` 提供滑动刷新功能的组件.

## 参数

| 参数 | 描述 | 类型 | 支持平台 |
| ---------- | ---------------------------------------------------- | ---------- | -------- |
| onRefresh |`RefreshWrapper`执行刷新操作时,会触发到此回调函数 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| getRefresh | 定义刷新栏的视图表现,返回 `View``Text` 等组件。 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| onRefresh |`RefreshWrapper``Refresh Header`执行刷新操作时,会触发到此回调函数 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| getRefresh | 定义`Refresh Header`刷新栏的视图表现,返回 `View``Text` 等组件。 | `Function` | `Android、iOS、hippy-react-web、Web-Renderer` |
| bounceTime | 指定刷新条收回动画的时长,单位为ms | `number` | `Android、iOS、Web-Renderer` |

| hiddenHeader | 是否显示`RefreshWrapper``Refresh Header``default: false``最低支持版本 2.17.6` | `boolean` | `Android、iOS` |
| showFooter | 是否显示`RefreshWrapper``Refresh Footer``default: false``最低支持版本 2.17.6` | `boolean` | `Android、iOS` |
| onFooterRefresh |`RefreshWrapper``Refresh Footer`执行刷新操作时,会触发到此回调函数。 `最低支持版本 2.17.6` | `Function` | `Android、iOS` |
| getFooterRefresh | 定义`Refresh Footer`刷新栏的视图表现,返回 `View``Text` 等组件。`最低支持版本 2.17.6` | `Function` | `Android、iOS` |

## 方法

### refreshCompleted
Expand Down
107 changes: 90 additions & 17 deletions examples/hippy-react-demo/src/components/ViewPager/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
View,
Text,
ViewPager,
RefreshWrapper,
} from '@hippy/react';
import { CirclePagerView, SquarePagerView, TrianglePagerView } from '../../shared/PagerItemView';

Expand Down Expand Up @@ -65,6 +66,10 @@ export default class PagerExample extends React.Component {
super(props);
this.onPageSelected = this.onPageSelected.bind(this);
this.onPageScrollStateChanged = this.onPageScrollStateChanged.bind(this);
this.onRefresh = this.onRefresh.bind(this);
this.getRefresh = this.getRefresh.bind(this);
this.onFooterRefresh = this.onFooterRefresh.bind(this);
this.getFooterRefresh = this.getFooterRefresh.bind(this);
}

onPageSelected(pageData) {
Expand All @@ -81,6 +86,55 @@ export default class PagerExample extends React.Component {
onPageScroll({ offset, position }) {
console.log('onPageScroll', offset, position);
}

/**
* callback for header
*/
onRefresh() {
setTimeout(async () => {
console.log('RefreshWrapper onRefresh');
this.refresh.refreshCompleted();
}, 3000);
}

/**
* get header view
*/
getRefresh() {
return (
<View style={{ flex: 1, width: 80, backgroundColor: 'green' }}>
<View style={{ flex: 2 }}></View>
<View style={{ width: 40, height: 40, alignSelf: 'center', backgroundColor: 'red' }}></View>
<Text style={{ flex: 1, marginTop: 10, textAlign: 'center' }}>刷新中...</Text>
<View style={{ flex: 2 }}></View>
</View>
);
}

/**
* callback for footer
*/
onFooterRefresh() {
setTimeout(async () => {
console.log('RefreshWrapper onFooterRefresh');
this.refresh.refreshFooterCompleted();
}, 3000);
}

/**
* get footer view
*/
getFooterRefresh() {
return (
<View style={{ flex: 1, width: 80, backgroundColor: 'green' }}>
<View style={{ flex: 2 }}></View>
<View style={{ width: 40, height: 40, alignSelf: 'center', backgroundColor: 'red' }}></View>
<Text style={{ flex: 1, marginTop: 10, textAlign: 'center' }}>刷新中...</Text>
<View style={{ flex: 2 }}></View>
</View>
);
}

render() {
const { selectedIndex } = this.state;
return (
Expand All @@ -98,26 +152,45 @@ export default class PagerExample extends React.Component {
<Text style={styles.buttonText}>直接滑到第1页</Text>
</View>
</View>
<ViewPager

<RefreshWrapper
ref={(ref) => {
this.viewpager = ref;
this.refresh = ref;
}}
style={styles.container}
initialPage={0}
keyboardDismissMode="none"
scrollEnabled
onPageSelected={this.onPageSelected}
onPageScrollStateChanged={this.onPageScrollStateChanged}
onPageScroll={this.onPageScroll}
style={{ flex: 1 }}
horizontal={true}
hiddenHeader={false}
showFooter={true}
onRefresh={this.onRefresh}
onFooterRefresh={this.onFooterRefresh}
bounceTime={500}
getRefresh={this.getRefresh}
getFooterRefresh={this.getFooterRefresh}
>
{
[
SquarePagerView('squarePager'),
TrianglePagerView('TrianglePager'),
CirclePagerView('CirclePager'),
]
}
</ViewPager>

<ViewPager
ref={(ref) => {
this.viewpager = ref;
}}
style={styles.container}
initialPage={0}
keyboardDismissMode="none"
scrollEnabled
onPageSelected={this.onPageSelected}
onPageScrollStateChanged={this.onPageScrollStateChanged}
onPageScroll={this.onPageScroll}
>
{
[
SquarePagerView('squarePager'),
TrianglePagerView('TrianglePager'),
CirclePagerView('CirclePager'),
]
}
</ViewPager>

</RefreshWrapper>

<View style={styles.dotContainer}>
{
new Array(PAGE_COUNT).fill(0)
Expand Down
30 changes: 28 additions & 2 deletions ios/sdk/component/listview/HippyBaseListView.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@

@interface HippyBaseListView () <HippyScrollProtocol, HippyRefreshDelegate>

/// Scrollable's scroll event delegates
@property (nonatomic, strong) NSHashTable<id<UIScrollViewDelegate>> *scrollListeners;
/// Scrollable's layout event delegates
@property (nonatomic, strong) NSHashTable<id<HippyScrollableLayoutDelegate>> *layoutDelegates;

@end

@implementation HippyBaseListView {
__weak HippyBridge *_bridge;
__weak HippyRootView *_rootView;
NSHashTable *_scrollListeners;
BOOL _isInitialListReady;
NSUInteger _preNumberOfRows;
BOOL _allowNextScrollNoMatterWhat;
Expand All @@ -55,7 +59,6 @@ @implementation HippyBaseListView {
- (instancetype)initWithBridge:(HippyBridge *)bridge {
if (self = [super initWithFrame:CGRectZero]) {
_bridge = bridge;
_scrollListeners = [NSHashTable weakObjectsHashTable];
_dataSource = [HippyBaseListViewDataSource new];
_isInitialListReady = NO;
_preNumberOfRows = 0;
Expand Down Expand Up @@ -204,6 +207,9 @@ - (void)zoomToRect:(__unused CGRect)rect animated:(__unused BOOL)animated {
}

- (void)addScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener {
if (!self.scrollListeners) {
self.scrollListeners = [NSHashTable weakObjectsHashTable];
}
[_scrollListeners addObject:scrollListener];
}

Expand Down Expand Up @@ -238,6 +244,19 @@ - (void)scrollToIndex:(NSInteger)index animated:(BOOL)animated {
}
}

- (void)addHippyScrollableLayoutDelegate:(id<HippyScrollableLayoutDelegate>)delegate {
HippyAssertMainThread();
if (!self.layoutDelegates) {
self.layoutDelegates = [NSHashTable weakObjectsHashTable];
}
[self.layoutDelegates addObject:delegate];
}

- (void)removeHippyScrollableLayoutDelegate:(id<HippyScrollableLayoutDelegate>)delegate {
HippyAssertMainThread();
[self.layoutDelegates removeObject:delegate];
}

#pragma mark - Delegate & Datasource

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
Expand Down Expand Up @@ -375,6 +394,13 @@ - (void)tableViewDidLayoutSubviews:(HippyListTableView *)tableView {
}
}
_previousVisibleCells = visibleCells;

// Notify delegates of HippyScrollableLayoutDelegate
for (id<HippyScrollableLayoutDelegate> layoutDelegate in self.layoutDelegates) {
if ([layoutDelegate respondsToSelector:@selector(scrollableDidLayout:)]) {
[layoutDelegate scrollableDidLayout:self];
}
}
}

#pragma mark - Scroll
Expand Down
28 changes: 28 additions & 0 deletions ios/sdk/component/refreshview/HippyRefreshWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,40 @@
*/

#import <UIKit/UIKit.h>
#import "HippyComponent.h"
#import "HippyInvalidating.h"

NS_ASSUME_NONNULL_BEGIN

@class HippyBridge;

/// RefreshWrapper add refresh capability to scrollable components such as ListView
@interface HippyRefreshWrapper : UIView <HippyInvalidating>

/// Direction of Refresh
@property (nonatomic, assign, getter=isHorizontal) BOOL horizontal;

/// Bounce time of refresh start/end animation
@property (nonatomic, assign) CGFloat bounceTime;

/// The onRefresh block that JS side binding.
@property (nonatomic, copy) HippyDirectEventBlock onRefresh;

/// The footer onRefresh block that JS side binding.
@property (nonatomic, copy) HippyDirectEventBlock onFooterRefresh;

/// Call to indicate refresh completion.
- (void)refreshCompleted;

/// Call to indicate refresh footer completion.
- (void)refreshFooterCompleted;

/// Call to start the refresh process.
- (void)startRefresh;

/// Call to start the footer refresh process.
- (void)startRefreshFooter;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 053a116

Please sign in to comment.