Merge branch 'feature/listview' into 'master'
Feature/listview See merge request !1
This commit is contained in:
commit
95a85af56b
@ -26,7 +26,7 @@ android {
|
|||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
buildJSBundle.exec()
|
buildJSBundle.exec()
|
||||||
buildDemo.exec()
|
buildDemo.exec()
|
||||||
buildDebugger.exec()
|
//buildDebugger.exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
task buildJSBundle(type: Exec) {
|
task buildJSBundle(type: Exec) {
|
||||||
|
@ -67,8 +67,8 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
|
|||||||
|
|
||||||
|
|
||||||
private void initJSExecutor() {
|
private void initJSExecutor() {
|
||||||
// mDoricJSE = new DoricNativeJSExecutor();
|
mDoricJSE = new DoricNativeJSExecutor();
|
||||||
mDoricJSE = new DoricRemoteJSExecutor();
|
// mDoricJSE = new DoricRemoteJSExecutor();
|
||||||
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_LOG, new JavaFunction() {
|
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_LOG, new JavaFunction() {
|
||||||
@Override
|
@Override
|
||||||
public JavaValue exec(JSDecoder[] args) {
|
public JavaValue exec(JSDecoder[] args) {
|
||||||
|
@ -116,12 +116,42 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||||
return new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
return new ViewGroup.LayoutParams(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void blendChild(ViewNode viewNode, JSObject jsObject) {
|
protected void blendChild(ViewNode viewNode, JSObject jsObject) {
|
||||||
|
|
||||||
|
|
||||||
JSValue jsValue = jsObject.getProperty("margin");
|
JSValue jsValue = jsObject.getProperty("margin");
|
||||||
|
JSValue widthSpec = jsObject.getProperty("widthSpec");
|
||||||
|
JSValue heightSpec = jsObject.getProperty("widthSpec");
|
||||||
|
|
||||||
ViewGroup.LayoutParams layoutParams = viewNode.getLayoutParams();
|
ViewGroup.LayoutParams layoutParams = viewNode.getLayoutParams();
|
||||||
|
if (widthSpec.isNumber()) {
|
||||||
|
switch (widthSpec.asNumber().toInt()) {
|
||||||
|
case 1:
|
||||||
|
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (heightSpec.isNumber()) {
|
||||||
|
switch (heightSpec.asNumber().toInt()) {
|
||||||
|
case 1:
|
||||||
|
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (jsValue.isObject() && layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
if (jsValue.isObject() && layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
JSValue topVal = jsValue.asObject().getProperty("top");
|
JSValue topVal = jsValue.asObject().getProperty("top");
|
||||||
if (topVal.isNumber()) {
|
if (topVal.isNumber()) {
|
||||||
|
@ -50,7 +50,7 @@ public class LinearNode extends GroupNode<LinearLayout> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||||
return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
return new LinearLayout.LayoutParams(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,6 +62,6 @@ public class StackNode extends GroupNode<FrameLayout> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||||
return new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
return new FrameLayout.LayoutParams(0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,16 +86,12 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
protected void blend(T view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) {
|
protected void blend(T view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "width":
|
case "width":
|
||||||
if (prop.asNumber().toInt() < 0) {
|
if (layoutParams.width >= 0) {
|
||||||
layoutParams.width = prop.asNumber().toInt();
|
|
||||||
} else {
|
|
||||||
layoutParams.width = DoricUtils.dp2px(prop.asNumber().toFloat());
|
layoutParams.width = DoricUtils.dp2px(prop.asNumber().toFloat());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "height":
|
case "height":
|
||||||
if (prop.asNumber().toInt() < 0) {
|
if (layoutParams.height >= 0) {
|
||||||
layoutParams.height = prop.asNumber().toInt();
|
|
||||||
} else {
|
|
||||||
layoutParams.height = DoricUtils.dp2px(prop.asNumber().toFloat());
|
layoutParams.height = DoricUtils.dp2px(prop.asNumber().toFloat());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -8,6 +8,7 @@ export default bundles.map(bundle => {
|
|||||||
output: {
|
output: {
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
file: `bundle/${bundle}.js`,
|
file: `bundle/${bundle}.js`,
|
||||||
|
sourcemap: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
resolve({ jsnext: true, main: true }),
|
resolve({ jsnext: true, main: true }),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Image, ViewHolder, VMPanel, ViewModel, Gravity, NativeCall, Text, Color, VLayout, log, logw, loge, Group, } from "doric"
|
import { Image, ViewHolder, VMPanel, ViewModel, Gravity, NativeCall, Text, Color, VLayout, log, logw, loge, Group, LayoutSpec, } from "doric"
|
||||||
|
|
||||||
|
|
||||||
interface CountModel {
|
interface CountModel {
|
||||||
@ -57,6 +57,10 @@ class CounterView extends ViewHolder {
|
|||||||
// iv.width = iv.height = 100
|
// iv.width = iv.height = 100
|
||||||
iv.imageUrl = "https://misc.aotu.io/ONE-SUNDAY/SteamEngine.png"
|
iv.imageUrl = "https://misc.aotu.io/ONE-SUNDAY/SteamEngine.png"
|
||||||
//iv.bgColor = Color.parse('#00ff00')
|
//iv.bgColor = Color.parse('#00ff00')
|
||||||
|
iv.layoutConfig = {
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
}
|
||||||
root.addChild(iv)
|
root.addChild(iv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { loge, log, ViewHolder, Stack, ViewModel, Gravity, Text, Color, HLayout, VLayout, Group, VMPanel } from "doric";
|
import { loge, log, ViewHolder, Stack, ViewModel, Gravity, Text, Color, HLayout, VLayout, Group, VMPanel, LayoutSpec } from "doric";
|
||||||
|
|
||||||
type SnakeNode = {
|
type SnakeNode = {
|
||||||
x: number
|
x: number
|
||||||
@ -154,10 +154,14 @@ class SnakeView extends ViewHolder {
|
|||||||
margin: {
|
margin: {
|
||||||
top: 20
|
top: 20
|
||||||
},
|
},
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
}
|
}
|
||||||
vlayout.space = 20
|
vlayout.space = 20
|
||||||
vlayout.layoutConfig = {
|
vlayout.layoutConfig = {
|
||||||
alignment: new Gravity().centerX().top()
|
alignment: new Gravity().centerX().top(),
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
}
|
}
|
||||||
this.panel.bgColor = Color.parse('#00ff00')
|
this.panel.bgColor = Color.parse('#00ff00')
|
||||||
vlayout.addChild(title)
|
vlayout.addChild(title)
|
||||||
@ -165,11 +169,20 @@ class SnakeView extends ViewHolder {
|
|||||||
root.addChild(vlayout)
|
root.addChild(vlayout)
|
||||||
|
|
||||||
const hlayout = new HLayout
|
const hlayout = new HLayout
|
||||||
this.start.text = "Start"
|
hlayout.layoutConfig = {
|
||||||
this.start.textSize = 30
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
this.start.textColor = Color.parse("#ffffff")
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
}
|
||||||
hlayout.addChild(this.start)
|
hlayout.addChild(this.start.also(
|
||||||
|
it => {
|
||||||
|
it.text = "Start"
|
||||||
|
it.textSize = 30
|
||||||
|
it.textColor = Color.parse("#ffffff")
|
||||||
|
it.layoutConfig = {
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
}
|
||||||
|
}))
|
||||||
vlayout.addChild(hlayout)
|
vlayout.addChild(hlayout)
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +195,9 @@ class SnakeView extends ViewHolder {
|
|||||||
controlArea.gravity = new Gravity().centerX()
|
controlArea.gravity = new Gravity().centerX()
|
||||||
controlArea.space = 10
|
controlArea.space = 10
|
||||||
controlArea.layoutConfig = {
|
controlArea.layoutConfig = {
|
||||||
alignment: new Gravity().centerX()
|
alignment: new Gravity().centerX(),
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
}
|
}
|
||||||
const line1 = new HLayout
|
const line1 = new HLayout
|
||||||
const line2 = new HLayout
|
const line2 = new HLayout
|
||||||
@ -191,6 +206,14 @@ class SnakeView extends ViewHolder {
|
|||||||
line2.addChild(this.left)
|
line2.addChild(this.left)
|
||||||
line2.addChild(this.down)
|
line2.addChild(this.down)
|
||||||
line2.addChild(this.right)
|
line2.addChild(this.right)
|
||||||
|
line1.layoutConfig = {
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
}
|
||||||
|
line2.layoutConfig = {
|
||||||
|
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||||
|
}
|
||||||
controlArea.addChild(line1)
|
controlArea.addChild(line1)
|
||||||
controlArea.addChild(line2)
|
controlArea.addChild(line2)
|
||||||
vlayout.addChild(controlArea)
|
vlayout.addChild(controlArea)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
"target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||||
@ -11,7 +10,7 @@
|
|||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
"sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
"outDir": "build/", /* Redirect output structure to the directory. */
|
"outDir": "build/", /* Redirect output structure to the directory. */
|
||||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
@ -53,7 +52,7 @@
|
|||||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||||
/* Experimental Options */
|
/* Experimental Options */
|
||||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
"emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */
|
"emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
@ -8,6 +8,7 @@ export default bundles.map(bundle => {
|
|||||||
output: {
|
output: {
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
file: `bundle/${bundle}.js`,
|
file: `bundle/${bundle}.js`,
|
||||||
|
sourcemap: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
resolve({ jsnext: true, main: true }),
|
resolve({ jsnext: true, main: true }),
|
||||||
|
@ -13,10 +13,12 @@
|
|||||||
#import "DoricNativePlugin.h"
|
#import "DoricNativePlugin.h"
|
||||||
#import "DoricRootNode.h"
|
#import "DoricRootNode.h"
|
||||||
#import "DoricLocalServer.h"
|
#import "DoricLocalServer.h"
|
||||||
|
#import "DoricLayouts.h"
|
||||||
|
#import "DoricExtensions.h"
|
||||||
|
|
||||||
@interface ViewController ()
|
@interface ViewController ()
|
||||||
@property (nonatomic,strong) DoricContext *doricContext;
|
@property(nonatomic, strong) DoricContext *doricContext;
|
||||||
@property (nonatomic,strong) DoricLocalServer *localServer;
|
@property(nonatomic, strong) DoricLocalServer *localServer;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ViewController
|
@implementation ViewController
|
||||||
@ -27,7 +29,10 @@ - (void)viewDidLoad {
|
|||||||
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"Snake" ofType:@"js"];
|
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"Snake" ofType:@"js"];
|
||||||
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
||||||
self.doricContext = [[DoricContext alloc] initWithScript:jsContent source:@"test.js"];
|
self.doricContext = [[DoricContext alloc] initWithScript:jsContent source:@"test.js"];
|
||||||
self.doricContext.rootNode.view = self.view;
|
[self.doricContext.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) {
|
||||||
|
it.layoutConfig = [[DoricStackConfig alloc] initWithWidth:DoricLayoutAtMost height:DoricLayoutAtMost];
|
||||||
|
[self.view addSubview:it];
|
||||||
|
}]];
|
||||||
[self.doricContext initContextWithWidth:self.view.width height:self.view.height];
|
[self.doricContext initContextWithWidth:self.view.width height:self.view.height];
|
||||||
[self.doricContext.driver connectDevKit:@"ws://192.168.11.38:7777"];
|
[self.doricContext.driver connectDevKit:@"ws://192.168.11.38:7777"];
|
||||||
self.localServer = [[DoricLocalServer alloc] init];
|
self.localServer = [[DoricLocalServer alloc] init];
|
||||||
|
@ -25,7 +25,7 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../"
|
:path: "../"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Doric: 1dae6e8a19a32a27af975f787509cc0658dde095
|
Doric: f96b77d435e836e88cf02319e3c9ebc08cab65f6
|
||||||
GCDWebServer: ead88cd14596dd4eae4f5830b8877c87c8728990
|
GCDWebServer: ead88cd14596dd4eae4f5830b8877c87c8728990
|
||||||
SDWebImage: 920f1a2ff1ca8296ad34f6e0510a1ef1d70ac965
|
SDWebImage: 920f1a2ff1ca8296ad34f6e0510a1ef1d70ac965
|
||||||
SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531
|
SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531
|
||||||
|
@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@property(nonatomic, strong) DoricRootNode *rootNode;
|
@property(nonatomic, strong) DoricRootNode *rootNode;
|
||||||
@property(nonatomic, strong) NSString *source;
|
@property(nonatomic, strong) NSString *source;
|
||||||
@property(nonatomic, strong) NSString *script;;
|
@property(nonatomic, strong) NSString *script;;
|
||||||
@property(nonatomic, strong) NSDictionary *initialParams;
|
@property(nonatomic, strong) NSMutableDictionary *initialParams;
|
||||||
|
|
||||||
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source;
|
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#import "DoricContextManager.h"
|
#import "DoricContextManager.h"
|
||||||
#import "DoricRootNode.h"
|
#import "DoricRootNode.h"
|
||||||
#import "DoricConstant.h"
|
#import "DoricConstant.h"
|
||||||
|
#import "DoricExtensions.h"
|
||||||
|
|
||||||
@implementation DoricContext
|
@implementation DoricContext
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ - (instancetype)initWithScript:(NSString *)script source:(NSString *)source {
|
|||||||
_rootNode = [[DoricRootNode alloc] initWithContext:self];
|
_rootNode = [[DoricRootNode alloc] initWithContext:self];
|
||||||
_script = script;
|
_script = script;
|
||||||
_source = source;
|
_source = source;
|
||||||
_initialParams = [@{@"width": @(LAYOUT_MATCH_PARENT), @"height": @(LAYOUT_MATCH_PARENT)} mutableCopy];
|
_initialParams = [@{@"width": @(0), @"height": @(0)} mutableCopy];
|
||||||
[self callEntity:DORIC_ENTITY_CREATE, nil];
|
[self callEntity:DORIC_ENTITY_CREATE, nil];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@ -63,8 +64,10 @@ - (DoricAsyncResult *)callEntity:(NSString *)method withArgumentsArray:(NSArray
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height {
|
- (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height {
|
||||||
[self.initialParams setValue:@(width) forKey:@"width"];
|
[self.initialParams also:^(NSMutableDictionary *it) {
|
||||||
[self.initialParams setValue:@(height) forKey:@"height"];
|
it[@"width"] = @(width);
|
||||||
|
it[@"height"] = @(height);
|
||||||
|
}];
|
||||||
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
|
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,15 +24,13 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface DoricGroupNode <V:UIView *, P:LayoutParams *> : DoricViewNode<V>
|
@interface DoricGroupNode <V:UIView *, P:DoricLayoutConfig *> : DoricViewNode<V>
|
||||||
|
|
||||||
@property(nonatomic, strong) NSMutableDictionary *children;
|
@property(nonatomic, strong) NSMutableDictionary *children;
|
||||||
@property(nonatomic, strong) NSMutableArray *indexedChildren;
|
@property(nonatomic, strong) NSMutableArray *indexedChildren;
|
||||||
|
|
||||||
@property(nonatomic) CGFloat desiredWidth;
|
|
||||||
@property(nonatomic) CGFloat desiredHeight;
|
|
||||||
|
|
||||||
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutconfig;
|
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutConfig;
|
||||||
|
|
||||||
- (P)generateDefaultLayoutParams;
|
- (P)generateDefaultLayoutParams;
|
||||||
@end
|
@end
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
// Created by pengfei.zhou on 2019/7/30.
|
// Created by pengfei.zhou on 2019/7/30.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#import <Doric/DoricExtensions.h>
|
||||||
#import "DoricGroupNode.h"
|
#import "DoricGroupNode.h"
|
||||||
|
|
||||||
@implementation DoricGroupNode
|
@implementation DoricGroupNode
|
||||||
@ -72,10 +73,10 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
[tobeRemoved addObject:old];
|
[tobeRemoved addObject:old];
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutParams *params = node.layoutParams;
|
DoricLayoutConfig *params = node.layoutConfig;
|
||||||
if (params == nil) {
|
if (params == nil) {
|
||||||
params = [self generateDefaultLayoutParams];
|
params = [self generateDefaultLayoutParams];
|
||||||
node.layoutParams = params;
|
node.layoutConfig = params;
|
||||||
}
|
}
|
||||||
[node blend:val[@"props"]];
|
[node blend:val[@"props"]];
|
||||||
if (self.indexedChildren.count <= i) {
|
if (self.indexedChildren.count <= i) {
|
||||||
@ -108,21 +109,35 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (LayoutParams *)generateDefaultLayoutParams {
|
- (DoricLayoutConfig *)generateDefaultLayoutParams {
|
||||||
LayoutParams *params = [[LayoutParams alloc] init];
|
DoricLayoutConfig *params = [[DoricLayoutConfig alloc] init];
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutconfig {
|
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutConfig {
|
||||||
LayoutParams *params = child.layoutParams;
|
DoricLayoutConfig *params = child.layoutConfig;
|
||||||
if ([params isKindOfClass:MarginLayoutParams.class]) {
|
|
||||||
MarginLayoutParams *marginParams = (MarginLayoutParams *) params;
|
[layoutConfig[@"widthSpec"] also:^(NSNumber *it) {
|
||||||
NSDictionary *margin = layoutconfig[@"margin"];
|
if (it) {
|
||||||
|
params.widthSpec = (DoricLayoutSpec) [it integerValue];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[layoutConfig[@"heightSpec"] also:^(NSNumber *it) {
|
||||||
|
if (it) {
|
||||||
|
params.heightSpec = (DoricLayoutSpec) [it integerValue];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
if ([params isKindOfClass:DoricMarginConfig.class]) {
|
||||||
|
DoricMarginConfig *marginParams = (DoricMarginConfig *) params;
|
||||||
|
NSDictionary *margin = layoutConfig[@"margin"];
|
||||||
if (margin) {
|
if (margin) {
|
||||||
marginParams.margin.top = [(NSNumber *) margin[@"top"] floatValue];
|
marginParams.margin = DoricMarginMake(
|
||||||
marginParams.margin.left = [(NSNumber *) margin[@"left"] floatValue];
|
[(NSNumber *) margin[@"left"] floatValue],
|
||||||
marginParams.margin.right = [(NSNumber *) margin[@"right"] floatValue];
|
[(NSNumber *) margin[@"top"] floatValue],
|
||||||
marginParams.margin.bottom = [(NSNumber *) margin[@"bottom"] floatValue];
|
[(NSNumber *) margin[@"right"] floatValue],
|
||||||
|
[(NSNumber *) margin[@"bottom"] floatValue]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +22,5 @@
|
|||||||
|
|
||||||
#import "DoricGroupNode.h"
|
#import "DoricGroupNode.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
@interface DoricHLayoutNode : DoricGroupNode<DoricHLayoutView *, DoricLinearConfig *>
|
||||||
|
|
||||||
@interface DoricHLayoutNode : DoricGroupNode<UIView *, VHLayoutParams *>
|
|
||||||
@property(nonatomic) CGFloat space;
|
|
||||||
@property(nonatomic) DoricGravity gravity;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
|
@ -24,114 +24,42 @@
|
|||||||
#import "DoricUtil.h"
|
#import "DoricUtil.h"
|
||||||
|
|
||||||
@implementation DoricHLayoutNode
|
@implementation DoricHLayoutNode
|
||||||
- (instancetype)init {
|
- (DoricHLayoutView *)build:(NSDictionary *)props {
|
||||||
if (self = [super init]) {
|
return [DoricHLayoutView new];
|
||||||
_space = 0;
|
|
||||||
_gravity = 0;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)blendView:(id)view forPropName:(NSString *)name propValue:(id)prop {
|
- (void)blendView:(DoricHLayoutView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||||
if ([name isEqualToString:@"gravity"]) {
|
if ([name isEqualToString:@"gravity"]) {
|
||||||
self.gravity = [(NSNumber *)prop integerValue];
|
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||||
} else if ([name isEqualToString:@"space"]) {
|
} else if ([name isEqualToString:@"space"]) {
|
||||||
self.space = [(NSNumber *)prop floatValue];
|
view.space = [(NSNumber *) prop floatValue];
|
||||||
} else {
|
} else {
|
||||||
[super blendView:view forPropName:name propValue:prop];
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutconfig {
|
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutConfig {
|
||||||
[super blendChild:child layoutConfig:layoutconfig];
|
[super blendChild:child layoutConfig:layoutConfig];
|
||||||
if (![child.layoutParams isKindOfClass:VHLayoutParams.class]) {
|
if (![child.layoutConfig isKindOfClass:DoricLinearConfig.class]) {
|
||||||
DoricLog(@"blend HLayout child error,layout params not match");
|
DoricLog(@"blend DoricHLayoutView child error,layout params not match");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VHLayoutParams *params = (VHLayoutParams *)child.layoutParams;
|
DoricLinearConfig *params = (DoricLinearConfig *) child.layoutConfig;
|
||||||
NSDictionary *margin = [layoutconfig objectForKey:@"margin"];
|
NSDictionary *margin = layoutConfig[@"margin"];
|
||||||
if (margin) {
|
if (margin) {
|
||||||
params.margin.top = [(NSNumber *)[margin objectForKey:@"top"] floatValue];
|
params.margin = DoricMarginMake(
|
||||||
params.margin.left = [(NSNumber *)[margin objectForKey:@"left"] floatValue];
|
[(NSNumber *) margin[@"left"] floatValue],
|
||||||
params.margin.right = [(NSNumber *)[margin objectForKey:@"right"] floatValue];
|
[(NSNumber *) margin[@"top"] floatValue],
|
||||||
params.margin.bottom = [(NSNumber *)[margin objectForKey:@"bottom"] floatValue];
|
[(NSNumber *) margin[@"right"] floatValue],
|
||||||
|
[(NSNumber *) margin[@"bottom"] floatValue]);
|
||||||
}
|
}
|
||||||
NSNumber *alignment = [layoutconfig objectForKey:@"alignment"];
|
NSNumber *alignment = layoutConfig[@"alignment"];
|
||||||
if (alignment) {
|
if (alignment) {
|
||||||
params.alignment = [alignment integerValue];
|
params.alignment = (DoricGravity) [alignment integerValue];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (VHLayoutParams *)generateDefaultLayoutParams {
|
- (DoricLinearConfig *)generateDefaultLayoutParams {
|
||||||
return [[VHLayoutParams alloc] init];
|
return [[DoricLinearConfig alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent {
|
|
||||||
DoricLayoutDesc widthSpec = self.layoutParams.width;
|
|
||||||
DoricLayoutDesc heightSpec = self.layoutParams.height;
|
|
||||||
CGFloat maxWidth = 0,maxHeight = 0;
|
|
||||||
for (DoricViewNode *child in self.indexedChildren) {
|
|
||||||
[child measureByParent:self];
|
|
||||||
CGFloat placeWidth = child.measuredWidth;
|
|
||||||
CGFloat placeHeight = child.measuredHeight;
|
|
||||||
maxWidth += placeWidth + self.space;
|
|
||||||
maxHeight = MAX(maxHeight, placeHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
maxWidth -= self.space;
|
|
||||||
|
|
||||||
self.desiredWidth = maxWidth;
|
|
||||||
self.desiredHeight = maxHeight;
|
|
||||||
|
|
||||||
if (widthSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
self.width = maxWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heightSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
self.height = maxHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutByParent:(DoricGroupNode *)parent {
|
|
||||||
if (self.layoutParams.width == LAYOUT_MATCH_PARENT) {
|
|
||||||
self.width = parent.width;
|
|
||||||
}
|
|
||||||
if (self.layoutParams.height == LAYOUT_MATCH_PARENT) {
|
|
||||||
self.height = parent.height;
|
|
||||||
}
|
|
||||||
// layout child
|
|
||||||
CGFloat xStart = 0;
|
|
||||||
if ((self.gravity & LEFT) == LEFT) {
|
|
||||||
xStart = 0;
|
|
||||||
} else if ((self.gravity & RIGHT) == RIGHT) {
|
|
||||||
xStart = self.width - self.desiredWidth;
|
|
||||||
} else if ((self.gravity & CENTER_X) == CENTER_X) {
|
|
||||||
xStart = (self.width -self.desiredWidth)/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (DoricViewNode *child in self.indexedChildren) {
|
|
||||||
if (child.layoutParams.width == LAYOUT_MATCH_PARENT) {
|
|
||||||
child.width = self.width;
|
|
||||||
}
|
|
||||||
if (child.layoutParams.height == LAYOUT_MATCH_PARENT) {
|
|
||||||
child.height = self.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([child.layoutParams isKindOfClass:VHLayoutParams.class]) {
|
|
||||||
VHLayoutParams *layoutParams = (VHLayoutParams *)child.layoutParams;
|
|
||||||
DoricGravity gravity = layoutParams.alignment | self.gravity;
|
|
||||||
if ((gravity & TOP) == TOP) {
|
|
||||||
child.top = 0;
|
|
||||||
} else if ((gravity & BOTTOM) == BOTTOM) {
|
|
||||||
child.bottom = self.height;
|
|
||||||
} else if ((gravity & CENTER_Y) == CENTER_Y) {
|
|
||||||
child.centerY = self.height/2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
child.left = xStart;
|
|
||||||
xStart = child.right + self.space;
|
|
||||||
[child layoutByParent:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -40,12 +40,4 @@ - (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id
|
|||||||
[super blendView:view forPropName:name propValue:prop];
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent {
|
|
||||||
DoricLayoutDesc widthSpec = self.layoutParams.width;
|
|
||||||
DoricLayoutDesc heightSpec = self.layoutParams.height;
|
|
||||||
if (widthSpec == LAYOUT_WRAP_CONTENT || heightSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
[self.view sizeToFit];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
@end
|
||||||
|
109
iOS/Pod/Classes/Shader/DoricLayouts.h
Normal file
109
iOS/Pod/Classes/Shader/DoricLayouts.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct DoricMargin {
|
||||||
|
CGFloat left;
|
||||||
|
CGFloat right;
|
||||||
|
CGFloat top;
|
||||||
|
CGFloat bottom;
|
||||||
|
};
|
||||||
|
typedef struct DoricMargin DoricMargin;
|
||||||
|
|
||||||
|
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom);
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSInteger, DoricLayoutSpec) {
|
||||||
|
DoricLayoutExact,
|
||||||
|
DoricLayoutWrapContent,
|
||||||
|
DoricLayoutAtMost,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSInteger, DoricGravity) {
|
||||||
|
SPECIFIED = 1,
|
||||||
|
START = 1 << 1,
|
||||||
|
END = 1 << 2,
|
||||||
|
SHIFT_X = 0,
|
||||||
|
SHIFT_Y = 4,
|
||||||
|
LEFT = (START | SPECIFIED) << SHIFT_X,
|
||||||
|
RIGHT = (END | SPECIFIED) << SHIFT_X,
|
||||||
|
TOP = (START | SPECIFIED) << SHIFT_Y,
|
||||||
|
BOTTOM = (END | SPECIFIED) << SHIFT_Y,
|
||||||
|
CENTER_X = SPECIFIED << SHIFT_X,
|
||||||
|
CENTER_Y = SPECIFIED << SHIFT_Y,
|
||||||
|
CENTER = CENTER_X | CENTER_Y,
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface DoricLayoutConfig : NSObject
|
||||||
|
@property(nonatomic, assign) DoricLayoutSpec widthSpec;
|
||||||
|
@property(nonatomic, assign) DoricLayoutSpec heightSpec;
|
||||||
|
@property(nonatomic, assign) DoricGravity alignment;
|
||||||
|
|
||||||
|
- (instancetype)init;
|
||||||
|
|
||||||
|
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricStackConfig : DoricLayoutConfig
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricMarginConfig : DoricLayoutConfig
|
||||||
|
@property(nonatomic) DoricMargin margin;
|
||||||
|
|
||||||
|
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricLinearConfig : DoricMarginConfig
|
||||||
|
@property(nonatomic, assign) NSUInteger weight;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface DoricLayoutContainer <T :DoricLayoutConfig *> : UIView
|
||||||
|
|
||||||
|
- (T)configForChild:(__kindof UIView *)child;
|
||||||
|
|
||||||
|
- (void)layout;
|
||||||
|
|
||||||
|
- (void)requestLayout;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricStackView : DoricLayoutContainer<DoricStackConfig *>
|
||||||
|
@property(nonatomic, assign) DoricGravity gravity;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricLinearView : DoricLayoutContainer<DoricLinearConfig *>
|
||||||
|
@property(nonatomic, assign) DoricGravity gravity;
|
||||||
|
@property(nonatomic, assign) CGFloat space;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface DoricVLayoutView : DoricLinearView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricHLayoutView : DoricLinearView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface UIView (DoricLayoutConfig)
|
||||||
|
@property(nonatomic, strong) DoricLayoutConfig *layoutConfig;
|
||||||
|
@property(nonatomic, copy) NSString *tagString;
|
||||||
|
|
||||||
|
- (UIView *)viewWithTagString:(NSString *)tagString;
|
||||||
|
@end
|
505
iOS/Pod/Classes/Shader/DoricLayouts.m
Normal file
505
iOS/Pod/Classes/Shader/DoricLayouts.m
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
* 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/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "DoricLayouts.h"
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import "UIView+Doric.h"
|
||||||
|
|
||||||
|
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) {
|
||||||
|
DoricMargin margin;
|
||||||
|
margin.left = left;
|
||||||
|
margin.top = top;
|
||||||
|
margin.right = right;
|
||||||
|
margin.bottom = bottom;
|
||||||
|
return margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation DoricLayoutConfig
|
||||||
|
- (instancetype)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_widthSpec = DoricLayoutExact;
|
||||||
|
_heightSpec = DoricLayoutExact;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_widthSpec = width;
|
||||||
|
_heightSpec = height;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricMarginConfig
|
||||||
|
- (instancetype)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_margin = DoricMarginMake(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin {
|
||||||
|
if (self = [super initWithWidth:width height:height]) {
|
||||||
|
_margin = margin;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricStackConfig
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricLinearConfig
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface DoricLayoutContainer ()
|
||||||
|
@property(nonatomic, assign) BOOL waitingLayout;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricLayoutContainer
|
||||||
|
- (instancetype)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_waitingLayout = NO;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
_waitingLayout = NO;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||||
|
if (self = [super initWithCoder:coder]) {
|
||||||
|
_waitingLayout = NO;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (DoricLayoutConfig *)configForChild:(UIView *)child {
|
||||||
|
DoricLayoutConfig *config = child.layoutConfig;
|
||||||
|
if (!config) {
|
||||||
|
config = [[DoricLayoutConfig alloc] init];
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)requestLayout {
|
||||||
|
if ([self.superview isKindOfClass:[DoricLinearView class]]) {
|
||||||
|
[(DoricLinearView *) self.superview requestLayout];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self.waitingLayout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.waitingLayout = YES;
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
self.waitingLayout = NO;
|
||||||
|
[self sizeToFit];
|
||||||
|
[self layout];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
[super layoutSubviews];
|
||||||
|
[self requestLayout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layout {
|
||||||
|
[self.subviews enumerateObjectsUsingBlock:^(__kindof UIView *child, NSUInteger idx, BOOL *stop) {
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]) {
|
||||||
|
[(DoricLayoutContainer *) child layout];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@interface DoricStackView ()
|
||||||
|
|
||||||
|
@property(nonatomic, assign) CGFloat contentWidth;
|
||||||
|
@property(nonatomic, assign) CGFloat contentHeight;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricStackView
|
||||||
|
- (DoricStackConfig *)configForChild:(UIView *)child {
|
||||||
|
DoricStackConfig *config = (DoricStackConfig *) child.layoutConfig;
|
||||||
|
if (!config) {
|
||||||
|
config = [[DoricStackConfig alloc] init];
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)sizeToFit {
|
||||||
|
DoricLayoutConfig *config = self.layoutConfig;
|
||||||
|
self.contentWidth = 0;
|
||||||
|
self.contentHeight = 0;
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricStackConfig *childConfig = [self configForChild:child];
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]
|
||||||
|
|| childConfig.widthSpec == DoricLayoutWrapContent
|
||||||
|
|| childConfig.heightSpec == DoricLayoutWrapContent) {
|
||||||
|
[child sizeToFit];
|
||||||
|
}
|
||||||
|
self.contentWidth = MAX(self.contentWidth, child.width);
|
||||||
|
self.contentHeight = MAX(self.contentHeight, child.height);
|
||||||
|
}
|
||||||
|
if (config.widthSpec == DoricLayoutWrapContent) {
|
||||||
|
self.width = self.contentWidth;
|
||||||
|
} else if (config.widthSpec == DoricLayoutAtMost) {
|
||||||
|
self.width = self.superview.width;
|
||||||
|
}
|
||||||
|
if (config.heightSpec == DoricLayoutWrapContent) {
|
||||||
|
self.height = self.contentHeight;
|
||||||
|
} else if (config.heightSpec == DoricLayoutAtMost) {
|
||||||
|
self.height = self.superview.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layout {
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricStackConfig *childConfig = [self configForChild:child];
|
||||||
|
DoricGravity gravity = childConfig.alignment | self.gravity;
|
||||||
|
if ((gravity & LEFT) == LEFT) {
|
||||||
|
child.left = 0;
|
||||||
|
} else if ((gravity & RIGHT) == RIGHT) {
|
||||||
|
child.right = self.width;
|
||||||
|
} else if ((gravity & CENTER_X) == CENTER_X) {
|
||||||
|
child.centerX = self.width / 2;
|
||||||
|
}
|
||||||
|
if ((gravity & TOP) == TOP) {
|
||||||
|
child.top = 0;
|
||||||
|
} else if ((gravity & BOTTOM) == BOTTOM) {
|
||||||
|
child.bottom = self.height;
|
||||||
|
} else if ((gravity & CENTER_Y) == CENTER_Y) {
|
||||||
|
child.centerY = self.height / 2;
|
||||||
|
}
|
||||||
|
if (childConfig.widthSpec == DoricLayoutAtMost) {
|
||||||
|
child.width = self.width;
|
||||||
|
}
|
||||||
|
if (childConfig.heightSpec == DoricLayoutAtMost) {
|
||||||
|
child.height = self.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]) {
|
||||||
|
[(DoricLayoutContainer *) child layout];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface DoricLinearView ()
|
||||||
|
@property(nonatomic, assign) CGFloat contentWidth;
|
||||||
|
@property(nonatomic, assign) CGFloat contentHeight;
|
||||||
|
@property(nonatomic, assign) NSUInteger contentWeight;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricLinearView
|
||||||
|
- (DoricLinearConfig *)configForChild:(UIView *)child {
|
||||||
|
DoricLinearConfig *config = (DoricLinearConfig *) child.layoutConfig;
|
||||||
|
if (!config) {
|
||||||
|
config = [[DoricLinearConfig alloc] init];
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricVLayoutView
|
||||||
|
|
||||||
|
- (void)sizeToFit {
|
||||||
|
DoricLayoutConfig *config = self.layoutConfig;
|
||||||
|
self.contentWidth = 0;
|
||||||
|
self.contentHeight = 0;
|
||||||
|
self.contentWeight = 0;
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricLinearConfig *childConfig = [self configForChild:child];
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]
|
||||||
|
|| childConfig.widthSpec == DoricLayoutWrapContent
|
||||||
|
|| childConfig.heightSpec == DoricLayoutWrapContent) {
|
||||||
|
[child sizeToFit];
|
||||||
|
}
|
||||||
|
self.contentWidth = MAX(self.contentWidth, child.width + childConfig.margin.left + childConfig.margin.right);
|
||||||
|
self.contentHeight += child.height + self.space + childConfig.margin.top + childConfig.margin.bottom;
|
||||||
|
self.contentWeight += childConfig.weight;
|
||||||
|
}
|
||||||
|
self.contentHeight -= self.space;
|
||||||
|
if (config.widthSpec == DoricLayoutWrapContent) {
|
||||||
|
self.width = self.contentWidth;
|
||||||
|
} else if (config.widthSpec == DoricLayoutAtMost) {
|
||||||
|
self.width = self.superview.width;
|
||||||
|
}
|
||||||
|
if (config.heightSpec == DoricLayoutWrapContent) {
|
||||||
|
self.height = self.contentHeight;
|
||||||
|
} else if (config.heightSpec == DoricLayoutAtMost) {
|
||||||
|
self.height = self.superview.height;
|
||||||
|
}
|
||||||
|
if (self.contentWeight) {
|
||||||
|
CGFloat remain = self.height - self.contentHeight;
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricLinearConfig *childConfig = [self configForChild:child];
|
||||||
|
if (childConfig.weight) {
|
||||||
|
child.height += remain / self.contentWeight * childConfig.weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.contentHeight = self.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layout {
|
||||||
|
CGFloat yStart = 0;
|
||||||
|
if ((self.gravity & TOP) == TOP) {
|
||||||
|
yStart = 0;
|
||||||
|
} else if ((self.gravity & BOTTOM) == BOTTOM) {
|
||||||
|
yStart = self.height - self.contentHeight;
|
||||||
|
} else if ((self.gravity & CENTER_Y) == CENTER_Y) {
|
||||||
|
yStart = (self.height - self.contentHeight) / 2;
|
||||||
|
}
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricLinearConfig *childConfig = [self configForChild:child];
|
||||||
|
DoricGravity gravity = childConfig.alignment | self.gravity;
|
||||||
|
if ((gravity & LEFT) == LEFT) {
|
||||||
|
child.left = 0;
|
||||||
|
} else if ((gravity & RIGHT) == RIGHT) {
|
||||||
|
child.right = self.width;
|
||||||
|
} else if ((gravity & CENTER_X) == CENTER_X) {
|
||||||
|
child.centerX = self.width / 2;
|
||||||
|
} else {
|
||||||
|
if (childConfig.margin.left) {
|
||||||
|
child.left = childConfig.margin.left;
|
||||||
|
} else if (childConfig.margin.right) {
|
||||||
|
child.right = self.width - childConfig.margin.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (childConfig.widthSpec == DoricLayoutAtMost) {
|
||||||
|
child.width = self.width;
|
||||||
|
}
|
||||||
|
if (childConfig.heightSpec == DoricLayoutAtMost) {
|
||||||
|
child.height = self.height - yStart - childConfig.margin.top - childConfig.margin.bottom - self.space;
|
||||||
|
}
|
||||||
|
if (childConfig.margin.top) {
|
||||||
|
yStart += childConfig.margin.top;
|
||||||
|
}
|
||||||
|
child.top = yStart;
|
||||||
|
yStart = child.bottom + self.space;
|
||||||
|
if (childConfig.margin.bottom) {
|
||||||
|
yStart += childConfig.margin.bottom;
|
||||||
|
}
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]) {
|
||||||
|
[(DoricLayoutContainer *) child layout];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DoricHLayoutView
|
||||||
|
- (void)sizeToFit {
|
||||||
|
DoricLinearConfig *config;
|
||||||
|
if ([self.superview isKindOfClass:[DoricLinearView class]]) {
|
||||||
|
config = [(DoricLinearView *) self.superview configForChild:self];
|
||||||
|
} else {
|
||||||
|
config = (DoricLinearConfig *) self.layoutConfig;
|
||||||
|
if (!config) {
|
||||||
|
config = [[DoricLinearConfig alloc] init];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.contentWidth = 0;
|
||||||
|
self.contentHeight = 0;
|
||||||
|
self.contentWeight = 0;
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricLinearConfig *childConfig = [self configForChild:child];
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]
|
||||||
|
|| childConfig.widthSpec == DoricLayoutWrapContent
|
||||||
|
|| childConfig.heightSpec == DoricLayoutWrapContent) {
|
||||||
|
[child sizeToFit];
|
||||||
|
}
|
||||||
|
self.contentHeight = MAX(self.contentHeight, child.height + childConfig.margin.top + childConfig.margin.bottom);
|
||||||
|
self.contentWidth += child.width + self.space + childConfig.margin.left + childConfig.margin.right;
|
||||||
|
self.contentWeight += childConfig.weight;
|
||||||
|
}
|
||||||
|
self.contentWidth -= self.space;
|
||||||
|
if (config.widthSpec == DoricLayoutWrapContent) {
|
||||||
|
self.width = self.contentWidth;
|
||||||
|
} else if (config.widthSpec == DoricLayoutAtMost) {
|
||||||
|
self.width = self.superview.width;
|
||||||
|
}
|
||||||
|
if (config.heightSpec == DoricLayoutWrapContent) {
|
||||||
|
self.height = self.contentHeight;
|
||||||
|
} else if (config.heightSpec == DoricLayoutAtMost) {
|
||||||
|
self.height = self.superview.height;
|
||||||
|
}
|
||||||
|
if (self.contentWeight) {
|
||||||
|
CGFloat remain = self.width - self.contentWidth;
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricLinearConfig *childConfig = [self configForChild:child];
|
||||||
|
if (childConfig.weight) {
|
||||||
|
child.width += remain / self.contentWeight * childConfig.weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.contentWidth = self.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)layout {
|
||||||
|
CGFloat xStart = 0;
|
||||||
|
if ((self.gravity & LEFT) == LEFT) {
|
||||||
|
xStart = 0;
|
||||||
|
} else if ((self.gravity & RIGHT) == RIGHT) {
|
||||||
|
xStart = self.width - self.contentWidth;
|
||||||
|
} else if ((self.gravity & CENTER_X) == CENTER_X) {
|
||||||
|
xStart = (self.width - self.contentWidth) / 2;
|
||||||
|
}
|
||||||
|
for (UIView *child in self.subviews) {
|
||||||
|
if (child.isHidden) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DoricLinearConfig *childConfig = [self configForChild:child];
|
||||||
|
DoricGravity gravity = childConfig.alignment | self.gravity;
|
||||||
|
if ((gravity & TOP) == TOP) {
|
||||||
|
child.top = 0;
|
||||||
|
} else if ((gravity & BOTTOM) == BOTTOM) {
|
||||||
|
child.bottom = self.height;
|
||||||
|
} else if ((gravity & CENTER_Y) == CENTER_Y) {
|
||||||
|
child.centerY = self.height / 2;
|
||||||
|
} else {
|
||||||
|
if (childConfig.margin.top) {
|
||||||
|
child.top = childConfig.margin.top;
|
||||||
|
} else if (childConfig.margin.bottom) {
|
||||||
|
child.bottom = self.height - childConfig.margin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childConfig.heightSpec == DoricLayoutAtMost) {
|
||||||
|
child.height = self.height;
|
||||||
|
}
|
||||||
|
if (childConfig.widthSpec == DoricLayoutAtMost) {
|
||||||
|
child.width = self.width - xStart - childConfig.margin.right - childConfig.margin.left - self.space;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childConfig.margin.left) {
|
||||||
|
xStart += childConfig.margin.left;
|
||||||
|
}
|
||||||
|
child.left = xStart;
|
||||||
|
xStart = child.right + self.space;
|
||||||
|
if (childConfig.margin.right) {
|
||||||
|
xStart += childConfig.margin.right;
|
||||||
|
}
|
||||||
|
if ([child isKindOfClass:[DoricLayoutContainer class]]) {
|
||||||
|
[(DoricLayoutContainer *) child layout];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static const void *kLayoutConfig = &kLayoutConfig;
|
||||||
|
static const void *kTagString = &kTagString;
|
||||||
|
|
||||||
|
@implementation UIView (DoricLayoutConfig)
|
||||||
|
@dynamic layoutConfig;
|
||||||
|
|
||||||
|
- (void)setLayoutConfig:(DoricLayoutConfig *)layoutConfig {
|
||||||
|
objc_setAssociatedObject(self, kLayoutConfig, layoutConfig, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (DoricLayoutConfig *)layoutConfig {
|
||||||
|
return objc_getAssociatedObject(self, kLayoutConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTagString:(NSString *)tagString {
|
||||||
|
objc_setAssociatedObject(self, kTagString, tagString, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||||
|
self.tag = [tagString hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)tagString {
|
||||||
|
return objc_getAssociatedObject(self, kTagString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (UIView *)viewWithTagString:(NSString *)tagString {
|
||||||
|
// notice the potential hash collision
|
||||||
|
return [self viewWithTag:[tagString hash]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
DoricVLayoutView *vLayout(NSArray <__kindof UIView *> *views) {
|
||||||
|
DoricVLayoutView *layout = [[DoricVLayoutView alloc] initWithFrame:CGRectZero];
|
||||||
|
for (__kindof UIView *uiView in views) {
|
||||||
|
[layout addSubview:uiView];
|
||||||
|
}
|
||||||
|
layout.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutWrapContent height:DoricLayoutWrapContent];
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoricHLayoutView *hLayout(NSArray <__kindof UIView *> *views) {
|
||||||
|
DoricHLayoutView *layout = [[DoricHLayoutView alloc] initWithFrame:CGRectZero];
|
||||||
|
for (__kindof UIView *uiView in views) {
|
||||||
|
[layout addSubview:uiView];
|
||||||
|
}
|
||||||
|
layout.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutWrapContent height:DoricLayoutWrapContent];
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoricVLayoutView *vLayoutWithBlock(NSArray <UIView *(^)()> *blocks) {
|
||||||
|
DoricVLayoutView *layout = [[DoricVLayoutView alloc] initWithFrame:CGRectZero];
|
||||||
|
UIView *(^block)();
|
||||||
|
for (block in blocks) {
|
||||||
|
[layout addSubview:block()];
|
||||||
|
}
|
||||||
|
layout.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutWrapContent height:DoricLayoutWrapContent];
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoricHLayoutView *hLayoutWithBlock(NSArray <UIView *(^)()> *blocks) {
|
||||||
|
DoricHLayoutView *layout = [[DoricHLayoutView alloc] initWithFrame:CGRectZero];
|
||||||
|
UIView *(^block)();
|
||||||
|
for (block in blocks) {
|
||||||
|
[layout addSubview:block()];
|
||||||
|
}
|
||||||
|
layout.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutWrapContent height:DoricLayoutWrapContent];
|
||||||
|
return layout;
|
||||||
|
}
|
@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@interface DoricRootNode : DoricStackNode
|
@interface DoricRootNode : DoricStackNode
|
||||||
|
|
||||||
- (void)setupRootView:(UIView *)view;
|
- (void)setupRootView:(DoricStackView *)view;
|
||||||
|
|
||||||
- (void)render:(NSDictionary *)props;
|
- (void)render:(NSDictionary *)props;
|
||||||
@end
|
@end
|
||||||
|
@ -23,17 +23,15 @@
|
|||||||
#import "DoricRootNode.h"
|
#import "DoricRootNode.h"
|
||||||
|
|
||||||
@implementation DoricRootNode
|
@implementation DoricRootNode
|
||||||
- (void)setupRootView:(UIView *)view {
|
- (void)setupRootView:(DoricStackView *)view {
|
||||||
self.view = view;
|
self.view = view;
|
||||||
|
self.layoutConfig = view.layoutConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)render:(NSDictionary *)props {
|
- (void)render:(NSDictionary *)props {
|
||||||
[self blend:props];
|
[self blend:props];
|
||||||
[self requestLayout];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)requestLayout {
|
- (void)requestLayout {
|
||||||
[self measureByParent:self];
|
[self.view requestLayout];
|
||||||
[self layoutByParent:self];
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
@ -22,10 +22,5 @@
|
|||||||
|
|
||||||
#import "DoricGroupNode.h"
|
#import "DoricGroupNode.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
@interface DoricStackNode : DoricGroupNode<DoricStackView *, DoricStackConfig *>
|
||||||
|
|
||||||
@interface DoricStackNode : DoricGroupNode<UIView *, StackLayoutParams *>
|
|
||||||
@property(nonatomic) DoricGravity gravity;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
|
@ -25,93 +25,33 @@
|
|||||||
|
|
||||||
@implementation DoricStackNode
|
@implementation DoricStackNode
|
||||||
|
|
||||||
- (instancetype)init {
|
- (DoricStackView *)build:(NSDictionary *)props {
|
||||||
if (self = [super init]) {
|
return [DoricStackView new];
|
||||||
_gravity = 0;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent {
|
- (void)blendView:(DoricStackView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||||
DoricLayoutDesc widthSpec = self.layoutParams.width;
|
if ([name isEqualToString:@"gravity"]) {
|
||||||
DoricLayoutDesc heightSpec = self.layoutParams.height;
|
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||||
CGFloat maxWidth = 0, maxHeight = 0;
|
} else {
|
||||||
for (DoricViewNode *child in self.indexedChildren) {
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
[child measureByParent:self];
|
|
||||||
CGFloat placeWidth = child.measuredWidth;
|
|
||||||
CGFloat placeHeight = child.measuredHeight;
|
|
||||||
maxWidth = MAX(maxWidth, placeWidth);
|
|
||||||
maxHeight = MAX(maxHeight, placeHeight);
|
|
||||||
}
|
|
||||||
self.desiredWidth = maxWidth;
|
|
||||||
self.desiredHeight = maxHeight;
|
|
||||||
|
|
||||||
if (widthSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
self.width = maxWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heightSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
self.height = maxHeight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (LayoutParams *)generateDefaultLayoutParams {
|
- (DoricStackConfig *)generateDefaultLayoutParams {
|
||||||
return [[StackLayoutParams alloc] init];
|
return [[DoricStackConfig alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutconfig {
|
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutConfig {
|
||||||
[super blendChild:child layoutConfig:layoutconfig];
|
[super blendChild:child layoutConfig:layoutConfig];
|
||||||
if (![child.layoutParams isKindOfClass:StackLayoutParams.class]) {
|
if (![child.layoutConfig isKindOfClass:DoricStackConfig.class]) {
|
||||||
DoricLog(@"blend Stack child error,layout params not match");
|
DoricLog(@"blend DoricHLayoutView child error,layout params not match");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StackLayoutParams *params = (StackLayoutParams *) child.layoutParams;
|
DoricStackConfig *params = (DoricStackConfig *) child.layoutConfig;
|
||||||
// NSDictionary *margin = [layoutconfig objectForKey:@"margin"];
|
NSNumber *alignment = layoutConfig[@"alignment"];
|
||||||
// if (margin) {
|
|
||||||
// params.margin.top = [(NSNumber *)[margin objectForKey:@"top"] floatValue];
|
|
||||||
// params.margin.left = [(NSNumber *)[margin objectForKey:@"left"] floatValue];
|
|
||||||
// params.margin.right = [(NSNumber *)[margin objectForKey:@"right"] floatValue];
|
|
||||||
// params.margin.bottom = [(NSNumber *)[margin objectForKey:@"bottom"] floatValue];
|
|
||||||
// }
|
|
||||||
NSNumber *alignment = layoutconfig[@"alignment"];
|
|
||||||
if (alignment) {
|
if (alignment) {
|
||||||
params.alignment = [alignment integerValue];
|
params.alignment = (DoricGravity) [alignment integerValue];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutByParent:(DoricGroupNode *)parent {
|
|
||||||
for (DoricViewNode *child in self.indexedChildren) {
|
|
||||||
if (child.layoutParams.width == LAYOUT_MATCH_PARENT) {
|
|
||||||
child.width = self.width;
|
|
||||||
}
|
|
||||||
if (child.layoutParams.height == LAYOUT_MATCH_PARENT) {
|
|
||||||
child.height = self.height;
|
|
||||||
}
|
|
||||||
DoricGravity gravity = self.gravity;
|
|
||||||
if ([child.layoutParams isKindOfClass:StackLayoutParams.class]) {
|
|
||||||
StackLayoutParams *layoutParams = (StackLayoutParams *) child.layoutParams;
|
|
||||||
gravity |= layoutParams.alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((gravity & LEFT) == LEFT) {
|
|
||||||
child.left = self.left;
|
|
||||||
}
|
|
||||||
if ((gravity & RIGHT) == RIGHT) {
|
|
||||||
child.right = self.right;
|
|
||||||
}
|
|
||||||
if ((gravity & TOP) == TOP) {
|
|
||||||
child.top = self.top;
|
|
||||||
}
|
|
||||||
if ((gravity & BOTTOM) == BOTTOM) {
|
|
||||||
child.bottom = self.bottom;
|
|
||||||
}
|
|
||||||
if ((gravity & CENTER_X) == CENTER_X) {
|
|
||||||
child.centerX = self.centerX;
|
|
||||||
}
|
|
||||||
if ((gravity & CENTER_Y) == CENTER_Y) {
|
|
||||||
child.centerY = self.centerY;
|
|
||||||
}
|
|
||||||
[child layoutByParent:self];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
@end
|
||||||
|
@ -37,7 +37,7 @@ - (void)blendView:(UILabel *)view forPropName:(NSString *)name propValue:(id)pro
|
|||||||
} else if ([name isEqualToString:@"textColor"]) {
|
} else if ([name isEqualToString:@"textColor"]) {
|
||||||
view.textColor = DoricColor(prop);
|
view.textColor = DoricColor(prop);
|
||||||
} else if ([name isEqualToString:@"textAlignment"]) {
|
} else if ([name isEqualToString:@"textAlignment"]) {
|
||||||
DoricGravity gravity = [(NSNumber *) prop integerValue];
|
DoricGravity gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||||
NSTextAlignment alignment = NSTextAlignmentCenter;
|
NSTextAlignment alignment = NSTextAlignmentCenter;
|
||||||
switch (gravity) {
|
switch (gravity) {
|
||||||
case LEFT:
|
case LEFT:
|
||||||
@ -54,12 +54,4 @@ - (void)blendView:(UILabel *)view forPropName:(NSString *)name propValue:(id)pro
|
|||||||
[super blendView:view forPropName:name propValue:prop];
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent {
|
|
||||||
DoricLayoutDesc widthSpec = self.layoutParams.width;
|
|
||||||
DoricLayoutDesc heightSpec = self.layoutParams.height;
|
|
||||||
if (widthSpec == LAYOUT_WRAP_CONTENT || heightSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
[self.view sizeToFit];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
@end
|
||||||
|
@ -22,11 +22,5 @@
|
|||||||
|
|
||||||
#import "DoricGroupNode.h"
|
#import "DoricGroupNode.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
@interface DoricVLayoutNode : DoricGroupNode<DoricVLayoutView *, DoricLinearConfig *>
|
||||||
|
|
||||||
@interface DoricVLayoutNode : DoricGroupNode<UIView *, VHLayoutParams *>
|
|
||||||
@property(nonatomic) CGFloat space;
|
|
||||||
@property(nonatomic) DoricGravity gravity;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
|
@ -24,19 +24,16 @@
|
|||||||
#import "DoricUtil.h"
|
#import "DoricUtil.h"
|
||||||
|
|
||||||
@implementation DoricVLayoutNode
|
@implementation DoricVLayoutNode
|
||||||
- (instancetype)init {
|
|
||||||
if (self = [super init]) {
|
- (DoricVLayoutView *)build:(NSDictionary *)props {
|
||||||
_space = 0;
|
return [DoricVLayoutView new];
|
||||||
_gravity = 0;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)blendView:(id)view forPropName:(NSString *)name propValue:(id)prop {
|
- (void)blendView:(DoricVLayoutView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||||
if ([name isEqualToString:@"gravity"]) {
|
if ([name isEqualToString:@"gravity"]) {
|
||||||
self.gravity = [(NSNumber *) prop integerValue];
|
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||||
} else if ([name isEqualToString:@"space"]) {
|
} else if ([name isEqualToString:@"space"]) {
|
||||||
self.space = [(NSNumber *) prop floatValue];
|
view.space = [(NSNumber *) prop floatValue];
|
||||||
} else {
|
} else {
|
||||||
[super blendView:view forPropName:name propValue:prop];
|
[super blendView:view forPropName:name propValue:prop];
|
||||||
}
|
}
|
||||||
@ -44,92 +41,26 @@ - (void)blendView:(id)view forPropName:(NSString *)name propValue:(id)prop {
|
|||||||
|
|
||||||
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutconfig {
|
- (void)blendChild:(DoricViewNode *)child layoutConfig:(NSDictionary *)layoutconfig {
|
||||||
[super blendChild:child layoutConfig:layoutconfig];
|
[super blendChild:child layoutConfig:layoutconfig];
|
||||||
if (![child.layoutParams isKindOfClass:VHLayoutParams.class]) {
|
if (![child.layoutConfig isKindOfClass:DoricLinearConfig.class]) {
|
||||||
DoricLog(@"blend VLayout child error,layout params not match");
|
DoricLog(@"blend DoricVLayoutView child error,layout params not match");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VHLayoutParams *params = (VHLayoutParams *) child.layoutParams;
|
DoricLinearConfig *params = (DoricLinearConfig *) child.layoutConfig;
|
||||||
NSDictionary *margin = layoutconfig[@"margin"];
|
NSDictionary *margin = layoutconfig[@"margin"];
|
||||||
if (margin) {
|
if (margin) {
|
||||||
params.margin.top = [(NSNumber *) margin[@"top"] floatValue];
|
params.margin = DoricMarginMake(
|
||||||
params.margin.left = [(NSNumber *) margin[@"left"] floatValue];
|
[(NSNumber *) margin[@"left"] floatValue],
|
||||||
params.margin.right = [(NSNumber *) margin[@"right"] floatValue];
|
[(NSNumber *) margin[@"top"] floatValue],
|
||||||
params.margin.bottom = [(NSNumber *) margin[@"bottom"] floatValue];
|
[(NSNumber *) margin[@"right"] floatValue],
|
||||||
|
[(NSNumber *) margin[@"bottom"] floatValue]);
|
||||||
}
|
}
|
||||||
NSNumber *alignment = layoutconfig[@"alignment"];
|
NSNumber *alignment = layoutconfig[@"alignment"];
|
||||||
if (alignment) {
|
if (alignment) {
|
||||||
params.alignment = [alignment integerValue];
|
params.alignment = (DoricGravity) [alignment integerValue];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (LayoutParams *)generateDefaultLayoutParams {
|
- (DoricLinearConfig *)generateDefaultLayoutParams {
|
||||||
return [[VHLayoutParams alloc] init];
|
return [[DoricLinearConfig alloc] init];
|
||||||
}
|
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent {
|
|
||||||
DoricLayoutDesc widthSpec = self.layoutParams.width;
|
|
||||||
DoricLayoutDesc heightSpec = self.layoutParams.height;
|
|
||||||
CGFloat maxWidth = 0, maxHeight = 0;
|
|
||||||
for (DoricViewNode *child in self.indexedChildren) {
|
|
||||||
[child measureByParent:self];
|
|
||||||
CGFloat placeWidth = child.measuredWidth;
|
|
||||||
CGFloat placeHeight = child.measuredHeight;
|
|
||||||
maxWidth = MAX(maxWidth, placeWidth);
|
|
||||||
maxHeight += placeHeight + self.space;
|
|
||||||
}
|
|
||||||
maxHeight -= self.space;
|
|
||||||
|
|
||||||
self.desiredWidth = maxWidth;
|
|
||||||
self.desiredHeight = maxHeight;
|
|
||||||
|
|
||||||
if (widthSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
self.width = maxWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heightSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
self.height = maxHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutByParent:(DoricGroupNode *)parent {
|
|
||||||
if (self.layoutParams.width == LAYOUT_MATCH_PARENT) {
|
|
||||||
self.width = parent.width;
|
|
||||||
}
|
|
||||||
if (self.layoutParams.height == LAYOUT_MATCH_PARENT) {
|
|
||||||
self.height = parent.height;
|
|
||||||
}
|
|
||||||
// layout child
|
|
||||||
CGFloat yStart = 0;
|
|
||||||
if ((self.gravity & TOP) == TOP) {
|
|
||||||
yStart = 0;
|
|
||||||
} else if ((self.gravity & BOTTOM) == BOTTOM) {
|
|
||||||
yStart = self.height - self.desiredHeight;
|
|
||||||
} else if ((self.gravity & CENTER_Y) == CENTER_Y) {
|
|
||||||
yStart = (self.height - self.desiredHeight) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (DoricViewNode *child in self.indexedChildren) {
|
|
||||||
if (child.layoutParams.width == LAYOUT_MATCH_PARENT) {
|
|
||||||
child.width = self.width;
|
|
||||||
}
|
|
||||||
if (child.layoutParams.height == LAYOUT_MATCH_PARENT) {
|
|
||||||
child.height = self.height;
|
|
||||||
}
|
|
||||||
if ([child.layoutParams isKindOfClass:VHLayoutParams.class]) {
|
|
||||||
VHLayoutParams *layoutParams = (VHLayoutParams *) child.layoutParams;
|
|
||||||
DoricGravity gravity = layoutParams.alignment | self.gravity;
|
|
||||||
if ((gravity & LEFT) == LEFT) {
|
|
||||||
child.left = 0;
|
|
||||||
} else if ((gravity & RIGHT) == RIGHT) {
|
|
||||||
child.right = self.width;
|
|
||||||
} else if ((gravity & CENTER_X) == CENTER_X) {
|
|
||||||
child.centerX = self.width / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
child.top = yStart;
|
|
||||||
yStart = child.bottom + self.space;
|
|
||||||
[child layoutByParent:self];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
//
|
|
||||||
// DoricViewContainer.h
|
|
||||||
// Doric
|
|
||||||
//
|
|
||||||
// Created by pengfei.zhou on 2019/7/30.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "UIView+Doric.h"
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, DoricGravity) {
|
|
||||||
SPECIFIED = 1,
|
|
||||||
START = 1 << 1,
|
|
||||||
END = 1 << 2,
|
|
||||||
SHIFT_X = 0,
|
|
||||||
SHIFT_Y = 4,
|
|
||||||
LEFT = (START | SPECIFIED) << SHIFT_X,
|
|
||||||
RIGHT = (END | SPECIFIED) << SHIFT_X,
|
|
||||||
TOP = (START | SPECIFIED) << SHIFT_Y,
|
|
||||||
BOTTOM = (END | SPECIFIED) << SHIFT_Y,
|
|
||||||
CENTER_X = SPECIFIED << SHIFT_X,
|
|
||||||
CENTER_Y = SPECIFIED << SHIFT_Y,
|
|
||||||
CENTER = CENTER_X | CENTER_Y,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, DoricLayoutDesc) {
|
|
||||||
LAYOUT_ABSOLUTE = 0,
|
|
||||||
LAYOUT_MATCH_PARENT = -1,
|
|
||||||
LAYOUT_WRAP_CONTENT = -2,
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface DoricRect : NSObject
|
|
||||||
@property(nonatomic) CGFloat left;
|
|
||||||
@property(nonatomic) CGFloat right;
|
|
||||||
@property(nonatomic) CGFloat top;
|
|
||||||
@property(nonatomic) CGFloat bottom;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@interface LayoutParams : NSObject
|
|
||||||
@property(nonatomic) DoricLayoutDesc width;
|
|
||||||
@property(nonatomic) DoricLayoutDesc height;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface MarginLayoutParams : LayoutParams
|
|
||||||
@property(nonatomic, strong) DoricRect *margin;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface StackLayoutParams : LayoutParams
|
|
||||||
@property(nonatomic) DoricGravity alignment;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface VHLayoutParams : MarginLayoutParams
|
|
||||||
@property(nonatomic) DoricGravity alignment;
|
|
||||||
@property(nonatomic) NSInteger weight;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@interface UIView (DoricContainer)
|
|
||||||
|
|
||||||
@property(nonatomic, strong) LayoutParams *layoutParams;
|
|
||||||
|
|
||||||
- (void)layout;
|
|
||||||
|
|
||||||
- (void)measure;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface Stack : UIView
|
|
||||||
@property(nonatomic) DoricGravity gravity;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface LinearLayout : UIView
|
|
||||||
@property(nonatomic) DoricGravity gravity;
|
|
||||||
@property(nonatomic) CGFloat space;
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@interface VLayout : LinearLayout
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface HLayout : LinearLayout
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
//
|
|
||||||
// DoricViewContainer.m
|
|
||||||
// Doric
|
|
||||||
//
|
|
||||||
// Created by pengfei.zhou on 2019/7/30.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "DoricViewContainer.h"
|
|
||||||
#import <objc/runtime.h>
|
|
||||||
|
|
||||||
@implementation DoricRect
|
|
||||||
- (instancetype)init {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_left = 0;
|
|
||||||
_right = 0;
|
|
||||||
_top = 0;
|
|
||||||
_bottom = 0;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation LayoutParams
|
|
||||||
- (instancetype)init {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_width = LAYOUT_WRAP_CONTENT;
|
|
||||||
_height = LAYOUT_WRAP_CONTENT;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MarginLayoutParams
|
|
||||||
- (instancetype)init {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_margin = [[DoricRect alloc] init];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation StackLayoutParams
|
|
||||||
- (instancetype)init {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_alignment = 0;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation VHLayoutParams
|
|
||||||
- (instancetype)init {
|
|
||||||
if (self = [super init]) {
|
|
||||||
_alignment = 0;
|
|
||||||
_weight = 0;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@implementation UIView (DoricContainer)
|
|
||||||
|
|
||||||
- (LayoutParams *)layoutParams {
|
|
||||||
return objc_getAssociatedObject(self, _cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLayoutParams:(LayoutParams *)layoutParams {
|
|
||||||
objc_setAssociatedObject(self, @selector(layoutParams), layoutParams, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layout {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)measure {
|
|
||||||
if (self.layoutParams) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Stack
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation LinearLayout
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation VLayout
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation HLayout
|
|
||||||
@end
|
|
@ -21,8 +21,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "DoricContextHolder.h"
|
#import "DoricContextHolder.h"
|
||||||
#import "DoricViewContainer.h"
|
#import "DoricLayouts.h"
|
||||||
|
|
||||||
#import "UIView+Doric.h"
|
#import "UIView+Doric.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
@ -37,24 +36,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
@property(nonatomic, strong) NSString *viewId;
|
@property(nonatomic, strong) NSString *viewId;
|
||||||
|
|
||||||
@property(nonatomic, strong) LayoutParams *layoutParams;
|
@property(nonatomic, strong) DoricLayoutConfig *layoutConfig;
|
||||||
|
|
||||||
@property(nonatomic, strong, readonly) NSArray<NSString *> *idList;
|
@property(nonatomic, strong, readonly) NSArray<NSString *> *idList;
|
||||||
|
|
||||||
|
|
||||||
@property(nonatomic) CGFloat x;
|
|
||||||
@property(nonatomic) CGFloat y;
|
|
||||||
@property(nonatomic) CGFloat width;
|
|
||||||
@property(nonatomic) CGFloat height;
|
|
||||||
@property(nonatomic) CGFloat centerX;
|
|
||||||
@property(nonatomic) CGFloat centerY;
|
|
||||||
@property(nonatomic) CGFloat top;
|
|
||||||
@property(nonatomic) CGFloat left;
|
|
||||||
@property(nonatomic) CGFloat right;
|
|
||||||
@property(nonatomic) CGFloat bottom;
|
|
||||||
@property(nonatomic, readonly) CGFloat measuredWidth;
|
|
||||||
@property(nonatomic, readonly) CGFloat measuredHeight;
|
|
||||||
|
|
||||||
- (V)build:(NSDictionary *)props;
|
- (V)build:(NSDictionary *)props;
|
||||||
|
|
||||||
- (void)blend:(NSDictionary *)props;
|
- (void)blend:(NSDictionary *)props;
|
||||||
@ -63,10 +48,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
|
|
||||||
- (void)callJSResponse:(NSString *)funcId, ...;
|
- (void)callJSResponse:(NSString *)funcId, ...;
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent;
|
|
||||||
|
|
||||||
- (void)layoutByParent:(DoricGroupNode *)parent;
|
|
||||||
|
|
||||||
+ (DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type;
|
+ (DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type;
|
||||||
|
|
||||||
- (void)requestLayout;
|
- (void)requestLayout;
|
||||||
|
@ -85,6 +85,7 @@ - (void)blend:(NSDictionary *)props {
|
|||||||
if (self.view == nil) {
|
if (self.view == nil) {
|
||||||
self.view = [self build:props];
|
self.view = [self build:props];
|
||||||
}
|
}
|
||||||
|
self.view.layoutConfig = self.layoutConfig;
|
||||||
for (NSString *key in props) {
|
for (NSString *key in props) {
|
||||||
id value = props[key];
|
id value = props[key];
|
||||||
[self blendView:self.view forPropName:key propValue:value];
|
[self blendView:self.view forPropName:key propValue:value];
|
||||||
@ -94,18 +95,12 @@ - (void)blend:(NSDictionary *)props {
|
|||||||
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||||
if ([name isEqualToString:@"width"]) {
|
if ([name isEqualToString:@"width"]) {
|
||||||
NSNumber *width = (NSNumber *) prop;
|
NSNumber *width = (NSNumber *) prop;
|
||||||
if ([width integerValue] < 0) {
|
if ([width floatValue] >= 0) {
|
||||||
self.layoutParams.width = [width integerValue];
|
|
||||||
} else {
|
|
||||||
self.layoutParams.width = LAYOUT_ABSOLUTE;
|
|
||||||
view.width = [width floatValue];
|
view.width = [width floatValue];
|
||||||
}
|
}
|
||||||
} else if ([name isEqualToString:@"height"]) {
|
} else if ([name isEqualToString:@"height"]) {
|
||||||
NSNumber *height = (NSNumber *) prop;
|
NSNumber *height = (NSNumber *) prop;
|
||||||
if ([height integerValue] < 0) {
|
if ([height floatValue] >= 0) {
|
||||||
self.layoutParams.height = [height integerValue];
|
|
||||||
} else {
|
|
||||||
self.layoutParams.height = LAYOUT_ABSOLUTE;
|
|
||||||
view.height = [height floatValue];
|
view.height = [height floatValue];
|
||||||
}
|
}
|
||||||
} else if ([name isEqualToString:@"x"]) {
|
} else if ([name isEqualToString:@"x"]) {
|
||||||
@ -119,14 +114,14 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
[self.parent blendChild:self layoutConfig:prop];
|
[self.parent blendChild:self layoutConfig:prop];
|
||||||
}
|
}
|
||||||
} else if ([name isEqualToString:@"onClick"]) {
|
} else if ([name isEqualToString:@"onClick"]) {
|
||||||
[self.callbackIds setObject:prop forKey:@"onClick"];
|
self.callbackIds[@"onClick"] = prop;
|
||||||
view.userInteractionEnabled = YES;
|
view.userInteractionEnabled = YES;
|
||||||
UITapGestureRecognizer *tapGesturRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClick:)];
|
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClick:)];
|
||||||
[view addGestureRecognizer:tapGesturRecognizer];
|
[view addGestureRecognizer:tapGestureRecognizer];
|
||||||
} else if ([name isEqualToString:@"border"]) {
|
} else if ([name isEqualToString:@"border"]) {
|
||||||
NSDictionary *dic = prop;
|
NSDictionary *dic = prop;
|
||||||
CGFloat width = [(NSNumber *) [dic objectForKey:@"width"] floatValue];
|
CGFloat width = [(NSNumber *) dic[@"width"] floatValue];
|
||||||
UIColor *color = DoricColor((NSNumber *) [dic objectForKey:@"color"]);
|
UIColor *color = DoricColor((NSNumber *) dic[@"color"]);
|
||||||
view.layer.borderWidth = width;
|
view.layer.borderWidth = width;
|
||||||
view.layer.borderColor = color.CGColor;
|
view.layer.borderColor = color.CGColor;
|
||||||
} else if ([name isEqualToString:@"corners"]) {
|
} else if ([name isEqualToString:@"corners"]) {
|
||||||
@ -134,10 +129,10 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
view.layer.cornerRadius = [(NSNumber *) prop floatValue];
|
view.layer.cornerRadius = [(NSNumber *) prop floatValue];
|
||||||
} else if ([prop isKindOfClass:NSDictionary.class]) {
|
} else if ([prop isKindOfClass:NSDictionary.class]) {
|
||||||
NSDictionary *dic = prop;
|
NSDictionary *dic = prop;
|
||||||
CGFloat leftTop = [(NSNumber *) [dic objectForKey:@"leftTop"] floatValue];
|
CGFloat leftTop = [(NSNumber *) dic[@"leftTop"] floatValue];
|
||||||
CGFloat rightTop = [(NSNumber *) [dic objectForKey:@"rightTop"] floatValue];
|
CGFloat rightTop = [(NSNumber *) dic[@"rightTop"] floatValue];
|
||||||
CGFloat rightBottom = [(NSNumber *) [dic objectForKey:@"rightBottom"] floatValue];
|
CGFloat rightBottom = [(NSNumber *) dic[@"rightBottom"] floatValue];
|
||||||
CGFloat leftBottom = [(NSNumber *) [dic objectForKey:@"leftBottom"] floatValue];
|
CGFloat leftBottom = [(NSNumber *) dic[@"leftBottom"] floatValue];
|
||||||
CALayer *mask = nil;
|
CALayer *mask = nil;
|
||||||
if (ABS(leftTop - rightTop) > CGFLOAT_MIN
|
if (ABS(leftTop - rightTop) > CGFLOAT_MIN
|
||||||
|| ABS(leftTop - rightBottom) > CGFLOAT_MIN
|
|| ABS(leftTop - rightBottom) > CGFLOAT_MIN
|
||||||
@ -155,14 +150,14 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
}
|
}
|
||||||
} else if ([name isEqualToString:@"shadow"]) {
|
} else if ([name isEqualToString:@"shadow"]) {
|
||||||
NSDictionary *dic = prop;
|
NSDictionary *dic = prop;
|
||||||
CGFloat opacity = [(NSNumber *) [dic objectForKey:@"opacity"] floatValue];
|
CGFloat opacity = [(NSNumber *) dic[@"opacity"] floatValue];
|
||||||
if (opacity > CGFLOAT_MIN) {
|
if (opacity > CGFLOAT_MIN) {
|
||||||
view.clipsToBounds = NO;
|
view.clipsToBounds = NO;
|
||||||
UIColor *color = DoricColor((NSNumber *) [dic objectForKey:@"color"]);
|
UIColor *color = DoricColor((NSNumber *) dic[@"color"]);
|
||||||
view.layer.shadowColor = color.CGColor;
|
view.layer.shadowColor = color.CGColor;
|
||||||
view.layer.shadowRadius = [(NSNumber *) [dic objectForKey:@"radius"] floatValue];
|
view.layer.shadowRadius = [(NSNumber *) dic[@"radius"] floatValue];
|
||||||
view.layer.shadowOffset = CGSizeMake([(NSNumber *) [dic objectForKey:@"offsetX"] floatValue], [(NSNumber *) [dic objectForKey:@"offsetY"] floatValue]);
|
view.layer.shadowOffset = CGSizeMake([(NSNumber *) dic[@"offsetX"] floatValue], [(NSNumber *) dic[@"offsetY"] floatValue]);
|
||||||
view.layer.shadowOpacity = opacity;
|
view.layer.shadowOpacity = (float) opacity;
|
||||||
} else {
|
} else {
|
||||||
view.clipsToBounds = YES;
|
view.clipsToBounds = YES;
|
||||||
}
|
}
|
||||||
@ -173,35 +168,7 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)onClick:(UIView *)view {
|
- (void)onClick:(UIView *)view {
|
||||||
[self callJSResponse:[self.callbackIds objectForKey:@"onClick"], nil];
|
[self callJSResponse:self.callbackIds[@"onClick"], nil];
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)measuredWidth {
|
|
||||||
if ([self.layoutParams isKindOfClass:MarginLayoutParams.class]) {
|
|
||||||
MarginLayoutParams *marginParams = (MarginLayoutParams *) self.layoutParams;
|
|
||||||
return self.width + marginParams.margin.left + marginParams.margin.right;
|
|
||||||
}
|
|
||||||
return self.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)measuredHeight {
|
|
||||||
if ([self.layoutParams isKindOfClass:MarginLayoutParams.class]) {
|
|
||||||
MarginLayoutParams *marginParams = (MarginLayoutParams *) self.layoutParams;
|
|
||||||
return self.height + marginParams.margin.top + marginParams.margin.bottom;
|
|
||||||
}
|
|
||||||
return self.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)measureByParent:(DoricGroupNode *)parent {
|
|
||||||
DoricLayoutDesc widthSpec = self.layoutParams.width;
|
|
||||||
DoricLayoutDesc heightSpec = self.layoutParams.height;
|
|
||||||
if (widthSpec == LAYOUT_WRAP_CONTENT || heightSpec == LAYOUT_WRAP_CONTENT) {
|
|
||||||
[self.view sizeToFit];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)layoutByParent:(DoricGroupNode *)parent {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray<NSString *> *)idList {
|
- (NSArray<NSString *> *)idList {
|
||||||
@ -232,87 +199,7 @@ - (void)callJSResponse:(NSString *)funcId, ... {
|
|||||||
+ (DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type {
|
+ (DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type {
|
||||||
DoricRegistry *registry = context.driver.registry;
|
DoricRegistry *registry = context.driver.registry;
|
||||||
Class clz = [registry acquireViewNode:type];
|
Class clz = [registry acquireViewNode:type];
|
||||||
return [[clz alloc] initWithContext:context];
|
return [(DoricViewNode *) [clz alloc] initWithContext:context];
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)x {
|
|
||||||
return ((UIView *) self.view).x;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)y {
|
|
||||||
return ((UIView *) self.view).y;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)width {
|
|
||||||
return ((UIView *) self.view).width;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)height {
|
|
||||||
return ((UIView *) self.view).height;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)top {
|
|
||||||
return ((UIView *) self.view).top;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)bottom {
|
|
||||||
return ((UIView *) self.view).bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)left {
|
|
||||||
return ((UIView *) self.view).left;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)right {
|
|
||||||
return ((UIView *) self.view).right;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)centerX {
|
|
||||||
return ((UIView *) self.view).centerX;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGFloat)centerY {
|
|
||||||
return ((UIView *) self.view).centerY;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setX:(CGFloat)x {
|
|
||||||
((UIView *) self.view).x = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setY:(CGFloat)y {
|
|
||||||
((UIView *) self.view).y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setWidth:(CGFloat)width {
|
|
||||||
((UIView *) self.view).width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setHeight:(CGFloat)height {
|
|
||||||
((UIView *) self.view).height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setLeft:(CGFloat)left {
|
|
||||||
((UIView *) self.view).left = left;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRight:(CGFloat)right {
|
|
||||||
((UIView *) self.view).right = right;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setTop:(CGFloat)top {
|
|
||||||
((UIView *) self.view).top = top;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setBottom:(CGFloat)bottom {
|
|
||||||
((UIView *) self.view).bottom = bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setCenterX:(CGFloat)centerX {
|
|
||||||
((UIView *) self.view).centerX = centerX;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setCenterY:(CGFloat)centerY {
|
|
||||||
((UIView *) self.view).centerY = centerY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)requestLayout {
|
- (void)requestLayout {
|
||||||
|
29
iOS/Pod/Classes/Util/DoricExtensions.h
Normal file
29
iOS/Pod/Classes/Util/DoricExtensions.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
|
||||||
|
@interface NSObject (Doric)
|
||||||
|
- (id)apply:(id (^)(id it))block;
|
||||||
|
|
||||||
|
- (instancetype)also:(void (^)(id it))block;
|
||||||
|
|
||||||
|
- (void)let:(void (^)(id it))block;
|
||||||
|
@end
|
35
iOS/Pod/Classes/Util/DoricExtensions.m
Normal file
35
iOS/Pod/Classes/Util/DoricExtensions.m
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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/10/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "DoricExtensions.h"
|
||||||
|
|
||||||
|
@implementation NSObject (Doric)
|
||||||
|
- (id)apply:(id (^)(id it))block {
|
||||||
|
return block(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)also:(void (^)(id it))block {
|
||||||
|
block(self);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)let:(void (^)(id it))block {
|
||||||
|
block(self);
|
||||||
|
}
|
||||||
|
@end
|
@ -98,8 +98,8 @@ export abstract class Panel {
|
|||||||
|
|
||||||
private retrospectView(ids: string[]): View {
|
private retrospectView(ids: string[]): View {
|
||||||
return ids.reduce((acc: View, cur) => {
|
return ids.reduce((acc: View, cur) => {
|
||||||
if (acc instanceof Group) {
|
if (Reflect.has(acc, "subViewById")) {
|
||||||
return acc.children.filter(e => e.viewId === cur)[0]
|
return Reflect.apply(Reflect.get(acc, "subViewById"), acc, [cur])
|
||||||
}
|
}
|
||||||
return acc
|
return acc
|
||||||
}, this.__root__)
|
}, this.__root__)
|
||||||
|
@ -19,9 +19,25 @@ import { uniqueId } from "../util/uniqueId";
|
|||||||
import { Gravity } from "../util/gravity";
|
import { Gravity } from "../util/gravity";
|
||||||
import { loge } from "../util/log";
|
import { loge } from "../util/log";
|
||||||
|
|
||||||
export const MATCH_PARENT = -1
|
export enum LayoutSpec {
|
||||||
|
EXACTLY = 0,
|
||||||
|
WRAP_CONTENT = 1,
|
||||||
|
AT_MOST = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayoutConfig {
|
||||||
|
widthSpec?: LayoutSpec
|
||||||
|
heightSpec?: LayoutSpec
|
||||||
|
margin?: {
|
||||||
|
left?: number,
|
||||||
|
right?: number,
|
||||||
|
top?: number,
|
||||||
|
bottom?: number,
|
||||||
|
}
|
||||||
|
alignment?: Gravity
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const WRAP_CONTENT = -2
|
|
||||||
|
|
||||||
export function Property(target: Object, propKey: string) {
|
export function Property(target: Object, propKey: string) {
|
||||||
Reflect.defineMetadata(propKey, true, target)
|
Reflect.defineMetadata(propKey, true, target)
|
||||||
@ -29,10 +45,10 @@ export function Property(target: Object, propKey: string) {
|
|||||||
|
|
||||||
export abstract class View implements Modeling {
|
export abstract class View implements Modeling {
|
||||||
@Property
|
@Property
|
||||||
width: number = WRAP_CONTENT
|
width: number = 0
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
height: number = WRAP_CONTENT
|
height: number = 0
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
x: number = 0
|
x: number = 0
|
||||||
@ -61,6 +77,26 @@ export abstract class View implements Modeling {
|
|||||||
@Property
|
@Property
|
||||||
viewId = uniqueId('ViewId')
|
viewId = uniqueId('ViewId')
|
||||||
|
|
||||||
|
@Property
|
||||||
|
padding?: {
|
||||||
|
left?: number,
|
||||||
|
right?: number,
|
||||||
|
top?: number,
|
||||||
|
bottom?: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
layoutConfig?: LayoutConfig
|
||||||
|
|
||||||
|
@Property
|
||||||
|
onClick?: Function
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to reuse native view
|
||||||
|
*/
|
||||||
|
@Property
|
||||||
|
identifier?: string
|
||||||
|
|
||||||
parent?: Group
|
parent?: Group
|
||||||
|
|
||||||
callbacks: Map<String, Function> = new Map
|
callbacks: Map<String, Function> = new Map
|
||||||
@ -187,42 +223,28 @@ export abstract class View implements Modeling {
|
|||||||
toModel() {
|
toModel() {
|
||||||
return this.nativeViewModel
|
return this.nativeViewModel
|
||||||
}
|
}
|
||||||
|
let(block: (it: this) => void) {
|
||||||
@Property
|
block(this)
|
||||||
padding?: {
|
|
||||||
left?: number,
|
|
||||||
right?: number,
|
|
||||||
top?: number,
|
|
||||||
bottom?: number,
|
|
||||||
}
|
}
|
||||||
|
also(block: (it: this) => void) {
|
||||||
@Property
|
block(this)
|
||||||
layoutConfig?: Config
|
return this
|
||||||
|
|
||||||
@Property
|
|
||||||
onClick?: Function
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Config {
|
|
||||||
margin?: {
|
|
||||||
left?: number,
|
|
||||||
right?: number,
|
|
||||||
top?: number,
|
|
||||||
bottom?: number,
|
|
||||||
}
|
}
|
||||||
alignment?: Gravity
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StackConfig extends Config {
|
export interface StackConfig extends LayoutConfig {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LinearConfig extends Config {
|
export interface LinearConfig extends LayoutConfig {
|
||||||
weight?: number
|
weight?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class Group extends View {
|
export interface SuperView {
|
||||||
|
subViewById(id: string): View | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class Group extends View implements SuperView {
|
||||||
@Property
|
@Property
|
||||||
readonly children: View[] = new Proxy([], {
|
readonly children: View[] = new Proxy([], {
|
||||||
set: (target, index, value) => {
|
set: (target, index, value) => {
|
||||||
@ -243,6 +265,14 @@ export abstract class Group extends View {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
subViewById(id: string): View | undefined {
|
||||||
|
for (let view of this.children) {
|
||||||
|
if (view.viewId === id) {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
addChild(view: View) {
|
addChild(view: View) {
|
||||||
this.children.push(view)
|
this.children.push(view)
|
||||||
}
|
}
|
||||||
@ -283,6 +313,16 @@ export class Stack extends Group {
|
|||||||
@Property
|
@Property
|
||||||
gravity?: Gravity
|
gravity?: Gravity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Scroller extends View implements SuperView {
|
||||||
|
@Property
|
||||||
|
contentView?: View
|
||||||
|
|
||||||
|
subViewById(id: string): View | undefined {
|
||||||
|
return this.contentView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Root extends Stack {
|
export class Root extends Stack {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -322,31 +362,107 @@ export class Image extends View {
|
|||||||
imageUrl?: string
|
imageUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class List extends View {
|
export class List extends View implements SuperView {
|
||||||
|
private cachedViews: Map<string, View> = new Map
|
||||||
|
|
||||||
}
|
subViewById(id: string): View | undefined {
|
||||||
|
return this.cachedViews.get(id)
|
||||||
export class Slide extends View {
|
}
|
||||||
|
|
||||||
}
|
@Property
|
||||||
|
itemCount = 0
|
||||||
export function stack() {
|
|
||||||
|
@Property
|
||||||
}
|
renderItem!: (index: number) => View
|
||||||
|
|
||||||
export function vlayout(providers: Array<() => View>, config: {
|
|
||||||
width: number
|
private getItem(itemIdx: number) {
|
||||||
height: number
|
let view = this.cachedViews.get(`${itemIdx}`)
|
||||||
space?: number
|
if (view === undefined) {
|
||||||
}) {
|
view = this.renderItem(itemIdx)
|
||||||
const vlayout = new VLayout
|
this.cachedViews.set(`${itemIdx}`, view)
|
||||||
vlayout.width = config.width
|
}
|
||||||
vlayout.height = config.height
|
return view
|
||||||
if (config.space !== undefined) {
|
}
|
||||||
vlayout.space = config.space
|
|
||||||
|
@Property
|
||||||
|
private renderBunchedItems(items: number[]): View[] {
|
||||||
|
return items.map(e => this.getItem(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SectionList extends View implements SuperView {
|
||||||
|
private cachedViews: Map<string, View> = new Map
|
||||||
|
|
||||||
|
subViewById(id: string): View | undefined {
|
||||||
|
return this.cachedViews.get(id)
|
||||||
|
}
|
||||||
|
@Property
|
||||||
|
sectionRowsCount: number[] = []
|
||||||
|
|
||||||
|
@Property
|
||||||
|
renderSectionHeader!: (sectionIdx: number) => View
|
||||||
|
|
||||||
|
@Property
|
||||||
|
renderItem!: (sectionIdx: number, itemIdx: number) => View
|
||||||
|
|
||||||
|
@Property
|
||||||
|
sectionHeaderSticky = true
|
||||||
|
|
||||||
|
setupSectionRows(sectionCount: number, numberOfSection: (section: number) => number) {
|
||||||
|
this.sectionRowsCount = [...Array(sectionCount).keys()].map(e => numberOfSection(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
private getItem(sectionIdx: number, itemIdx: number) {
|
||||||
|
let view = this.cachedViews.get(`${sectionIdx}:${itemIdx}`)
|
||||||
|
if (view === undefined) {
|
||||||
|
view = this.renderItem(sectionIdx, itemIdx)
|
||||||
|
this.cachedViews.set(`${sectionIdx}:${itemIdx}`, view)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSectionHeader(sectionIdx: number) {
|
||||||
|
let view = this.cachedViews.get(`${sectionIdx}:`)
|
||||||
|
if (view === undefined) {
|
||||||
|
view = this.renderSectionHeader(sectionIdx)
|
||||||
|
this.cachedViews.set(`${sectionIdx}:`, view)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
private renderBunchedItems(items: Array<{ itemIdx: number, sectionIdx: number }>,
|
||||||
|
headers: number[]): { items: View[], headers: View[] } {
|
||||||
|
return {
|
||||||
|
items: items.map(e => this.getItem(e.sectionIdx, e.itemIdx)),
|
||||||
|
headers: headers.map(e => this.getSectionHeader(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Slide extends View implements SuperView {
|
||||||
|
@Property
|
||||||
|
pageCount = 0
|
||||||
|
|
||||||
|
@Property
|
||||||
|
renderPage!: (pageIdx: number) => View
|
||||||
|
|
||||||
|
private cachedViews: Map<string, View> = new Map
|
||||||
|
subViewById(id: string): View | undefined {
|
||||||
|
return this.cachedViews.get(id)
|
||||||
|
}
|
||||||
|
private getPage(pageIdx: number) {
|
||||||
|
let view = this.cachedViews.get(`${pageIdx}`)
|
||||||
|
if (view === undefined) {
|
||||||
|
view = this.renderPage(pageIdx)
|
||||||
|
this.cachedViews.set(`${pageIdx}`, view)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Property
|
||||||
|
private renderBunchedPages(pages: number[]): View[] {
|
||||||
|
return pages.map(e => this.getPage(e))
|
||||||
}
|
}
|
||||||
providers.forEach(e => {
|
|
||||||
vlayout.addChild(e())
|
|
||||||
})
|
|
||||||
return vlayout
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user