diff --git a/demo/index.ts b/demo/index.ts index ef40e3af..432ed215 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -5,4 +5,5 @@ export default [ 'src/ScrollerDemo', 'src/SliderDemo', 'src/LayoutDemo', + 'src/EffectsDemo', ] \ No newline at end of file diff --git a/demo/src/EffectsDemo.ts b/demo/src/EffectsDemo.ts new file mode 100644 index 00000000..71780949 --- /dev/null +++ b/demo/src/EffectsDemo.ts @@ -0,0 +1,367 @@ + +import { Group, Panel, Text, text, gravity, Color, Stack, LayoutSpec, vlayout, hlayout, scroller, IVLayout, IHLayout, layoutConfig } from "doric"; +import { colors } from "./colorutils"; + + +function box(idx = 0) { + return (new Stack).also(it => { + it.width = it.height = 20 + it.bgColor = colors[idx || 0] + }) +} + +function boxStr(str: string, idx = 0) { + return (new Text).also(it => { + it.width = it.height = 20 + it.text = str + it.textColor = Color.parse('#ffffff') + it.bgColor = colors[idx || 0] + }) +} + +function label(str: string) { + return text({ + text: str, + textSize: 16, + }) +} + +@Entry +class EffectsDemo extends Panel { + build(rootView: Group) { + scroller( + vlayout([ + hlayout([ + vlayout([ + label("Origin view"), + box().apply({ + width: 100, + height: 100 + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Border"), + box().apply({ + width: 100, + height: 100, + border: { + width: 5, + color: colors[3] + }, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Corner"), + box().apply({ + width: 100, + height: 100, + corners: 10, + layoutConfig: layoutConfig().exactly().m({ + bottom: 10 + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Shadow"), + box().apply({ + width: 100, + height: 100, + shadow: { + opacity: 1, + color: colors[1], + offsetX: 3, + offsetY: 3, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + bottom: 10 + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + ]).apply({ space: 20 } as IHLayout), + hlayout([ + vlayout([ + label("Border,Corner"), + box().apply({ + width: 100, + height: 100, + border: { + width: 5, + color: colors[3] + }, + corners: 10, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Border,Shadow"), + box().apply({ + width: 100, + height: 100, + border: { + width: 5, + color: colors[3] + }, + shadow: { + opacity: 1, + color: colors[1], + offsetX: 3, + offsetY: 3, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + bottom: 10 + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Corner,Shadow"), + box().apply({ + width: 100, + height: 100, + corners: 10, + shadow: { + opacity: 1, + color: colors[1], + offsetX: 3, + offsetY: 3, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + bottom: 10 + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Border,Corner,Shadow"), + box().apply({ + width: 100, + height: 100, + border: { + width: 5, + color: colors[3] + }, + corners: 10, + shadow: { + opacity: 1, + color: colors[1], + offsetX: 3, + offsetY: 3, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + ]).apply({ space: 20 } as IHLayout), + hlayout([ + vlayout([ + label("Shadow"), + box().apply({ + width: 100, + height: 100, + corners: 50, + shadow: { + opacity: 1, + color: colors[1], + offsetX: 0, + offsetY: 0, + radius: 10, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 10, + right: 10, + bottom: 10, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Shadow,offset"), + box().apply({ + width: 100, + height: 100, + corners: 50, + shadow: { + opacity: 1, + color: colors[1], + offsetX: 5, + offsetY: 5, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 10, + right: 10, + bottom: 10, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Shadow,opacity"), + box().apply({ + width: 100, + height: 100, + corners: 50, + shadow: { + opacity: 0.5, + color: colors[1], + offsetX: 5, + offsetY: 5, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 10, + right: 10, + bottom: 10, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Shadow,color"), + box().apply({ + width: 100, + height: 100, + corners: 50, + shadow: { + opacity: 1, + color: colors[2], + offsetX: 5, + offsetY: 5, + radius: 5, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 10, + right: 10, + bottom: 10, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + ]).apply({ space: 20 } as IHLayout), + hlayout([ + vlayout([ + label("Corner round"), + box().apply({ + width: 100, + height: 100, + corners: 50, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Corner left top"), + box().apply({ + width: 100, + height: 100, + corners: { + leftTop: 50, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Corner right top"), + box().apply({ + width: 100, + height: 100, + corners: { + rightTop: 50, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Corner left bottom"), + box().apply({ + width: 100, + height: 100, + corners: { + leftBottom: 50, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + vlayout([ + label("Corner right bottom"), + box().apply({ + width: 100, + height: 100, + corners: { + rightBottom: 50, + }, + layoutConfig: layoutConfig().exactly().m({ + left: 5, + right: 5, + bottom: 5, + }) + }),]).apply({ + gravity: gravity().center(), + space: 10, + } as IVLayout), + ]).apply({ space: 20 } as IHLayout), + ]).also(it => { + it.space = 20 + }), + ).also(it => { + it.layoutConfig = layoutConfig().wrap() + }).in(rootView) + } +} \ No newline at end of file diff --git a/demo/src/ListDemo.ts b/demo/src/ListDemo.ts index c4572d97..a0ccb61a 100644 --- a/demo/src/ListDemo.ts +++ b/demo/src/ListDemo.ts @@ -44,6 +44,7 @@ class ListPanel extends Panel { text({ textColor: Color.parse("#ffffff"), textSize: 20, + text: "", }).also(it => { counter = it it.layoutConfig = { diff --git a/demo/src/SliderDemo.ts b/demo/src/SliderDemo.ts index 49ca4b8a..a1f6a35c 100644 --- a/demo/src/SliderDemo.ts +++ b/demo/src/SliderDemo.ts @@ -1,53 +1,48 @@ -import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, slider, slideItem } from "doric"; -const colors = [ - "#f0932b", - "#eb4d4b", - "#6ab04c", - "#e056fd", - "#686de0", - "#30336b", +import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, slider, slideItem, image, layoutConfig } from "doric"; +import { colors } from "./colorutils"; + +const imageUrls = [ + 'http://b.hiphotos.baidu.com/image/pic/item/908fa0ec08fa513db777cf78376d55fbb3fbd9b3.jpg', + 'http://f.hiphotos.baidu.com/image/pic/item/0e2442a7d933c8956c0e8eeadb1373f08202002a.jpg', + 'http://f.hiphotos.baidu.com/image/pic/item/b151f8198618367aa7f3cc7424738bd4b31ce525.jpg', + 'http://b.hiphotos.baidu.com/image/pic/item/0eb30f2442a7d9337119f7dba74bd11372f001e0.jpg', + 'http://calonye.com/wp-content/uploads/2015/08/0-wx_fmtgiftpwebpwxfrom5wx_lazy1-9.gif', + 'http://hbimg.b0.upaiyun.com/ca29ea125b7f2d580f573e48eb594b1ef509757f34a08-m0hK45_fw658', + 'https://misc.aotu.io/ONE-SUNDAY/SteamEngine.png', ] @Entry class SliderPanel extends Panel { build(rootView: Group): void { rootView.addChild(vlayout([ text({ - text: "SliderDemo", + text: "Gallery", layoutConfig: { widthSpec: LayoutSpec.AT_MOST, heightSpec: LayoutSpec.EXACTLY, }, textSize: 30, - textColor: Color.parse("#535c68"), - bgColor: Color.parse("#dff9fb"), + textColor: Color.WHITE, + bgColor: colors[1], textAlignment: gravity().center(), height: 50, }), slider({ itemCount: 100, renderPage: (idx) => { - return slideItem(text({ - layoutConfig: { - widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.EXACTLY, - alignment: gravity().center(), - }, - text: `Page At Line ${idx}`, - textAlignment: gravity().center(), - textColor: Color.parse("#ffffff"), - textSize: 20, - height: 300, - bgColor: Color.parse(colors[idx % colors.length]), - }).also(it => { + return slideItem(image({ + imageUrl: imageUrls[idx % imageUrls.length], + layoutConfig: layoutConfig().wrap().a(gravity().center()), + })).also(it => { let start = idx it.onClick = () => { - it.bgColor = Color.parse(colors[++start % colors.length]) + it.bgColor = (colors[++start % colors.length]) } - })) + }) }, layoutConfig: { widthSpec: LayoutSpec.AT_MOST, heightSpec: LayoutSpec.WRAP_CONTENT, + weight: 1, }, }), ]).also(it => { diff --git a/demo/src/Snake.ts b/demo/src/Snake.ts index 6b438750..90d2da7d 100644 --- a/demo/src/Snake.ts +++ b/demo/src/Snake.ts @@ -281,6 +281,14 @@ class SnakeView extends ViewHolder { if (item === undefined) { item = new Stack item.width = item.height = 10 + item.corners = 5 + item.shadow = { + color: Color.GRAY, + opacity: 1, + radius: 3, + offsetX: 3, + offsetY: 3, + } this.panel.addChild(item) } if (index === nodes.length - 1) { diff --git a/demo/src/colorutils.ts b/demo/src/colorutils.ts new file mode 100644 index 00000000..093d46c3 --- /dev/null +++ b/demo/src/colorutils.ts @@ -0,0 +1,14 @@ +import { Color } from "doric"; + +export const colors = [ + "#70a1ff", + "#7bed9f", + "#ff6b81", + "#a4b0be", + "#f0932b", + "#eb4d4b", + "#6ab04c", + "#e056fd", + "#686de0", + "#30336b", +].map(e => Color.parse(e)) \ No newline at end of file diff --git a/iOS/Pod/Classes/Shader/DoricViewNode.m b/iOS/Pod/Classes/Shader/DoricViewNode.m index 6731c663..a978736a 100644 --- a/iOS/Pod/Classes/Shader/DoricViewNode.m +++ b/iOS/Pod/Classes/Shader/DoricViewNode.m @@ -147,20 +147,21 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop CGFloat rightTop = [(NSNumber *) dic[@"rightTop"] floatValue]; CGFloat rightBottom = [(NSNumber *) dic[@"rightBottom"] floatValue]; CGFloat leftBottom = [(NSNumber *) dic[@"leftBottom"] floatValue]; - CALayer *mask = nil; if (ABS(leftTop - rightTop) > CGFLOAT_MIN || ABS(leftTop - rightBottom) > CGFLOAT_MIN || ABS(leftTop - leftBottom) > CGFLOAT_MIN) { view.layer.cornerRadius = 0; - CAShapeLayer *shapeLayer = [CAShapeLayer layer]; - CGPathRef path = DoricCreateRoundedRectPath(self.view.bounds, leftTop, rightTop, rightBottom, leftBottom); - shapeLayer.path = path; - CGPathRelease(path); - mask = shapeLayer; + dispatch_async(dispatch_get_main_queue(), ^{ + CAShapeLayer *shapeLayer = [CAShapeLayer layer]; + CGPathRef path = DoricCreateRoundedRectPath(self.view.bounds, leftTop, rightTop, rightBottom, leftBottom); + shapeLayer.path = path; + CGPathRelease(path); + view.layer.mask = shapeLayer; + }); } else { view.layer.cornerRadius = leftTop; + view.layer.mask = nil; } - view.layer.mask = mask; } } else if ([name isEqualToString:@"shadow"]) { NSDictionary *dic = prop; diff --git a/js-framework/src/ui/declarative.ts b/js-framework/src/ui/declarative.ts index 9a609cca..02a5e61b 100644 --- a/js-framework/src/ui/declarative.ts +++ b/js-framework/src/ui/declarative.ts @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { View, LayoutSpec } from './view' +import { View, LayoutSpec, LayoutConfig } from './view' import { Stack, HLayout, VLayout } from './layout' import { IText, IImage, Text, Image } from './widgets' import { IList, List } from './list' import { ISlider, Slider } from './slider' +import { Gravity } from '../util/gravity' +import { Modeling } from '../util/types' export function text(config: IText) { const ret = new Text - ret.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - } + ret.layoutConfig = layoutConfig().wrap() for (let key in config) { Reflect.set(ret, key, Reflect.get(config, key, config), ret) } @@ -33,10 +32,7 @@ export function text(config: IText) { export function image(config: IImage) { const ret = new Image - ret.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - } + ret.layoutConfig = layoutConfig().wrap() for (let key in config) { Reflect.set(ret, key, Reflect.get(config, key, config), ret) } @@ -45,10 +41,7 @@ export function image(config: IImage) { export function stack(views: View[]) { const ret = new Stack - ret.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - } + ret.layoutConfig = layoutConfig().wrap() for (let v of views) { ret.addChild(v) } @@ -57,10 +50,7 @@ export function stack(views: View[]) { export function hlayout(views: View[]) { const ret = new HLayout - ret.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - } + ret.layoutConfig = layoutConfig().wrap() for (let v of views) { ret.addChild(v) } @@ -69,10 +59,7 @@ export function hlayout(views: View[]) { export function vlayout(views: View[]) { const ret = new VLayout - ret.layoutConfig = { - widthSpec: LayoutSpec.WRAP_CONTENT, - heightSpec: LayoutSpec.WRAP_CONTENT, - } + ret.layoutConfig = layoutConfig().wrap() for (let v of views) { ret.addChild(v) } @@ -93,4 +80,80 @@ export function slider(config: ISlider) { Reflect.set(ret, key, Reflect.get(config, key, config), ret) } return ret +} + +export class LayoutConfigImpl implements LayoutConfig, Modeling { + widthSpec?: LayoutSpec + heightSpec?: LayoutSpec + margin?: { + left?: number, + right?: number, + top?: number, + bottom?: number, + } + alignment?: Gravity + //Only affective in VLayout or HLayout + weight?: number + + wrap() { + this.widthSpec = LayoutSpec.WRAP_CONTENT + this.heightSpec = LayoutSpec.WRAP_CONTENT + return this + } + + atmost() { + this.widthSpec = LayoutSpec.AT_MOST + this.heightSpec = LayoutSpec.AT_MOST + return this + } + + exactly() { + this.widthSpec = LayoutSpec.EXACTLY + this.heightSpec = LayoutSpec.EXACTLY + return this + } + + w(w: LayoutSpec) { + this.widthSpec = w + return this + } + + h(h: LayoutSpec) { + this.heightSpec = h + return this + } + + m(m: { + left?: number, + right?: number, + top?: number, + bottom?: number, + }) { + this.margin = m + return this + } + + a(a: Gravity) { + this.alignment = a + return this + } + + wg(w: number) { + this.weight = w + return this + } + + toModel() { + return { + widthSpec: this.widthSpec, + heightSpec: this.heightSpec, + margin: this.margin, + alignment: this.alignment ? this.alignment.toModel() : undefined, + weight: this.weight, + } + } +} + +export function layoutConfig() { + return new LayoutConfigImpl } \ No newline at end of file diff --git a/js-framework/src/ui/slider.ts b/js-framework/src/ui/slider.ts index 5584445a..0778b6e5 100644 --- a/js-framework/src/ui/slider.ts +++ b/js-framework/src/ui/slider.ts @@ -5,7 +5,7 @@ export function slideItem(item: View) { return (new SlideItem).also((it) => { it.layoutConfig = { widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.WRAP_CONTENT, + heightSpec: LayoutSpec.AT_MOST, } it.addChild(item) })