Merge branch 'feature/listview' into 'master'
Feature/listview See merge request !1
This commit is contained in:
		@@ -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