add vh layout

This commit is contained in:
pengfei.zhou 2019-07-24 10:14:17 +08:00
parent 341692f319
commit 9592e9ed3d
13 changed files with 300 additions and 39 deletions

View File

@ -3,10 +3,12 @@ package com.github.penfeizhou.doric;
import android.text.TextUtils; import android.text.TextUtils;
import com.github.penfeizhou.doric.plugin.ShaderPlugin; import com.github.penfeizhou.doric.plugin.ShaderPlugin;
import com.github.penfeizhou.doric.shader.HLayoutNode;
import com.github.penfeizhou.doric.shader.ImageNode; import com.github.penfeizhou.doric.shader.ImageNode;
import com.github.penfeizhou.doric.shader.RootNode; import com.github.penfeizhou.doric.shader.RootNode;
import com.github.penfeizhou.doric.shader.StackNode; import com.github.penfeizhou.doric.shader.StackNode;
import com.github.penfeizhou.doric.shader.TextNode; import com.github.penfeizhou.doric.shader.TextNode;
import com.github.penfeizhou.doric.shader.VLayoutNode;
import com.github.penfeizhou.doric.shader.ViewNode; import com.github.penfeizhou.doric.shader.ViewNode;
import com.github.penfeizhou.doric.utils.DoricMetaInfo; import com.github.penfeizhou.doric.utils.DoricMetaInfo;
import com.github.penfeizhou.doric.plugin.DoricJavaPlugin; import com.github.penfeizhou.doric.plugin.DoricJavaPlugin;
@ -47,6 +49,8 @@ public class DoricRegistry {
this.registerViewNode(TextNode.class); this.registerViewNode(TextNode.class);
this.registerViewNode(ImageNode.class); this.registerViewNode(ImageNode.class);
this.registerViewNode(StackNode.class); this.registerViewNode(StackNode.class);
this.registerViewNode(VLayoutNode.class);
this.registerViewNode(HLayoutNode.class);
initRegistry(this); initRegistry(this);
} }

View File

@ -0,0 +1,26 @@
package com.github.penfeizhou.doric.shader;
import android.widget.LinearLayout;
import com.github.penfeizhou.doric.DoricContext;
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
import com.github.pengfeizhou.jscore.JSObject;
/**
* @Description: com.github.penfeizhou.doric.shader
* @Author: pengfei.zhou
* @CreateDate: 2019-07-23
*/
@DoricPlugin(name = "HLayout")
public class HLayoutNode extends LinearNode {
public HLayoutNode(DoricContext doricContext) {
super(doricContext);
}
@Override
public LinearLayout build(JSObject jsObject) {
LinearLayout linearLayout = super.build(jsObject);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
return linearLayout;
}
}

View File

@ -0,0 +1,54 @@
package com.github.penfeizhou.doric.shader;
import android.graphics.drawable.ShapeDrawable;
import android.widget.LinearLayout;
import com.github.penfeizhou.doric.DoricContext;
import com.github.penfeizhou.doric.utils.DoricUtils;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
/**
* @Description: com.github.penfeizhou.doric.shader
* @Author: pengfei.zhou
* @CreateDate: 2019-07-23
*/
public class LinearNode extends GroupNode<LinearLayout> {
public LinearNode(DoricContext doricContext) {
super(doricContext);
}
@Override
public LinearLayout build(JSObject jsObject) {
return new LinearLayout(getContext());
}
@Override
protected void blend(LinearLayout view, String name, JSValue prop) {
switch (name) {
case "space":
ShapeDrawable shapeDrawable;
if (view.getDividerDrawable() == null) {
shapeDrawable = new ShapeDrawable();
shapeDrawable.setAlpha(0);
view.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
} else {
shapeDrawable = (ShapeDrawable) view.getDividerDrawable();
view.setDividerDrawable(null);
}
if (view.getOrientation() == LinearLayout.VERTICAL) {
shapeDrawable.setIntrinsicHeight(DoricUtils.dp2px(prop.asNumber().toFloat()));
} else {
shapeDrawable.setIntrinsicWidth(DoricUtils.dp2px(prop.asNumber().toFloat()));
}
view.setDividerDrawable(shapeDrawable);
break;
case "gravity":
view.setGravity(prop.asNumber().toInt());
break;
default:
super.blend(view, name, prop);
break;
}
}
}

View File

