Merge branch 'iOS_master' into combine

This commit is contained in:
pengfei.zhou
2019-12-21 23:09:37 +08:00
56 changed files with 1055 additions and 260 deletions

View File

@@ -1 +0,0 @@
../../../js-framework/bundle

View File

@@ -0,0 +1 @@
*.js

View File

@@ -25,4 +25,6 @@
#import "DoricNavigatorDelegate.h"
#import "DoricNavBarDelegate.h"
#import "DoricViewController.h"
#import "DoricPromise.h"
#import "DoricPromise.h"
#import "DoricLibrary.h"
#import "DoricNativePlugin.h"

View File

@@ -41,8 +41,9 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic, strong) NSMutableDictionary *initialParams;
@property(nonatomic, strong) DoricRootNode *rootNode;
@property(nonatomic, strong) NSMutableDictionary <NSString *, DoricViewNode *> *headNodes;
@property(nonatomic, copy) NSString *extra;
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source;
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source extra:(NSString *)extra;
- (DoricAsyncResult *)callEntity:(NSString *)method, ...;

View File

@@ -28,7 +28,7 @@
@implementation DoricContext
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source {
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source extra:(NSString *)extra {
if (self = [super init]) {
_driver = [DoricDriver instance];
_pluginInstanceMap = [NSMutableDictionary new];
@@ -39,6 +39,7 @@ - (instancetype)initWithScript:(NSString *)script source:(NSString *)source {
_script = script;
_source = source;
_initialParams = [@{@"width": @(0), @"height": @(0)} mutableCopy];
_extra = extra;
[self callEntity:DORIC_ENTITY_CREATE, nil];
}
return self;
@@ -78,7 +79,7 @@ - (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height {
it[@"width"] = @(width);
it[@"height"] = @(height);
}];
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, self.extra, nil];
}
- (void)reload:(NSString *)script {
@@ -86,6 +87,7 @@ - (void)reload:(NSString *)script {
self.script = script;
[self.driver createContext:self.contextId script:script source:self.source];
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
[self onShow];
}
- (void)onShow {

View File

@@ -26,7 +26,7 @@
NS_ASSUME_NONNULL_BEGIN
@interface DoricContextHolder : NSObject
@property(nonatomic, strong) DoricContext *doricContext;
@property(nonatomic, weak) DoricContext *doricContext;
- (instancetype)initWithContext:(DoricContext *)doricContext;

View File

@@ -0,0 +1,25 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/12/11.
//
#import <Foundation/Foundation.h>
#import "DoricRegistry.h"
@interface DoricLibrary : NSObject
- (void)load:(DoricRegistry *)registry;
@end

View File

@@ -0,0 +1,26 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/12/11.
//
#import "DoricLibrary.h"
@implementation DoricLibrary
- (void)load:(DoricRegistry *)registry {
}
@end

View File

@@ -25,5 +25,5 @@
@interface DoricPanel : UIViewController
@property(nonatomic, strong) DoricContext *doricContext;
- (void)config:(NSString *)script alias:(NSString *)alias;
- (void)config:(NSString *)script alias:(NSString *)alias extra:(NSString *)extra;
@end

View File

@@ -22,8 +22,8 @@
@implementation DoricPanel
- (void)config:(NSString *)script alias:(NSString *)alias {
self.doricContext = [[[DoricContext alloc] initWithScript:script source:alias] also:^(DoricContext *it) {
- (void)config:(NSString *)script alias:(NSString *)alias extra:(NSString *)extra {
self.doricContext = [[[DoricContext alloc] initWithScript:script source:alias extra:extra] also:^(DoricContext *it) {
[it.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) {
[self.view addSubview:it];
}]];

View File

@@ -23,6 +23,7 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class DoricLibrary;
@interface DoricRegistry : NSObject
@@ -38,6 +39,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)registerViewNode:(Class)nodeClass withName:(NSString *)name;
- (Class)acquireViewNode:(NSString *)name;
+ (void)register:(DoricLibrary *)library;
@end
NS_ASSUME_NONNULL_END

View File

@@ -42,6 +42,35 @@
#import "DoricFlowLayoutNode.h"
#import "DoricPopoverPlugin.h"
#import "DoricAnimatePlugin.h"
#import "DoricNestedSliderNode.h"
#import "DoricInputNode.h"
#import "DoricLibrary.h"
@interface DoricLibraries : NSObject
@property(nonatomic, strong) NSMutableSet <DoricLibrary *> *libraries;
+ (instancetype)instance;
@end
@implementation DoricLibraries
- (instancetype)init {
if (self = [super init]) {
_libraries = [NSMutableSet new];
}
return self;
}
+ (instancetype)instance {
static DoricLibraries *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[DoricLibraries alloc] init];
});
return _instance;
}
@end
@interface DoricRegistry ()
@@ -53,12 +82,19 @@ @interface DoricRegistry ()
@implementation DoricRegistry
+ (void)register:(DoricLibrary *)library {
[DoricLibraries.instance.libraries addObject:library];
}
- (instancetype)init {
if (self = [super init]) {
_bundles = [[NSMutableDictionary alloc] init];
_plugins = [[NSMutableDictionary alloc] init];
_nodes = [[NSMutableDictionary alloc] init];
[self innerRegister];
[DoricLibraries.instance.libraries enumerateObjectsUsingBlock:^(DoricLibrary *obj, BOOL *stop) {
[obj load:self];
}];
}
return self;
}
@@ -86,6 +122,8 @@ - (void)innerRegister {
[self registerViewNode:DoricRefreshableNode.class withName:@"Refreshable"];
[self registerViewNode:DoricFlowLayoutItemNode.class withName:@"FlowLayoutItem"];
[self registerViewNode:DoricFlowLayoutNode.class withName:@"FlowLayout"];
[self registerViewNode:DoricNestedSliderNode.class withName:@"NestedSlider"];
[self registerViewNode:DoricInputNode.class withName:@"Input"];
}
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name {

View File

@@ -8,7 +8,7 @@
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed onO an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
@@ -22,5 +22,5 @@
#import "DoricNavBarDelegate.h"
@interface DoricViewController : UIViewController <DoricNavigatorDelegate, DoricNavBarDelegate>
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias;
@end
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias extra:(NSString *)extra;
@end

View File

@@ -32,7 +32,7 @@ @interface DoricViewController ()
@end
@implementation DoricViewController
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias {
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias extra:(NSString *)extra {
if (self = [super init]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
DoricAsyncResult <NSString *> *result = [DoricJSLoaderManager.instance request:scheme];
@@ -46,7 +46,7 @@ - (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias {
}];
[self.view addSubview:panel.view];
[self addChildViewController:panel];
[panel config:result alias:alias];
[panel config:result alias:alias extra:extra];
panel.doricContext.navigator = self;
panel.doricContext.navBar = self;
self.doricPanel = panel;
@@ -78,8 +78,8 @@ - (void)viewWillLayoutSubviews {
self.doricPanel.view.height = self.view.height;
}
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated {
DoricViewController *viewController = [[DoricViewController alloc] initWithScheme:scheme alias:alias];
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated extra:(NSString *)extra {
DoricViewController *viewController = [[DoricViewController alloc] initWithScheme:scheme alias:alias extra:extra];
[self.navigationController pushViewController:viewController animated:animated];
}

View File

@@ -55,12 +55,20 @@ - (instancetype)init {
- (void)initJSExecutor {
__weak typeof(self) _self = self;
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
[self.jsExecutor injectGlobalJSObject:INJECT_ENVIRONMENT obj:@{
@"platform": @"iOS",
@"platformVersion": [[UIDevice currentDevice] systemVersion],
@"appName": infoDictionary[@"CFBundleName"],
@"appVersion": infoDictionary[@"CFBundleShortVersionString"],
@"screenWidth": @([[UIScreen mainScreen] bounds].size.width),
@"screenHeight": @([[UIScreen mainScreen] bounds].size.height),
}];
[self.jsExecutor injectGlobalJSObject:INJECT_LOG obj:^(NSString *type, NSString *message) {
DoricLog(@"JS:%@", message);
}];
[self.jsExecutor injectGlobalJSObject:INJECT_EMPTY obj:^() {
}];
[self.jsExecutor injectGlobalJSObject:INJECT_REQUIRE obj:^(NSString *name) {
__strong typeof(_self) self = _self;

View File

@@ -50,6 +50,7 @@ - (instancetype)init {
return self;
}
#pragma mark - SRWebSocketDelegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
DoricLog(@"debugger webSocketDidOpen");
DC_UNLOCK(self.semaphore);
@@ -93,6 +94,8 @@ - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
result = ((Block4)tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3]);
} else if (argsArr.count == 5) {
result = ((Block5)tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3], argsArr[4]);
}else {
DoricLog(@"error:args to more than 5. args:%@",argsArr);
}
} else if ([cmd isEqualToString:@"invokeMethod"]) {
@@ -115,6 +118,7 @@ - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reas
DoricLog(@"debugger webSocketdidCloseWithCode");
}
#pragma mark - DoricJSExecutorProtocol
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source {
return nil;
@@ -141,10 +145,7 @@ - (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(
NSMutableArray *argsMArr = [NSMutableArray new];
for (id arg in args) {
NSDictionary *dic = @{
@"type": @(DoricargTypeWithArg(arg)),
@"value": arg
};
NSDictionary *dic = [self dicForArg:arg];
[argsMArr addObject:dic];
}
@@ -168,6 +169,19 @@ - (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(
return self.temp;
}
- (NSDictionary *)dicForArg:(id)arg {
DoricJSRemoteArgType type = DoricargTypeWithArg(arg);
if (type == DoricJSRemoteArgTypeObject || type == DoricJSRemoteArgTypeArray) {
NSString *jsonStr = [NSString dc_convertToJsonWithDic:(NSDictionary *)arg];
arg = jsonStr;
}
NSDictionary *dic = @{
@"type": @(type),
@"value": arg
};
return dic;
}
- (void)close {
[self.srWebSocket close];
}

View File

@@ -73,11 +73,15 @@ - (id)findClass:(Class)clz target:(id)target context:(DoricContext *)context met
dispatch_block_t block = ^() {
__strong __typeof__(_self) self = _self;
@try {
NSMutableArray *tempArray = [NSMutableArray new];
for (NSUInteger idx = 2; idx < methodSignature.numberOfArguments; idx++) {
if (idx - 2 > [array count]) {
break;
}
id args = [self createParamWithMethodName:array[idx - 2] context:context callbackId:callbackId argument:argument];
if (args) {
[tempArray addObject:args];
}
[invocation setArgument:&args atIndex:idx];
}
[invocation invoke];

View File

@@ -18,7 +18,7 @@
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@protocol DoricNavBarDelegate <NSObject>
- (BOOL)doric_navBar_isHidden;
@@ -28,4 +28,4 @@
- (void)doric_navBar_setTitle:(NSString *)title;
- (void)doric_navBar_setBackgroundColor:(UIColor *)color;
@end
@end

View File

@@ -20,7 +20,7 @@
#import <Foundation/Foundation.h>
@protocol DoricNavigatorDelegate <NSObject>
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated;
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated extra:(NSString *)extra;
- (void)doric_navigator_pop:(BOOL)animated;
@end
@end

View File

@@ -20,9 +20,9 @@
// Created by pengfei.zhou on 2019/7/29.
//
#import <Doric/Doric.h>
#import "DoricModalPlugin.h"
#import "DoricUtil.h"
#import "DoricExtensions.h"
@implementation DoricModalPlugin

View File

@@ -24,10 +24,19 @@ @implementation DoricNavigatorPlugin
- (void)push:(NSDictionary *)params {
dispatch_async(dispatch_get_main_queue(), ^{
BOOL animated = YES;
if (params[@"animated"]) {
animated = [params[@"animated"] boolValue];
NSString *scheme = params[@"scheme"];
NSString *alias = scheme;
NSDictionary *config = params[@"config"];
if (config) {
if (config[@"animated"]) {
animated = [config[@"animated"] boolValue];
}
if (config[@"alias"]) {
alias = config[@"alias"];
}
}
[self.doricContext.navigator doric_navigator_push:params[@"scheme"] alias:params[@"alias"] animated:animated];
[self.doricContext.navigator doric_navigator_push:scheme alias:alias animated:animated extra:config[@"extra"]];
});
}

View File

@@ -25,6 +25,8 @@
@protocol DoricFlowLayoutDelegate
- (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)doricFlowLayoutColumnSpace;
- (CGFloat)doricFlowLayoutRowSpace;
@@ -93,15 +95,23 @@ - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSInde
}
}
CGFloat width = (self.collectionView.width - self.columnSpace * (self.columnCount - 1)) / self.columnCount;
CGFloat width = [self.delegate doricFlowLayoutItemWidthAtIndexPath:indexPath];
CGFloat height = [self.delegate doricFlowLayoutItemHeightAtIndexPath:indexPath];
CGFloat x = (width + self.columnSpace) * [minYOfColumn integerValue];
CGFloat y = [self.columnHeightInfo[minYOfColumn] floatValue];
if (y > 0) {
y += self.rowSpace;
}
self.columnHeightInfo[minYOfColumn] = @(y + height);
if (width == self.collectionView.width) {
CGFloat maxY = 0;
for (NSNumber *column in self.columnHeightInfo.allValues) {
maxY = MAX(maxY, [column floatValue]);
}
y = maxY + self.rowSpace;
} else {
self.columnHeightInfo[minYOfColumn] = @(y + height);
}
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.frame = CGRectMake(x, y, width, height);
return attrs;
@@ -156,6 +166,11 @@ @interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewD
@property(nonatomic, assign) NSUInteger columnCount;
@property(nonatomic, assign) CGFloat columnSpace;
@property(nonatomic, assign) CGFloat rowSpace;
@property(nonatomic, copy) NSString *renderItemFuncId;
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
@property(nonatomic, copy) NSString *loadMoreViewId;
@property(nonatomic, assign) BOOL loadMore;
@end
@implementation DoricFlowLayoutNode
@@ -180,6 +195,7 @@ - (UICollectionView *)build {
it.delegate = self;
it.dataSource = self;
[it registerClass:[DoricFlowLayoutViewCell class] forCellWithReuseIdentifier:@"doricCell"];
[it registerClass:[DoricFlowLayoutViewCell class] forCellWithReuseIdentifier:@"doricLoadMoreCell"];
}];
}
@@ -198,17 +214,31 @@ - (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValu
self.itemCount = [prop unsignedIntegerValue];
[self.view reloadData];
} else if ([@"renderItem" isEqualToString:name]) {
[self.itemViewIds removeAllObjects];
[self clearSubModel];
[self.view reloadData];
if ([self.renderItemFuncId isEqualToString:prop]) {
} else {
[self.itemViewIds removeAllObjects];
[self clearSubModel];
[self.view reloadData];
self.renderItemFuncId = prop;
}
} else if ([@"batchCount" isEqualToString:name]) {
self.batchCount = [prop unsignedIntegerValue];
} else if ([@"onLoadMore" isEqualToString:name]) {
self.onLoadMoreFuncId = prop;
} else if ([@"loadMoreView" isEqualToString:name]) {
self.loadMoreViewId = prop;
} else if ([@"loadMore" isEqualToString:name]) {
self.loadMore = [prop boolValue];
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (NSDictionary *)itemModelAt:(NSUInteger)position {
if (position >= self.itemCount) {
return [self subModelOf:self.loadMoreViewId];
}
NSString *viewId = self.itemViewIds[@(position)];
if (viewId && viewId.length > 0) {
return [self subModelOf:viewId];
@@ -243,24 +273,26 @@ - (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
}
- (void)blendSubNode:(NSDictionary *)subModel {
NSString *viewId = subModel[@"id"];
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
if (viewNode) {
[viewNode blend:subModel[@"props"]];
} else {
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
[self recursiveMixin:subModel to:model];
[self setSubModel:model in:viewId];
}
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
if ([viewId isEqualToString:obj]) {
*stop = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
[UIView performWithoutAnimation:^{
[self.view reloadItemsAtIndexPaths:@[indexPath]];
}];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *viewId = subModel[@"id"];
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
if (viewNode) {
[viewNode blend:subModel[@"props"]];
} else {
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
[self recursiveMixin:subModel to:model];
[self setSubModel:model in:viewId];
}
}];
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
if ([viewId isEqualToString:obj]) {
*stop = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
[UIView performWithoutAnimation:^{
[self.view reloadItemsAtIndexPaths:@[indexPath]];
}];
}
}];
});
}
- (void)callItem:(NSUInteger)position size:(CGSize)size {
@@ -273,13 +305,14 @@ - (void)callItem:(NSUInteger)position size:(CGSize)size {
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.itemCount;
return self.itemCount + (self.loadMore ? 1 : 0);
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger position = (NSUInteger) indexPath.row;
NSDictionary *model = [self itemModelAt:position];
NSDictionary *props = model[@"props"];
DoricFlowLayoutViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"doricCell" forIndexPath:indexPath];
if (!cell.viewNode) {
DoricFlowLayoutItemNode *itemNode = [[DoricFlowLayoutItemNode alloc] initWithContext:self.doricContext];
@@ -287,11 +320,17 @@ - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collection
cell.viewNode = itemNode;
[cell.contentView addSubview:itemNode.view];
}
DoricFlowLayoutItemNode *node = cell.viewNode;
node.viewId = model[@"id"];
[node blend:props];
CGFloat width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
CGSize size = [node.view measureSize:CGSizeMake(width, collectionView.height)];
if (position > 0 && position >= self.itemCount && self.onLoadMoreFuncId) {
size = CGSizeMake(collectionView.width, size.height);
[self callJSResponse:self.onLoadMoreFuncId, nil];
}
[node.view layoutSelf:size];
[self callItem:position size:size];
return cell;
@@ -307,6 +346,17 @@ - (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath {
}
}
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger position = (NSUInteger) indexPath.row;
NSValue *value = self.itemSizeInfo[@(position)];
if (value) {
return [value CGSizeValue].width;
} else {
return 100;
}
}
- (CGFloat)doricFlowLayoutColumnSpace {
return self.columnSpace;
}

View File

@@ -20,7 +20,6 @@
// Created by pengfei.zhou on 2019/7/30.
//
#import <Doric/DoricExtensions.h>
#import "DoricGroupNode.h"
@interface DoricGroupNode ()

View File

@@ -26,6 +26,7 @@
@interface DoricImageNode ()
@property(nonatomic, copy) NSString *loadCallbackId;
@property(nonatomic, assign) BOOL isBlur;
@end
@implementation DoricImageNode
@@ -36,6 +37,15 @@ - (UIImageView *)build {
}];
}
- (void)blend:(NSDictionary *)props {
NSInteger value = [props[@"isBlur"] intValue];
if(value == 1) {
self.isBlur = YES;
}
[super blend:props];
}
- (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"imageUrl" isEqualToString:name]) {
__weak typeof(self) _self = self;
@@ -53,6 +63,13 @@ - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id
}
[self requestLayout];
}
if(self.isBlur) {
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:blurEffect];
effectView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
[view addSubview:effectView];
}
}];
} else if ([@"scaleType" isEqualToString:name]) {
switch ([prop integerValue]) {

View File

@@ -0,0 +1,31 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricInputNode.h
// Doric
//
// Created by 姜腾 on 2019/12/11.
//
#import "DoricViewNode.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricInputNode : DoricViewNode<UITextView *>
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,173 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricInputNode.m
// Doric
//
// Created by on 2019/12/11.
//
#import "DoricInputNode.h"
#import "DoricUtil.h"
#import "DoricPromise.h"
typedef void (^onTextChangeBlock)(NSString *text,DoricInputNode *node);
typedef void (^onFocusChangeBlock)(BOOL focused,DoricInputNode *node);
@interface DoricInputNode()<UITextViewDelegate>
@property(nonatomic, copy) onTextChangeBlock onTextChange;
@property(nonatomic, copy) onFocusChangeBlock onFocusShange;
@property(nonatomic, strong) UILabel *placeholderLabel;
@end
@implementation DoricInputNode
- (UITextView *)build {
UITextView *v = [[UITextView alloc] init];
v.delegate = self;
return v;
}
- (void)blendView:(UITextView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([name isEqualToString:@"text"]) {
view.text = prop;
} else if ([name isEqualToString:@"textSize"]) {
view.font = [UIFont systemFontOfSize:[(NSNumber *) prop floatValue]];
} else if ([name isEqualToString:@"textColor"]) {
view.textColor = DoricColor(prop);
} else if ([name isEqualToString:@"textAlignment"]) {
DoricGravity gravity = (DoricGravity) [(NSNumber *) prop integerValue];
NSTextAlignment alignment = NSTextAlignmentCenter;
if ((gravity & LEFT) == LEFT) {
alignment = NSTextAlignmentLeft;
} else if ((gravity & RIGHT) == RIGHT) {
alignment = NSTextAlignmentRight;
}
view.textAlignment = alignment;
} else if ([name isEqualToString:@"multiline"]) {
BOOL mutilin = [(NSNumber *) prop boolValue];
if (!mutilin) {
view.textContainer.maximumNumberOfLines = 1;
}else {
view.textContainer.maximumNumberOfLines = 0;
}
} else if ([name isEqualToString:@"hintText"]) {
self.placeholderLabel.text = (NSString *)prop;
} else if ([name isEqualToString:@"hintTextColor"]) {
self.placeholderLabel.textColor = DoricColor(prop);
} else if ([name isEqualToString:@"onTextChange"]) {
if ([prop isKindOfClass:[NSString class]]) {
self.onTextChange = ^(NSString *text, DoricInputNode *node) {
[node callJSResponse:prop,text,nil];
};
}else {
self.onTextChange = nil;
}
} else if ([name isEqualToString:@"onFocusChange"]) {
if ([prop isKindOfClass:[NSString class]]) {
self.onFocusShange = ^(BOOL focused, DoricInputNode *node) {
[node callJSResponse:prop,@(focused),nil];
};
}else {
self.onFocusShange = nil;
}
} else{
[super blendView:view forPropName:name propValue:prop];
}
}
- (void)blend:(NSDictionary *)props {
[super blend:props];
[self updatePlaceholderLabel];
[self.view.superview setNeedsLayout];
}
#pragma mark - Doric-JS api
- (NSString *)getText {
return self.view.text;
}
- (void)setSelection:(NSDictionary *)params withPromise:(DoricPromise *)promise {
NSString *start = params[@"start"];
NSString *end = params[@"end"];
if (([start isKindOfClass:[NSString class]] || [start isKindOfClass:[NSNumber class]]) &&
([start isKindOfClass:[NSString class]] || [start isKindOfClass:[NSNumber class]])) {
self.view.selectedRange = NSMakeRange(start.intValue, end.intValue - start.intValue);
}
[promise resolve:nil];
}
- (void)requestFocus {
[self.view becomeFirstResponder];
}
- (void)releaseFocus {
[self.view resignFirstResponder];
}
#pragma mark - UITextViewDelegate
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
if (self.onFocusShange) {
self.onFocusShange(YES, self);
}
return YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
if (self.onFocusShange) {
self.onFocusShange(NO, self);
}
return YES;
}
- (void)textViewDidChange:(UITextView *)textView {
if (self.onTextChange) {
self.onTextChange(textView.text, self);
}
[self updatePlaceholderLabel];
}
#pragma mark - placeholderLabel
- (UILabel *)placeholderLabel {
if (!_placeholderLabel) {
_placeholderLabel = [[UILabel alloc] init];
_placeholderLabel.numberOfLines = 0;
_placeholderLabel.userInteractionEnabled = NO;
}
return _placeholderLabel;
}
- (void)updatePlaceholderLabel {
if (self.view.text.length) {
[self.placeholderLabel removeFromSuperview];
return;
} else {
[self.view insertSubview:self.placeholderLabel atIndex:0];
}
self.placeholderLabel.textAlignment = self.view.textAlignment;
CGFloat lineFragmentPadding = self.view.textContainer.lineFragmentPadding;
UIEdgeInsets textContainerInset = self.view.textContainerInset;
CGFloat x = lineFragmentPadding + textContainerInset.left;
CGFloat y = textContainerInset.top;
CGFloat width = CGRectGetWidth(self.view.bounds) - x - lineFragmentPadding - textContainerInset.right;
CGFloat height = [self.placeholderLabel sizeThatFits:CGSizeMake(width, 0)].height;
self.placeholderLabel.frame = CGRectMake(x, y, width, height);
}
@end

View File

@@ -18,8 +18,11 @@
//
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIKit.h>
typedef UIEdgeInsets DoricMargin;
typedef UIEdgeInsets DoricPadding;
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom);
@@ -82,6 +85,10 @@ typedef NS_ENUM(NSInteger, DoricGravity) {
@property(nonatomic, strong) DoricLayoutConfig *layoutConfig;
@end
@interface UIView (DoricPadding)
@property(nonatomic, assign) DoricPadding padding;
@end
@interface UIView (DoricTag)
@property(nonatomic, copy) NSString *tagString;
@@ -96,4 +103,4 @@ typedef NS_ENUM(NSInteger, DoricGravity) {
- (void)doricLayoutSubviews;
- (BOOL)requestFromSubview:(UIView *)subview;
@end
@end

View File

@@ -19,7 +19,6 @@
#import "DoricLayouts.h"
#import <objc/runtime.h>
#import <Doric/DoricLayouts.h>
#import "UIView+Doric.h"
static const void *kLayoutConfig = &kLayoutConfig;
@@ -37,6 +36,24 @@ - (DoricLayoutConfig *)layoutConfig {
@end
static const void *kLayoutPadding = &kLayoutPadding;
@implementation UIView (DoricPadding)
@dynamic padding;
- (void)setPadding:(DoricPadding)padding {
objc_setAssociatedObject(self, kLayoutPadding, [NSValue value:&padding withObjCType:@encode(DoricPadding)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (DoricPadding)padding {
DoricPadding value;
value.left = value.right = value.top = value.bottom = 0;
[objc_getAssociatedObject(self, kLayoutPadding) getValue:&value];
return value;
}
@end
static const void *kTagString = &kTagString;
@implementation UIView (DoricTag)
@@ -79,13 +96,15 @@ - (CGSize)measureSize:(CGSize)targetSize {
|| config.heightSpec == DoricLayoutWrapContent) {
height = targetSize.height - config.margin.top - config.margin.bottom;
}
CGSize contentSize = [self sizeThatFits:CGSizeMake(width, height)];
DoricPadding padding = self.padding;
CGSize contentSize = [self sizeThatFits:CGSizeMake(
width - padding.left - padding.right,
height - padding.top - padding.bottom)];
if (config.widthSpec == DoricLayoutWrapContent) {
width = contentSize.width;
width = contentSize.width + padding.left + padding.right;
}
if (config.heightSpec == DoricLayoutWrapContent) {
height = contentSize.height;
height = contentSize.height + padding.left + padding.top + padding.bottom;
}
return CGSizeMake(width, height);
}
@@ -208,6 +227,8 @@ - (CGSize)sizeThatFits:(CGSize)size {
- (void)layoutSelf:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
DoricPadding padding = self.padding;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
@@ -219,33 +240,35 @@ - (void)layoutSelf:(CGSize)targetSize {
if (!childConfig) {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height)];
CGSize size = [child measureSize:CGSizeMake(
targetSize.width - padding.left - padding.right,
targetSize.height - padding.top - padding.bottom)];
[child layoutSelf:size];
DoricGravity gravity = childConfig.alignment;
if ((gravity & LEFT) == LEFT) {
child.left = 0;
child.left = padding.left;
} else if ((gravity & RIGHT) == RIGHT) {
child.right = targetSize.width;
child.right = targetSize.width - padding.right;
} else if ((gravity & CENTER_X) == CENTER_X) {
child.centerX = targetSize.width / 2;
} else {
if (childConfig.margin.left) {
child.left = childConfig.margin.left;
child.left = childConfig.margin.left + padding.left;
} else if (childConfig.margin.right) {
child.right = targetSize.width - childConfig.margin.right;
child.right = targetSize.width - childConfig.margin.right - padding.right;
}
}
if ((gravity & TOP) == TOP) {
child.top = 0;
child.top = padding.top;
} else if ((gravity & BOTTOM) == BOTTOM) {
child.bottom = targetSize.height;
child.bottom = targetSize.height - padding.bottom;
} else if ((gravity & CENTER_Y) == CENTER_Y) {
child.centerY = targetSize.height / 2;
} else {
if (childConfig.margin.top) {
child.top = childConfig.margin.top;
child.top = childConfig.margin.top + padding.top;
} else if (childConfig.margin.bottom) {
child.bottom = targetSize.height - childConfig.margin.bottom;
child.bottom = targetSize.height - childConfig.margin.bottom - padding.bottom;
}
}
}
@@ -292,15 +315,16 @@ - (CGSize)sizeThatFits:(CGSize)size {
- (void)layoutSelf:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
CGFloat yStart = 0;
DoricPadding padding = self.padding;
CGFloat yStart = padding.top;
if ((self.gravity & TOP) == TOP) {
yStart = 0;
yStart = padding.top;
} else if ((self.gravity & BOTTOM) == BOTTOM) {
yStart = targetSize.height - self.contentHeight;
yStart = targetSize.height - self.contentHeight - padding.bottom;
} else if ((self.gravity & CENTER_Y) == CENTER_Y) {
yStart = (targetSize.height - self.contentHeight) / 2;
yStart = (targetSize.height - self.contentHeight - padding.top - padding.bottom) / 2 + padding.top;
}
CGFloat remain = targetSize.height - self.contentHeight;
CGFloat remain = targetSize.height - self.contentHeight - padding.top - padding.bottom;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
@@ -313,24 +337,26 @@ - (void)layoutSelf:(CGSize)targetSize {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height - yStart)];
CGSize size = [child measureSize:CGSizeMake(
targetSize.width - padding.left - padding.right,
targetSize.height - yStart - padding.bottom)];
if (childConfig.weight) {
size.height += remain / self.contentWeight * childConfig.weight;
}
[child layoutSelf:size];
DoricGravity gravity = childConfig.alignment | self.gravity;
if ((gravity & LEFT) == LEFT) {
child.left = 0;
child.left = padding.left;
} else if ((gravity & RIGHT) == RIGHT) {
child.right = self.width;
child.right = self.width - padding.right;
} else if ((gravity & CENTER_X) == CENTER_X) {
child.centerX = targetSize.width / 2;
} else if (childConfig.margin.left) {
child.left = childConfig.margin.left + padding.left;
} else if (childConfig.margin.right) {
child.right = targetSize.width - childConfig.margin.right - padding.right;
} else {
if (childConfig.margin.left) {
child.left = childConfig.margin.left;
} else if (childConfig.margin.right) {
child.right = targetSize.width - childConfig.margin.right;
}
child.left = padding.left;
}
if (childConfig.margin.top) {
yStart += childConfig.margin.top;
@@ -380,17 +406,16 @@ - (CGSize)sizeThatFits:(CGSize)size {
- (void)layoutSelf:(CGSize)targetSize {
self.width = targetSize.width;
self.height = targetSize.height;
CGFloat xStart = 0;
if (self.contentWeight) {
xStart = 0;
} else if ((self.gravity & LEFT) == LEFT) {
xStart = 0;
DoricPadding padding = self.padding;
CGFloat xStart = padding.left;
if ((self.gravity & LEFT) == LEFT) {
xStart = padding.left;
} else if ((self.gravity & RIGHT) == RIGHT) {
xStart = targetSize.width - self.contentWidth;
xStart = targetSize.width - self.contentWidth - padding.right;
} else if ((self.gravity & CENTER_X) == CENTER_X) {
xStart = (targetSize.width - self.contentWidth) / 2;
xStart = (targetSize.width - self.contentWidth - padding.left - padding.right) / 2 + padding.left;
}
CGFloat remain = targetSize.width - self.contentWidth;
CGFloat remain = targetSize.width - self.contentWidth - padding.left - padding.right;
for (UIView *child in self.subviews) {
if (child.isHidden) {
continue;
@@ -403,7 +428,9 @@ - (void)layoutSelf:(CGSize)targetSize {
childConfig = [DoricLayoutConfig new];
}
CGSize size = [child measureSize:CGSizeMake(targetSize.width - xStart, targetSize.height)];
CGSize size = [child measureSize:CGSizeMake(
targetSize.width - xStart - padding.right,
targetSize.height - padding.top - padding.bottom)];
if (childConfig.weight) {
size.width += remain / self.contentWeight * childConfig.weight;
}
@@ -412,17 +439,17 @@ - (void)layoutSelf:(CGSize)targetSize {
DoricGravity gravity = childConfig.alignment | self.gravity;
if ((gravity & TOP) == TOP) {
child.top = 0;
child.top = padding.top;
} else if ((gravity & BOTTOM) == BOTTOM) {
child.bottom = targetSize.height;
child.bottom = targetSize.height - padding.bottom;
} else if ((gravity & CENTER_Y) == CENTER_Y) {
child.centerY = targetSize.height / 2;
} else if (childConfig.margin.top) {
child.top = childConfig.margin.top + padding.top;
} else if (childConfig.margin.bottom) {
child.bottom = targetSize.height - childConfig.margin.bottom - padding.bottom;
} else {
if (childConfig.margin.top) {
child.top = childConfig.margin.top;
} else if (childConfig.margin.bottom) {
child.bottom = targetSize.height - childConfig.margin.bottom;
}
child.top = padding.top;
}
if (childConfig.margin.left) {

View File

@@ -62,6 +62,10 @@ @interface DoricListNode () <UITableViewDataSource, UITableViewDelegate>
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSNumber *> *itemHeights;
@property(nonatomic, assign) NSUInteger itemCount;
@property(nonatomic, assign) NSUInteger batchCount;
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
@property(nonatomic, copy) NSString *renderItemFuncId;
@property(nonatomic, copy) NSString *loadMoreViewId;
@property(nonatomic, assign) BOOL loadMore;
@end
@implementation DoricListNode
@@ -86,6 +90,7 @@ - (UITableView *)build {
it.dataSource = self;
it.delegate = self;
it.separatorStyle = UITableViewCellSeparatorStyleNone;
it.allowsSelection = NO;
}];
}
@@ -94,11 +99,22 @@ - (void)blendView:(UITableView *)view forPropName:(NSString *)name propValue:(id
self.itemCount = [prop unsignedIntegerValue];
[self.view reloadData];
} else if ([@"renderItem" isEqualToString:name]) {
[self.itemViewIds removeAllObjects];
[self clearSubModel];
[self.view reloadData];
if (![self.renderItemFuncId isEqualToString:prop]) {
self.renderItemFuncId = prop;
[self.itemViewIds.allValues forEach:^(NSString *obj) {
[self removeSubModel:obj];
}];
[self.itemViewIds removeAllObjects];
[self.view reloadData];
}
} else if ([@"batchCount" isEqualToString:name]) {
self.batchCount = [prop unsignedIntegerValue];
} else if ([@"onLoadMore" isEqualToString:name]) {
self.onLoadMoreFuncId = prop;
} else if ([@"loadMoreView" isEqualToString:name]) {
self.loadMoreViewId = prop;
} else if ([@"loadMore" isEqualToString:name]) {
self.loadMore = [prop boolValue];
} else {
[super blendView:view forPropName:name propValue:prop];
}
@@ -109,7 +125,7 @@ - (void)blend:(NSDictionary *)props {
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.itemCount;
return self.itemCount + (self.loadMore ? 1 : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@@ -117,7 +133,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
NSDictionary *model = [self itemModelAt:position];
NSDictionary *props = model[@"props"];
NSString *reuseId = props[@"identifier"];
if (position > 0 && position >= self.itemCount && self.onLoadMoreFuncId) {
reuseId = @"doricLoadMoreCell";
[self callJSResponse:self.onLoadMoreFuncId, nil];
}
DoricTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId ?: @"doriccell"];
if (!cell) {
cell = [[DoricTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseId ?: @"doriccell"];
@@ -147,6 +166,9 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa
}
- (NSDictionary *)itemModelAt:(NSUInteger)position {
if (position >= self.itemCount) {
return [self subModelOf:self.loadMoreViewId];
}
NSString *viewId = self.itemViewIds[@(position)];
if (viewId && viewId.length > 0) {
return [self subModelOf:viewId];
@@ -160,29 +182,37 @@ - (NSDictionary *)itemModelAt:(NSUInteger)position {
NSUInteger pos = position + idx;
self.itemViewIds[@(pos)] = thisViewId;
}];
return array[0];
if (array.count > 0) {
return array[0];
} else {
return nil;
}
}
}
- (void)blendSubNode:(NSDictionary *)subModel {
NSString *viewId = subModel[@"id"];
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
if (viewNode) {
[viewNode blend:subModel[@"props"]];
} else {
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
[self recursiveMixin:subModel to:model];
[self setSubModel:model in:viewId];
}
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
if ([viewId isEqualToString:obj]) {
*stop = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
[UIView performWithoutAnimation:^{
[self.view reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
///Here async blend sub node because the item count need to be applied first.
dispatch_async(dispatch_get_main_queue(), ^{
NSString *viewId = subModel[@"id"];
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
if (viewNode) {
[viewNode blend:subModel[@"props"]];
} else {
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
[self recursiveMixin:subModel to:model];
[self setSubModel:model in:viewId];
}
}];
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
if ([viewId isEqualToString:obj]) {
*stop = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
[UIView performWithoutAnimation:^{
[self.view reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
}
}];
});
}
- (void)callItem:(NSUInteger)position height:(CGFloat)height {

View File

@@ -0,0 +1,24 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/12/7.
//
#import <Foundation/Foundation.h>
#import "DoricGroupNode.h"
@interface DoricNestedSliderNode : DoricGroupNode<UIScrollView *>
@end

View File

@@ -0,0 +1,101 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/12/7.
//
#import "DoricNestedSliderNode.h"
#import "Doric.h"
@interface DoricNestedSliderView : UIScrollView
@end
@implementation DoricNestedSliderView
- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) {
CGFloat width = size.width;
CGFloat height = size.height;
for (UIView *child in self.subviews) {
CGSize childSize = [child measureSize:size];
width = MAX(childSize.width, width);
height = MAX(childSize.height, height);
}
return CGSizeMake(width, height);
}
return size;
}
- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize];
[self.subviews forEachIndexed:^(__kindof UIView *obj, NSUInteger idx) {
obj.left = idx * self.width;
}];
[self setContentSize:CGSizeMake(self.subviews.count * self.width, self.height)];
}
@end
@interface DoricNestedSliderNode () <UIScrollViewDelegate>
@property(nonatomic, copy) NSString *onPageSelectedFuncId;
@property(nonatomic, assign) NSUInteger lastPosition;
@end
@implementation DoricNestedSliderNode
- (UIScrollView *)build {
return [[DoricNestedSliderView new] also:^(DoricNestedSliderView *it) {
it.delegate = self;
it.pagingEnabled = YES;
[it setShowsVerticalScrollIndicator:NO];
[it setShowsHorizontalScrollIndicator:NO];
}];
}
- (void)blendView:(UIScrollView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"onPageSlided" isEqualToString:name]) {
self.onPageSelectedFuncId = prop;
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSUInteger pageIndex = (NSUInteger) (scrollView.contentOffset.x / scrollView.width);
[scrollView setContentOffset:CGPointMake(pageIndex * scrollView.width, scrollView.contentOffset.y) animated:YES];
if (self.onPageSelectedFuncId && self.onPageSelectedFuncId.length > 0) {
if (pageIndex != self.lastPosition) {
[self callJSResponse:self.onPageSelectedFuncId, @(pageIndex), nil];
}
}
self.lastPosition = pageIndex;
}
- (void)slidePage:(NSDictionary *)params withPromise:(DoricPromise *)promise {
NSUInteger pageIndex = [params[@"page"] unsignedIntegerValue];
BOOL smooth = [params[@"smooth"] boolValue];
[self.view setContentOffset:CGPointMake(pageIndex * self.view.width, self.view.contentOffset.y) animated:smooth];
[promise resolve:nil];
self.lastPosition = pageIndex;
if (self.onPageSelectedFuncId && self.onPageSelectedFuncId.length > 0) {
[self callJSResponse:self.onPageSelectedFuncId, @(pageIndex), nil];
}
}
- (NSNumber *)getSlidedPage {
NSUInteger pageIndex = (NSUInteger) (self.view.contentOffset.x / self.view.width);
return @(pageIndex);
}
@end

View File

@@ -54,7 +54,11 @@ @interface DoricScrollerNode ()
@implementation DoricScrollerNode
- (DoricScrollView *)build {
return [DoricScrollView new];
return [[DoricScrollView new] also:^(DoricScrollView *it) {
if (@available(iOS 11, *)) {
it.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
}];
}
- (void)initWithSuperNode:(DoricSuperNode *)superNode {

View File

@@ -35,6 +35,9 @@ @interface DoricSliderNode () <UICollectionViewDataSource, UICollectionViewDeleg
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSString *> *itemViewIds;
@property(nonatomic, assign) NSUInteger itemCount;
@property(nonatomic, assign) NSUInteger batchCount;
@property(nonatomic, copy) NSString *onPageSelectedFuncId;
@property(nonatomic, assign) NSUInteger lastPosition;
@property(nonatomic, copy) NSString *renderPageFuncId;
@end
@interface DoricSliderView : UICollectionView
@@ -90,11 +93,18 @@ - (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValu
self.itemCount = [prop unsignedIntegerValue];
[self.view reloadData];
} else if ([@"renderPage" isEqualToString:name]) {
[self.itemViewIds removeAllObjects];
[self clearSubModel];
[self.view reloadData];
if ([self.renderPageFuncId isEqualToString:prop]) {
} else {
[self.itemViewIds removeAllObjects];
[self clearSubModel];
[self.view reloadData];
self.renderPageFuncId = prop;
}
} else if ([@"batchCount" isEqualToString:name]) {
self.batchCount = [prop unsignedIntegerValue];
} else if ([@"onPageSlided" isEqualToString:name]) {
self.onPageSelectedFuncId = prop;
} else {
[super blendView:view forPropName:name propValue:prop];
}
@@ -197,5 +207,28 @@ - (void)blendSubNode:(NSDictionary *)subModel {
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSUInteger pageIndex = (NSUInteger) (scrollView.contentOffset.x / scrollView.width);
scrollView.contentOffset = CGPointMake(pageIndex * scrollView.width, scrollView.contentOffset.y);
if (self.onPageSelectedFuncId && self.onPageSelectedFuncId.length > 0) {
if (pageIndex != self.lastPosition) {
[self callJSResponse:self.onPageSelectedFuncId, @(pageIndex), nil];
}
}
self.lastPosition = pageIndex;
}
- (void)slidePage:(NSDictionary *)params withPromise:(DoricPromise *)promise {
NSUInteger pageIndex = [params[@"page"] unsignedIntegerValue];
BOOL smooth = [params[@"smooth"] boolValue];
[self.view setContentOffset:CGPointMake(pageIndex * self.view.width, self.view.contentOffset.y) animated:smooth];
[promise resolve:nil];
self.lastPosition = pageIndex;
if (self.onPageSelectedFuncId && self.onPageSelectedFuncId.length > 0) {
[self callJSResponse:self.onPageSelectedFuncId, @(pageIndex), nil];
}
}
- (NSNumber *)getSlidedPage {
NSUInteger pageIndex = (NSUInteger) (self.view.contentOffset.x / self.view.width);
return @(pageIndex);
}
@end

View File

@@ -35,6 +35,8 @@
- (void)clearSubModel;
- (void)removeSubModel:(NSString *)viewId;
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId;
- (void)recursiveMixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)targetModel;

View File

@@ -62,7 +62,6 @@ - (void)mixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)targetModel {
targetProp[key] = obj;
}
}];
targetModel[@"props"] = targetProp;
}
- (void)recursiveMixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)targetModel {
@@ -149,11 +148,16 @@ - (void)clearSubModel {
[self.subNodes removeAllObjects];
}
- (void)removeSubModel:(NSString *)viewId {
[self.subNodes removeObjectForKey:viewId];
}
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
NSAssert(NO, @"Should override class:%@ ,method:%@.", NSStringFromClass([self class]),
NSStringFromSelector(_cmd));
NSStringFromSelector(_cmd));
return nil;
}
- (void)requestLayout {
[self.view setNeedsLayout];
}

View File

@@ -48,6 +48,8 @@ - (void)blendView:(UILabel *)view forPropName:(NSString *)name propValue:(id)pro
alignment = NSTextAlignmentRight;
}
view.textAlignment = alignment;
} else if ([name isEqualToString:@"maxLines"]) {
view.numberOfLines = [prop integerValue];
} else {
[super blendView:view forPropName:name propValue:prop];
}

View File

@@ -235,7 +235,6 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
} else {
view.clipsToBounds = YES;
}
} else if ([name isEqualToString:@"translationX"]) {
self.translationX = prop;
} else if ([name isEqualToString:@"translationY"]) {
@@ -250,6 +249,19 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
self.pivotY = prop;
} else if ([name isEqualToString:@"rotation"]) {
self.rotation = prop;
} else if ([name isEqualToString:@"padding"]) {
DoricPadding padding;
padding.left = padding.right = padding.top = padding.bottom = 0;
if ([prop isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = prop;
padding.left = [dictionary[@"left"] floatValue];
padding.right = [dictionary[@"right"] floatValue];
padding.top = [dictionary[@"top"] floatValue];
padding.bottom = [dictionary[@"bottom"] floatValue];
}
self.view.padding = padding;
} else if ([name isEqualToString:@"hidden"]) {
self.view.hidden = [prop boolValue];
} else {
DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name);
}
@@ -305,6 +317,11 @@ - (NSNumber *)getHeight {
return @(self.view.height);
}
- (NSDictionary *)getLocationOnScreen {
CGPoint point = [self.view convertPoint:CGPointMake(0, 0) toView:[UIApplication sharedApplication].windows.lastObject];
return @{@"x": @(point.x), @"y": @(point.y)};
}
- (void)blendLayoutConfig:(NSDictionary *)params {
[params[@"widthSpec"] also:^(NSNumber *it) {
if (it) {
@@ -357,6 +374,8 @@ - (NSDictionary *)transformation {
return dictionary;
}
#pragma animations
- (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
CAAnimation *animation = [self parseAnimation:params];
AnimationCallback *originDelegate = animation.delegate;
@@ -371,6 +390,7 @@ - (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
if (originDelegate) {
originDelegate.endBlock(callback);
}
[self.view.layer removeAllAnimations];
[self transformProperties];
[promise resolve:self.transformation];
};
@@ -379,6 +399,8 @@ - (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
if (params[@"delay"]) {
animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000;
}
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[self.view.layer addAnimation:animation forKey:nil];
}

View File

@@ -49,7 +49,7 @@ - (void)setupError:(NSException *)exception {
}
- (BOOL)hasResult {
return self.result;
return self.result != nil;
}
- (id)getResult {

View File

@@ -26,7 +26,7 @@ extern NSString *const DORIC_BUNDLE_SANDBOX;
extern NSString *const DORIC_BUNDLE_LIB;
extern NSString *const DORIC_MODULE_LIB;
extern NSString *const INJECT_ENVIRONMENT;
extern NSString *const INJECT_LOG;
extern NSString *const INJECT_REQUIRE;
extern NSString *const INJECT_TIMER_SET;

View File

@@ -26,6 +26,7 @@
NSString *const DORIC_BUNDLE_LIB = @"doric-lib";
NSString *const DORIC_MODULE_LIB = @"doric";
NSString *const INJECT_ENVIRONMENT = @"Environment";
NSString *const INJECT_LOG = @"nativeLog";
NSString *const INJECT_REQUIRE = @"nativeRequire";

View File

@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, DoricJSRemoteArgType) {
DoricJSRemoteArgTypeNil = 0,
DoricJSRemoteArgTypeInteger,
DoricJSRemoteArgTypeNumber,
DoricJSRemoteArgTypeBool,
DoricJSRemoteArgTypeString,
DoricJSRemoteArgTypeObject,
@@ -20,4 +20,5 @@ typedef NS_ENUM(NSUInteger, DoricJSRemoteArgType) {
DoricJSRemoteArgType DoricargTypeWithArg(id arg);
NS_ASSUME_NONNULL_END

View File

@@ -6,7 +6,16 @@
//
#import "DoricJSRemoteArgType.h"
DoricJSRemoteArgType DoricargTypeWithArg(id arg) {
// TODO:
return DoricJSRemoteArgTypeString;
DoricJSRemoteArgType DoricargTypeWithArg(id arg) {
DoricJSRemoteArgType type = DoricJSRemoteArgTypeNil;
if ([arg isKindOfClass:[NSNumber class]]) {
type = DoricJSRemoteArgTypeNumber;
}else if ([arg isKindOfClass:[NSString class]]) {
type = DoricJSRemoteArgTypeString;
}else if ([arg isKindOfClass:[NSDictionary class]]) {
type = DoricJSRemoteArgTypeObject;
}else if ([arg isKindOfClass:[NSMutableArray class]]) {
type = DoricJSRemoteArgTypeArray;
}
return type;
}

View File

@@ -39,4 +39,4 @@ NSBundle *_Nonnull DoricBundle(void);
void ShowToast(NSString *_Nonnull text, DoricGravity gravity);
UIImage *_Nonnull UIImageWithColor(UIColor *color);
UIImage *_Nonnull UIImageWithColor(UIColor * _Nonnull color);