iOS SwipeLayout
This commit is contained in:
10
iOS/Pod/Classes/Refresh/DoricRefreshableNode.h
Normal file
10
iOS/Pod/Classes/Refresh/DoricRefreshableNode.h
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricSuperNode.h"
|
||||
#import "DoricSwipeRefreshLayout.h"
|
||||
|
||||
@interface DoricRefreshableNode : DoricSuperNode<DoricSwipeRefreshLayout *>
|
||||
@end
|
128
iOS/Pod/Classes/Refresh/DoricRefreshableNode.m
Normal file
128
iOS/Pod/Classes/Refresh/DoricRefreshableNode.m
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import "DoricRefreshableNode.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@interface DoricRefreshableNode ()
|
||||
@property(nonatomic, strong) DoricViewNode *contentNode;
|
||||
@property(nonatomic, copy) NSString *contentViewId;
|
||||
@property(nonatomic, strong) DoricViewNode *headerNode;
|
||||
@property(nonatomic, copy) NSString *headerViewId;
|
||||
@end
|
||||
|
||||
@implementation DoricRefreshableNode
|
||||
- (DoricSwipeRefreshLayout *)build {
|
||||
return [DoricSwipeRefreshLayout new];
|
||||
}
|
||||
|
||||
- (void)blendView:(DoricSwipeRefreshLayout *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"content" isEqualToString:name]) {
|
||||
self.contentViewId = prop;
|
||||
} else if ([@"header" isEqualToString:name]) {
|
||||
self.headerViewId = prop;
|
||||
} else if ([@"onRefresh" isEqualToString:name]) {
|
||||
__weak typeof(self) _self = self;
|
||||
NSString *funcId = prop;
|
||||
self.view.onRefreshBlock = ^{
|
||||
__strong typeof(_self) self = _self;
|
||||
[self callJSResponse:funcId, nil];
|
||||
};
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
if ([viewId isEqualToString:self.contentViewId]) {
|
||||
return self.contentNode;
|
||||
} else if ([viewId isEqualToString:self.headerViewId]) {
|
||||
return self.headerNode;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
[super blend:props];
|
||||
[self blendHeader];
|
||||
[self blendContent];
|
||||
}
|
||||
|
||||
- (void)blendContent {
|
||||
NSDictionary *contentModel = [self subModelOf:self.contentViewId];
|
||||
if (!contentModel) {
|
||||
return;
|
||||
}
|
||||
NSString *viewId = contentModel[@"id"];
|
||||
NSString *type = contentModel[@"type"];
|
||||
NSDictionary *childProps = contentModel[@"props"];
|
||||
if (self.contentNode) {
|
||||
if ([self.contentNode.viewId isEqualToString:viewId]) {
|
||||
//skip
|
||||
} else {
|
||||
if (self.reusable && [type isEqualToString:self.contentNode.type]) {
|
||||
[self.contentNode also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it blend:childProps];
|
||||
}];
|
||||
} else {
|
||||
self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.contentView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.contentView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendHeader {
|
||||
NSDictionary *headerModel = [self subModelOf:self.headerViewId];
|
||||
if (!headerModel) {
|
||||
return;
|
||||
}
|
||||
NSString *viewId = headerModel[@"id"];
|
||||
NSString *type = headerModel[@"type"];
|
||||
NSDictionary *childProps = headerModel[@"props"];
|
||||
if (self.headerNode) {
|
||||
if ([self.headerNode.viewId isEqualToString:viewId]) {
|
||||
//skip
|
||||
} else {
|
||||
if (self.reusable && [type isEqualToString:self.headerNode.type]) {
|
||||
[self.headerNode also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it blend:childProps];
|
||||
}];
|
||||
} else {
|
||||
self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.headerView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.headerView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
[[self subNodeWithViewId:subModel[@"id"]] blend:subModel[@"props"]];
|
||||
}
|
||||
@end
|
22
iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h
Normal file
22
iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol DoricSwipePullingDelegate <NSObject>
|
||||
- (void)startAnimation;
|
||||
|
||||
- (void)stopAnimation;
|
||||
|
||||
- (void)setProgressRotation:(CGFloat)rotation;
|
||||
@end
|
||||
|
||||
@interface DoricSwipeRefreshLayout : UIScrollView
|
||||
@property(nonatomic, strong) UIView *contentView;
|
||||
@property(nonatomic, strong) UIView *headerView;
|
||||
@property(nonatomic, assign) BOOL refreshable;
|
||||
@property(nonatomic, assign) BOOL refreshing;
|
||||
@property(nonatomic, strong) void (^onRefreshBlock)(void);
|
||||
@property(nonatomic, weak) id <DoricSwipePullingDelegate> swipePullingDelegate;
|
||||
@end
|
118
iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m
Normal file
118
iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import "DoricSwipeRefreshLayout.h"
|
||||
#import "UIView+Doric.h"
|
||||
#import "DoricLayouts.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@interface DoricSwipeRefreshLayout () <UIScrollViewDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation DoricSwipeRefreshLayout
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.delegate = self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.delegate = self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.contentView) {
|
||||
CGSize childSize = [self.contentView sizeThatFits:size];
|
||||
return CGSizeMake(MIN(size.width, childSize.width), MIN(size.height, childSize.height));
|
||||
}
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
- (void)setContentView:(UIView *)contentView {
|
||||
if (_contentView) {
|
||||
[_contentView removeFromSuperview];
|
||||
}
|
||||
_contentView = contentView;
|
||||
[self addSubview:contentView];
|
||||
}
|
||||
|
||||
- (void)setHeaderView:(UIView *)headerView {
|
||||
if (_headerView) {
|
||||
[_headerView removeFromSuperview];
|
||||
}
|
||||
_headerView = headerView;
|
||||
[self addSubview:headerView];
|
||||
self.refreshable = YES;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[self layoutSelf];
|
||||
[self.contentView also:^(UIView *it) {
|
||||
[it layoutSubviews];
|
||||
it.x = it.y = 0;
|
||||
}];
|
||||
[self.headerView also:^(UIView *it) {
|
||||
[it layoutSubviews];
|
||||
it.bottom = it.centerX = 0;
|
||||
}];
|
||||
self.contentSize = self.frame.size;
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
|
||||
if (-scrollView.contentOffset.y >= self.headerView.height) {
|
||||
self.refreshing = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (scrollView.contentOffset.y <= 0) {
|
||||
[self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRefreshing:(BOOL)refreshing {
|
||||
if (_refreshing == refreshing) {
|
||||
return;
|
||||
}
|
||||
if (refreshing) {
|
||||
[UIView animateWithDuration:0.3f
|
||||
animations:^{
|
||||
self.contentInset = UIEdgeInsetsMake(self.headerView.height, 0, 0, 0);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self.swipePullingDelegate startAnimation];
|
||||
}
|
||||
];
|
||||
} else {
|
||||
[UIView animateWithDuration:0.3f
|
||||
animations:^{
|
||||
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self.swipePullingDelegate stopAnimation];
|
||||
}
|
||||
];
|
||||
}
|
||||
_refreshing = refreshing;
|
||||
}
|
||||
|
||||
- (void)setRefreshable:(BOOL)refreshable {
|
||||
self.scrollEnabled = refreshable;
|
||||
}
|
||||
|
||||
- (BOOL)refreshable {
|
||||
return self.scrollEnabled;
|
||||
}
|
||||
@end
|
Reference in New Issue
Block a user