@ -5,6 +5,7 @@ import android.widget.FrameLayout;
import com.github.penfeizhou.doric.DoricContext; import com.github.penfeizhou.doric.DoricContext;
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin; import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
/** /**
* @Description: com.github.penfeizhou.doric.widget * @Description: com.github.penfeizhou.doric.widget
@ -21,4 +22,15 @@ public class StackNode extends GroupNode<FrameLayout> {
public FrameLayout build(JSObject jsObject) { public FrameLayout build(JSObject jsObject) {
return new FrameLayout(getContext()); return new FrameLayout(getContext());
} }
@Override
protected void blend(FrameLayout view, String name, JSValue prop) {
switch (name) {
case "gravity":
view.setForegroundGravity(prop.asNumber().toInt());
break;
default:
super.blend(view, name, prop);
}
}
} }

View File

@ -0,0 +1,27 @@
package com.github.penfeizhou.doric.shader;
import android.widget.LinearLayout;
import com.github.penfeizhou.doric.DoricContext;
import com.github.penfeizhou.doric.extension.bridge.DoricPlugin;
import com.github.pengfeizhou.jscore.JSObject;
/**
* @Description: com.github.penfeizhou.doric.shader
* @Author: pengfei.zhou
* @CreateDate: 2019-07-23
*/
@DoricPlugin(name = "VLayout")
public class VLayoutNode extends LinearNode {
public VLayoutNode(DoricContext doricContext) {
super(doricContext);
}
@Override
public LinearLayout build(JSObject jsObject) {
LinearLayout linearLayout = super.build(jsObject);
linearLayout.setOrientation(LinearLayout.VERTICAL);
return linearLayout;
}
}

View File

@ -58,10 +58,18 @@ public abstract class ViewNode<T extends View> extends DoricComponent {
protected void blend(T view, String name, JSValue prop) { protected void blend(T view, String name, JSValue prop) {
switch (name) { switch (name) {
case "width": case "width":
view.getLayoutParams().width = DoricUtils.dp2px(prop.asNumber().toFloat()); if (prop.asNumber().toInt() < 0) {
view.getLayoutParams().width = prop.asNumber().toInt();
} else {
view.getLayoutParams().width = DoricUtils.dp2px(prop.asNumber().toFloat());
}
break; break;
case "height": case "height":
view.getLayoutParams().height = DoricUtils.dp2px(prop.asNumber().toFloat()); if (prop.asNumber().toInt() < 0) {
view.getLayoutParams().height = prop.asNumber().toInt();
} else {
view.getLayoutParams().height = DoricUtils.dp2px(prop.asNumber().toFloat());
}
break; break;
case "x": case "x":
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {

View File

@ -1,35 +1,52 @@
import { NativeCall, Text, Alignment, Color, VLayout, Panel, log, logw, loge } from "./index" import { Gravity, Mutable, NativeCall, Text, Color, VLayout, Panel, log, logw, loge, Group, Stack, } from "./index"
import { Group } from "./src/ui/view";
@Entry @Entry
export class MyPage extends Panel { export class MyPage extends Panel {
state = {
count: 0
}
build(rootView: Group): void { build(rootView: Group): void {
const state = Mutable.of(1)
const numberView = new Text const numberView = new Text
numberView.width = 100 numberView.width = 100
numberView.height = 200 numberView.height = 200
numberView.top = 50 numberView.top = 50
numberView.text = this.state.count.toString() state.bind((v) => {
numberView.text = v.toString()
})
numberView.textSize = 40 numberView.textSize = 40
numberView.centerX = rootView.width / 2 numberView.centerX = rootView.width / 2
rootView.addChild(numberView) rootView.addChild(numberView)
const click = new Text const click = new Text
click.width = click.height = 100
click.textSize = 20 click.textSize = 20
click.text = '点击计数' click.text = '点击计数'
click.onClick = () => { click.onClick = () => {
this.state.count++ state.set(state.get() + 1)
numberView.text = this.state.count.toString()
} }
click.centerX = rootView.width / 2
click.top = numberView.bottom + 20 click.top = numberView.bottom + 20
rootView.addChild(click) rootView.addChild(click)
rootView.bgColor = Color.safeParse('#00ff00')
const vlayout = new VLayout
vlayout.width = this.getRootView().width
vlayout.height = 500
vlayout.top = 50
vlayout.centerX = this.getRootView().width / 2
vlayout.space = 0
vlayout.gravity = (new Gravity()).bottom()
const v = [1, 2, 3,].map(e => {
const stack = new Stack
stack.width = stack.height = 50
stack.bgColor = Color.safeParse('#00ff00')
vlayout.addChild(stack)
stack.onClick = () => {
loge('stack:onClick')
if (vlayout.space !== undefined) {
loge('change space')
vlayout.space += 10
}
}
})
rootView.addChild(vlayout)
} }
@NativeCall @NativeCall

View File

@ -2,4 +2,6 @@ export * from "./src/ui/view"
export * from "./src/ui/panel" export * from "./src/ui/panel"
export * from "./src/util/color" export * from "./src/util/color"
export * from './src/util/log' export * from './src/util/log'
export * from './src/util/types'
export * from './src/util/gravity'
export * from './src/runtime/global' export * from './src/runtime/global'

View File

@ -5,6 +5,8 @@ function from(obj: Object) {
} }
}) })
} }
class Wrapper { class Wrapper {
val: any val: any
constructor(val: any) { constructor(val: any) {

View File

@ -1,18 +1,23 @@
import { Color, GradientColor } from "../util/color" import { Color, GradientColor } from "../util/color"
import { Modeling, Model, obj2Model } from "../util/types"; import { Modeling, Model, obj2Model } from "../util/types";
import { uniqueId } from "../util/uniqueId"; import { uniqueId } from "../util/uniqueId";
import { Gravity } from "../util/gravity";
import { loge } from "../util/log"; import { loge } from "../util/log";
export const MATCH_PARENT = -1
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)
} }
export abstract class View implements Modeling { export abstract class View implements Modeling {
@Property @Property
width: number = 0 width: number = WRAP_CONTENT
@Property @Property
height: number = 0 height: number = WRAP_CONTENT
@Property @Property
x: number = 0 x: number = 0
@ -146,9 +151,11 @@ export abstract class View implements Modeling {
} }
} }
} }
isDirty() { isDirty() {
return Reflect.ownKeys(this.__dirty_props__).length !== 0 return Reflect.ownKeys(this.__dirty_props__).length !== 0
} }
responseCallback(id: string, ...args: any) { responseCallback(id: string, ...args: any) {
const f = this.id2Callback(id) const f = this.id2Callback(id)
if (f instanceof Function) { if (f instanceof Function) {
@ -176,20 +183,9 @@ export abstract class View implements Modeling {
@Property @Property
config?: Config config?: Config
}
export enum Alignment { @Property
center = 0, onClick?: Function
start,
end,
}
export enum Gravity {
center = 0,
left,
right,
top,
bottom,
} }
export interface Config { export interface Config {
@ -199,14 +195,14 @@ export interface Config {
top?: number, top?: number,
bottom?: number, bottom?: number,
} }
alignment?: Alignment alignment?: Gravity
} }
export interface StackConfig extends Config { export interface StackConfig extends Config {
} }
export interface LayoutConfig extends Config { export interface LinearConfig extends Config {
weight?: number weight?: number
} }
@ -257,7 +253,7 @@ export abstract class Group extends View {
export class Stack extends Group { export class Stack extends Group {
@Property @Property
gravity?: number gravity?: Gravity
} }
export class Root extends Stack { export class Root extends Stack {
@ -267,7 +263,7 @@ class LinearLayout extends Group {
space?: number space?: number
@Property @Property
gravity?: number gravity?: Gravity
} }
export class VLayout extends LinearLayout { export class VLayout extends LinearLayout {
@ -288,9 +284,6 @@ export class Text extends View {
@Property @Property
maxLines?: number maxLines?: number
@Property
onClick?: Function
} }
export class Image extends View { export class Image extends View {
@ -305,3 +298,24 @@ export class List extends View {
export class Slide extends View { export class Slide extends View {
} }
export function stack() {
}
export function vlayout(providers: Array<() => View>, config: {
width: number
height: number
space?: number
}) {
const vlayout = new VLayout
vlayout.width = config.width
vlayout.height = config.height
if (config.space !== undefined) {
vlayout.space = config.space
}
providers.forEach(e => {
vlayout.addChild(e())
})
return vlayout
}

View File

@ -0,0 +1,64 @@
import { Modeling } from "./types";
const SPECIFIED = 1
const START = 1 << 1
const END = 1 << 2
const SHIFT_X = 0
const SHIFT_Y = 4
export const LEFT = (START | SPECIFIED) << SHIFT_X
export const RIGHT = (END | SPECIFIED) << SHIFT_X
export const TOP = (START | SPECIFIED) << SHIFT_Y
export const BOTTOM = (END | SPECIFIED) << SHIFT_Y
export const CENTER_X = SPECIFIED << SHIFT_X
export const CENTER_Y = SPECIFIED << SHIFT_Y
export const CENTER = CENTER_X | CENTER_Y
export class Gravity implements Modeling {
val = 0
left() {
this.val |= LEFT
return this
}
right() {
this.val |= RIGHT
return this
}
top() {
this.val |= TOP
return this
}
bottom() {
this.val |= BOTTOM
return this
}
center() {
this.val |= CENTER
return this
}
centerX() {
this.val |= CENTER_X
return this
}
centerY() {
this.val |= CENTER_Y
return this
}
toModel() {
return this.val
}
}

View File

@ -15,4 +15,36 @@ export function obj2Model(obj: Model): Model {
} }
type _M = string | number | boolean | Modeling | { [index: string]: Model | undefined } type _M = string | number | boolean | Modeling | { [index: string]: Model | undefined }
export type Model = _M | Array<_M> export type Model = _M | Array<_M>
export type Binder<T> = (v: T) => void
export class Mutable<T>{
private val: T
private binders: Set<Binder<T>> = new Set
get = () => {
return this.val
}
set = (v: T) => {
this.val = v
this.binders.forEach(e => {
Reflect.apply(e, undefined, [this.val])
})
}
private constructor(v: T) {
this.val = v
}
bind(binder: Binder<T>) {
this.binders.add(binder)
Reflect.apply(binder, undefined, [this.val])
}
static of<E>(v: E) {
return new Mutable(v)
}
}

View File

@ -1,5 +1,4 @@
let __uniqueId__: number = 0 let __uniqueId__ = 0
export function uniqueId(prefix: string) { export function uniqueId(prefix: string) {
return `__${prefix}_${__uniqueId__++}__`; return `__${prefix}_${__uniqueId__++}__`;
} }