move dir
This commit is contained in:
262
doric-js/src/ui/animation.ts
Normal file
262
doric-js/src/ui/animation.ts
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Modeling, Model } from "../util/types"
|
||||
|
||||
export type AnimatedKey = "translationX" | "translationY" | "scaleX" | "scaleY" | "rotation" | "pivotX" | "pivotY"
|
||||
|
||||
export enum RepeatMode {
|
||||
RESTART = 1,
|
||||
REVERSE = 2,
|
||||
}
|
||||
|
||||
export interface IAnimation extends Modeling {
|
||||
duration: number
|
||||
delay?: number
|
||||
}
|
||||
|
||||
export interface Changeable {
|
||||
fromValue: number
|
||||
toValue: number
|
||||
key: AnimatedKey
|
||||
repeatCount?: number
|
||||
repeatMode?: RepeatMode
|
||||
}
|
||||
export enum FillMode {
|
||||
/**
|
||||
* The receiver is removed from the presentation when the animation is completed.
|
||||
*/
|
||||
Removed = 0,
|
||||
/**
|
||||
* The receiver remains visible in its final state when the animation is completed.
|
||||
*/
|
||||
Forward = 0x1,
|
||||
/**
|
||||
* The receiver clamps values before zero to zero when the animation is completed.
|
||||
*/
|
||||
Backward = 0x2,
|
||||
/**
|
||||
* The receiver clamps values at both ends of the object’s time space
|
||||
*/
|
||||
Both = 0x3,
|
||||
}
|
||||
|
||||
export enum TimingFunction {
|
||||
/**
|
||||
* The system default timing function. Use this function to ensure that the timing of your animations matches that of most system animations.
|
||||
*/
|
||||
Default = 0,
|
||||
/**
|
||||
* Linear pacing, which causes an animation to occur evenly over its duration.
|
||||
*/
|
||||
Linear,
|
||||
/**
|
||||
* Ease-in pacing, which causes an animation to begin slowly and then speed up as it progresses.
|
||||
*/
|
||||
EaseIn,
|
||||
/**
|
||||
* Ease-out pacing, which causes an animation to begin quickly and then slow as it progresses.
|
||||
*/
|
||||
EaseOut,
|
||||
/**
|
||||
* Ease-in-ease-out pacing, which causes an animation to begin slowly, accelerate through the middle of its duration, and then slow again before completing.
|
||||
*/
|
||||
EaseInEaseOut,
|
||||
}
|
||||
|
||||
abstract class Animation implements IAnimation {
|
||||
changeables: Map<AnimatedKey, Changeable> = new Map
|
||||
duration = 0
|
||||
repeatCount?: number
|
||||
repeatMode?: RepeatMode
|
||||
delay?: number
|
||||
fillMode = FillMode.Forward
|
||||
timingFunction?: TimingFunction
|
||||
toModel() {
|
||||
const changeables = []
|
||||
for (let e of this.changeables.values()) {
|
||||
changeables.push({
|
||||
key: e.key,
|
||||
fromValue: e.fromValue,
|
||||
toValue: e.toValue,
|
||||
})
|
||||
}
|
||||
return {
|
||||
type: this.constructor.name,
|
||||
delay: this.delay,
|
||||
duration: this.duration,
|
||||
changeables,
|
||||
repeatCount: this.repeatCount,
|
||||
repeatMode: this.repeatMode,
|
||||
fillMode: this.fillMode,
|
||||
timingFunction: this.timingFunction
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ScaleAnimation extends Animation {
|
||||
private scaleXChangeable: Changeable = {
|
||||
key: "scaleX",
|
||||
fromValue: 1,
|
||||
toValue: 1,
|
||||
}
|
||||
private scaleYChangeable: Changeable = {
|
||||
key: "scaleY",
|
||||
fromValue: 1,
|
||||
toValue: 1,
|
||||
}
|
||||
constructor() {
|
||||
super()
|
||||
this.changeables.set("scaleX", this.scaleXChangeable)
|
||||
this.changeables.set("scaleY", this.scaleYChangeable)
|
||||
}
|
||||
|
||||
|
||||
set fromScaleX(v: number) {
|
||||
this.scaleXChangeable.fromValue = v
|
||||
}
|
||||
|
||||
get fromScaleX() {
|
||||
return this.scaleXChangeable.fromValue
|
||||
}
|
||||
|
||||
set toScaleX(v: number) {
|
||||
this.scaleXChangeable.toValue = v
|
||||
}
|
||||
|
||||
get toScaleX() {
|
||||
return this.scaleXChangeable.toValue
|
||||
}
|
||||
set fromScaleY(v: number) {
|
||||
this.scaleYChangeable.fromValue = v
|
||||
}
|
||||
|
||||
get fromScaleY() {
|
||||
return this.scaleYChangeable.fromValue
|
||||
}
|
||||
|
||||
set toScaleY(v: number) {
|
||||
this.scaleYChangeable.toValue = v
|
||||
}
|
||||
|
||||
get toScaleY() {
|
||||
return this.scaleYChangeable.toValue
|
||||
}
|
||||
}
|
||||
|
||||
export class TranslationAnimation extends Animation {
|
||||
private translationXChangeable: Changeable = {
|
||||
key: "translationX",
|
||||
fromValue: 1,
|
||||
toValue: 1,
|
||||
}
|
||||
private translationYChangeable: Changeable = {
|
||||
key: "translationY",
|
||||
fromValue: 1,
|
||||
toValue: 1,
|
||||
}
|
||||
constructor() {
|
||||
super()
|
||||
this.changeables.set("translationX", this.translationXChangeable)
|
||||
this.changeables.set("translationY", this.translationYChangeable)
|
||||
}
|
||||
|
||||
set fromTranslationX(v: number) {
|
||||
this.translationXChangeable.fromValue = v
|
||||
}
|
||||
|
||||
get fromTranslationX() {
|
||||
return this.translationXChangeable.fromValue
|
||||
}
|
||||
|
||||
set toTranslationX(v: number) {
|
||||
this.translationXChangeable.toValue = v
|
||||
}
|
||||
|
||||
get toTranslationX() {
|
||||
return this.translationXChangeable.toValue
|
||||
}
|
||||
set fromTranslationY(v: number) {
|
||||
this.translationYChangeable.fromValue = v
|
||||
}
|
||||
|
||||
get fromTranslationY() {
|
||||
return this.translationYChangeable.fromValue
|
||||
}
|
||||
|
||||
set toTranslationY(v: number) {
|
||||
this.translationYChangeable.toValue = v
|
||||
}
|
||||
|
||||
get toTranslationY() {
|
||||
return this.translationYChangeable.toValue
|
||||
}
|
||||
}
|
||||
|
||||
export class RotationAnimation extends Animation {
|
||||
private rotationChaneable: Changeable = {
|
||||
key: "rotation",
|
||||
fromValue: 1,
|
||||
toValue: 1,
|
||||
}
|
||||
constructor() {
|
||||
super()
|
||||
this.changeables.set("rotation", this.rotationChaneable)
|
||||
}
|
||||
|
||||
set fromRotation(v: number) {
|
||||
this.rotationChaneable.fromValue = v
|
||||
}
|
||||
|
||||
get fromRotation() {
|
||||
return this.rotationChaneable.fromValue
|
||||
}
|
||||
|
||||
set toRotation(v: number) {
|
||||
this.rotationChaneable.toValue = v
|
||||
}
|
||||
|
||||
get toRotation() {
|
||||
return this.rotationChaneable.toValue
|
||||
}
|
||||
}
|
||||
|
||||
export class AnimationSet implements IAnimation {
|
||||
private animations: IAnimation[] = []
|
||||
_duration = 0
|
||||
delay?: number
|
||||
addAnimation(anim: IAnimation) {
|
||||
this.animations.push(anim)
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return this._duration
|
||||
}
|
||||
|
||||
set duration(v: number) {
|
||||
this._duration = v
|
||||
this.animations.forEach(e => e.duration = v)
|
||||
}
|
||||
|
||||
toModel() {
|
||||
return {
|
||||
animations: this.animations.map(e => {
|
||||
return e.toModel()
|
||||
}) as Model,
|
||||
delay: this.delay,
|
||||
}
|
||||
}
|
||||
}
|
18
doric-js/src/ui/index.ui.ts
Normal file
18
doric-js/src/ui/index.ui.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
export * from './view'
|
||||
export * from './panel'
|
||||
export * from './animation'
|
169
doric-js/src/ui/panel.ts
Normal file
169
doric-js/src/ui/panel.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import '../runtime/global'
|
||||
import { View, Group } from "./view"
|
||||
import { loge } from '../util/log'
|
||||
import { Model } from '../util/types'
|
||||
import { Root } from '../widget/layouts'
|
||||
|
||||
|
||||
export function NativeCall(target: Panel, propertyKey: string, descriptor: PropertyDescriptor) {
|
||||
const originVal = descriptor.value
|
||||
descriptor.value = function () {
|
||||
const ret = Reflect.apply(originVal, this, arguments)
|
||||
return ret
|
||||
}
|
||||
return descriptor
|
||||
}
|
||||
|
||||
type Frame = { width: number, height: number }
|
||||
|
||||
declare function nativeEmpty(): void
|
||||
|
||||
export abstract class Panel {
|
||||
context?: any
|
||||
onCreate() { }
|
||||
onDestroy() { }
|
||||
onShow() { }
|
||||
onHidden() { }
|
||||
|
||||
abstract build(rootView: Group): void
|
||||
|
||||
private __data__?: object
|
||||
private __root__ = new Root
|
||||
private headviews: Map<string, View> = new Map
|
||||
|
||||
addHeadView(v: View) {
|
||||
this.headviews.set(v.viewId, v)
|
||||
}
|
||||
allHeadViews() {
|
||||
return this.headviews.values()
|
||||
}
|
||||
removeHeadView(v: View | string) {
|
||||
if (v instanceof View) {
|
||||
this.headviews.delete(v.viewId)
|
||||
} else {
|
||||
this.headviews.delete(v)
|
||||
}
|
||||
}
|
||||
|
||||
clearHeadViews() {
|
||||
this.headviews.clear()
|
||||
}
|
||||
|
||||
getRootView() {
|
||||
return this.__root__
|
||||
}
|
||||
|
||||
getInitData() {
|
||||
return this.__data__
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __init__(frame: Frame, data?: string) {
|
||||
if (data) {
|
||||
this.__data__ = JSON.parse(data)
|
||||
}
|
||||
this.__root__.width = frame.width
|
||||
this.__root__.height = frame.height
|
||||
this.__root__.children.length = 0
|
||||
this.build(this.__root__)
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __onCreate__() {
|
||||
this.onCreate()
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __onDestroy__() {
|
||||
this.onDestroy()
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __onShow__() {
|
||||
this.onShow()
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __onHidden__(): void {
|
||||
this.onHidden()
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __build__() {
|
||||
this.build(this.__root__)
|
||||
}
|
||||
|
||||
@NativeCall
|
||||
private __response__(viewIds: string[], callbackId: string) {
|
||||
const v = this.retrospectView(viewIds)
|
||||
if (v === undefined) {
|
||||
loge(`Cannot find view for ${viewIds}`)
|
||||
} else {
|
||||
const argumentsList: any = [callbackId]
|
||||
for (let i = 2; i < arguments.length; i++) {
|
||||
argumentsList.push(arguments[i])
|
||||
}
|
||||
return Reflect.apply(v.responseCallback, v, argumentsList)
|
||||
}
|
||||
}
|
||||
|
||||
private retrospectView(ids: string[]): View | undefined {
|
||||
return ids.reduce((acc: View | undefined, cur) => {
|
||||
if (acc === undefined) {
|
||||
if (cur === this.__root__.viewId) {
|
||||
return this.__root__
|
||||
}
|
||||
return this.headviews.get(cur)
|
||||
} else {
|
||||
if (Reflect.has(acc, "subviewById")) {
|
||||
return Reflect.apply(Reflect.get(acc, "subviewById"), acc, [cur])
|
||||
}
|
||||
return acc
|
||||
}
|
||||
}, undefined)
|
||||
}
|
||||
|
||||
private nativeRender(model: Model) {
|
||||
if (this.context) {
|
||||
this.context.shader.render(model)
|
||||
}
|
||||
}
|
||||
|
||||
private hookBeforeNativeCall() {
|
||||
this.__root__.clean()
|
||||
for (let v of this.headviews.values()) {
|
||||
v.clean()
|
||||
}
|
||||
}
|
||||
|
||||
private hookAfterNativeCall() {
|
||||
//Here insert a native call to ensure the promise is resolved done.
|
||||
nativeEmpty()
|
||||
if (this.__root__.isDirty()) {
|
||||
const model = this.__root__.toModel()
|
||||
this.nativeRender(model)
|
||||
}
|
||||
for (let v of this.headviews.values()) {
|
||||
if (v.isDirty()) {
|
||||
const model = v.toModel()
|
||||
this.nativeRender(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
401
doric-js/src/ui/view.ts
Normal file
401
doric-js/src/ui/view.ts
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import { Color, GradientColor } from "../util/color"
|
||||
import { Modeling, Model, obj2Model } from "../util/types";
|
||||
import { uniqueId } from "../util/uniqueId";
|
||||
import { loge } from "../util/log";
|
||||
import { BridgeContext } from "../runtime/global";
|
||||
import { LayoutConfig } from '../util/layoutconfig'
|
||||
import { IAnimation } from "./animation";
|
||||
|
||||
export function Property(target: Object, propKey: string) {
|
||||
Reflect.defineMetadata(propKey, true, target)
|
||||
}
|
||||
|
||||
export interface IView {
|
||||
width?: number
|
||||
height?: number
|
||||
backgroundColor?: Color | GradientColor
|
||||
corners?: number | { leftTop?: number; rightTop?: number; leftBottom?: number; rightBottom?: number }
|
||||
border?: { width: number; color: Color; }
|
||||
shadow?: { color: Color; opacity: number; radius: number; offsetX: number; offsetY: number }
|
||||
/**
|
||||
* float [0,..1]
|
||||
*/
|
||||
alpha?: number
|
||||
hidden?: boolean
|
||||
padding?: {
|
||||
left?: number,
|
||||
right?: number,
|
||||
top?: number,
|
||||
bottom?: number,
|
||||
}
|
||||
layoutConfig?: LayoutConfig
|
||||
onClick?: Function
|
||||
identifier?: string
|
||||
|
||||
/**++++++++++transform++++++++++*/
|
||||
translationX?: number
|
||||
|
||||
translationY?: number
|
||||
|
||||
scaleX?: number
|
||||
|
||||
scaleY?: number
|
||||
/**
|
||||
* float [0,..1]
|
||||
*/
|
||||
pivotX?: number
|
||||
/**
|
||||
* float [0,..1]
|
||||
*/
|
||||
pivotY?: number
|
||||
/**
|
||||
* rotation*PI
|
||||
*/
|
||||
rotation?: number
|
||||
/**----------transform----------*/
|
||||
}
|
||||
|
||||
|
||||
export abstract class View implements Modeling, IView {
|
||||
@Property
|
||||
width: number = 0
|
||||
|
||||
@Property
|
||||
height: number = 0
|
||||
|
||||
@Property
|
||||
x: number = 0
|
||||
|
||||
@Property
|
||||
y: number = 0
|
||||
|
||||
@Property
|
||||
backgroundColor?: Color | GradientColor
|
||||
|
||||
@Property
|
||||
corners?: number | { leftTop?: number; rightTop?: number; leftBottom?: number; rightBottom?: number }
|
||||
|
||||
@Property
|
||||
border?: { width: number; color: Color; }
|
||||
|
||||
@Property
|
||||
shadow?: { color: Color; opacity: number; radius: number; offsetX: number; offsetY: number }
|
||||
|
||||
@Property
|
||||
alpha?: number
|
||||
|
||||
@Property
|
||||
hidden?: boolean
|
||||
|
||||
@Property
|
||||
viewId = uniqueId('ViewId')
|
||||
|
||||
@Property
|
||||
padding?: {
|
||||
left?: number,
|
||||
right?: number,
|
||||
top?: number,
|
||||
bottom?: number,
|
||||
}
|
||||
|
||||
@Property
|
||||
layoutConfig?: LayoutConfig
|
||||
|
||||
@Property
|
||||
onClick?: Function
|
||||
|
||||
superview?: Superview
|
||||
|
||||
callbacks: Map<String, Function> = new Map
|
||||
|
||||
private callback2Id(f: Function) {
|
||||
const id = uniqueId('Function')
|
||||
this.callbacks.set(id, f)
|
||||
return id
|
||||
}
|
||||
|
||||
private id2Callback(id: string) {
|
||||
let f = this.callbacks.get(id)
|
||||
if (f === undefined) {
|
||||
f = Reflect.get(this, id) as Function
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get: (target, p, receiver) => {
|
||||
return Reflect.get(target, p, receiver)
|
||||
},
|
||||
set: (target, p, v, receiver) => {
|
||||
const oldV = Reflect.get(target, p, receiver)
|
||||
const ret = Reflect.set(target, p, v, receiver)
|
||||
if (Reflect.getMetadata(p, target) && oldV !== v) {
|
||||
receiver.onPropertyChanged(p.toString(), oldV, v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
})
|
||||
}
|
||||
/** Anchor start*/
|
||||
get left() {
|
||||
return this.x
|
||||
}
|
||||
set left(v: number) {
|
||||
this.x = v
|
||||
}
|
||||
|
||||
get right() {
|
||||
return this.x + this.width
|
||||
}
|
||||
set right(v: number) {
|
||||
this.x = v - this.width
|
||||
}
|
||||
|
||||
get top() {
|
||||
return this.y
|
||||
}
|
||||
|
||||
set top(v: number) {
|
||||
this.y = v
|
||||
}
|
||||
|
||||
get bottom() {
|
||||
return this.y + this.height
|
||||
}
|
||||
|
||||
set bottom(v: number) {
|
||||
this.y = v - this.height
|
||||
}
|
||||
|
||||
get centerX() {
|
||||
return this.x + this.width / 2
|
||||
}
|
||||
|
||||
get centerY() {
|
||||
return this.y + this.height / 2
|
||||
}
|
||||
|
||||
set centerX(v: number) {
|
||||
this.x = v - this.width / 2
|
||||
}
|
||||
|
||||
set centerY(v: number) {
|
||||
this.y = v - this.height / 2
|
||||
}
|
||||
/** Anchor end*/
|
||||
|
||||
private __dirty_props__: { [index: string]: Model | undefined } = {}
|
||||
|
||||
get dirtyProps() {
|
||||
return this.__dirty_props__
|
||||
}
|
||||
|
||||
nativeViewModel = {
|
||||
id: this.viewId,
|
||||
type: this.constructor.name,
|
||||
props: this.__dirty_props__,
|
||||
}
|
||||
|
||||
onPropertyChanged(propKey: string, oldV: Model, newV: Model): void {
|
||||
if (newV instanceof Function) {
|
||||
newV = this.callback2Id(newV)
|
||||
} else {
|
||||
newV = obj2Model(newV)
|
||||
}
|
||||
this.__dirty_props__[propKey] = newV
|
||||
}
|
||||
|
||||
clean() {
|
||||
for (const key in this.__dirty_props__) {
|
||||
if (Reflect.has(this.__dirty_props__, key)) {
|
||||
Reflect.deleteProperty(this.__dirty_props__, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isDirty() {
|
||||
return Reflect.ownKeys(this.__dirty_props__).length !== 0
|
||||
}
|
||||
|
||||
responseCallback(id: string, ...args: any) {
|
||||
const f = this.id2Callback(id)
|
||||
if (f instanceof Function) {
|
||||
const argumentsList: any = []
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
argumentsList.push(arguments[i])
|
||||
}
|
||||
return Reflect.apply(f, this, argumentsList)
|
||||
} else {
|
||||
loge(`Cannot find callback:${id} for ${JSON.stringify(this.toModel())}`)
|
||||
}
|
||||
}
|
||||
|
||||
toModel() {
|
||||
return this.nativeViewModel
|
||||
}
|
||||
|
||||
let(block: (it: this) => void) {
|
||||
block(this)
|
||||
}
|
||||
|
||||
also(block: (it: this) => void) {
|
||||
block(this)
|
||||
return this
|
||||
}
|
||||
|
||||
apply(config: IView) {
|
||||
for (let key in config) {
|
||||
Reflect.set(this, key, Reflect.get(config, key, config), this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
in(group: Group) {
|
||||
group.addChild(this)
|
||||
return this
|
||||
}
|
||||
|
||||
nativeChannel(context: any, name: string) {
|
||||
let thisView: View | undefined = this
|
||||
return function (args: any = undefined) {
|
||||
const func = context.shader.command
|
||||
const viewIds = []
|
||||
while (thisView != undefined) {
|
||||
viewIds.push(thisView.viewId)
|
||||
thisView = thisView.superview
|
||||
}
|
||||
const params = {
|
||||
viewIds: viewIds.reverse(),
|
||||
name,
|
||||
args,
|
||||
}
|
||||
return Reflect.apply(func, undefined, [params]) as Promise<any>
|
||||
}
|
||||
}
|
||||
|
||||
getWidth(context: BridgeContext) {
|
||||
return this.nativeChannel(context, 'getWidth')() as Promise<number>
|
||||
}
|
||||
|
||||
getHeight(context: BridgeContext) {
|
||||
return this.nativeChannel(context, 'getHeight')() as Promise<number>
|
||||
}
|
||||
|
||||
getLocationOnScreen(context: BridgeContext) {
|
||||
return this.nativeChannel(context, "getLocationOnScreen")() as Promise<{ x: number, y: number }>
|
||||
}
|
||||
|
||||
/**++++++++++transform++++++++++*/
|
||||
@Property
|
||||
translationX?: number
|
||||
|
||||
@Property
|
||||
translationY?: number
|
||||
|
||||
@Property
|
||||
scaleX?: number
|
||||
|
||||
@Property
|
||||
scaleY?: number
|
||||
|
||||
@Property
|
||||
pivotX?: number
|
||||
|
||||
@Property
|
||||
pivotY?: number
|
||||
|
||||
@Property
|
||||
rotation?: number
|
||||
/**----------transform----------*/
|
||||
|
||||
doAnimation(context: BridgeContext, animation: IAnimation) {
|
||||
return this.nativeChannel(context, "doAnimation")(animation.toModel()).then((args) => {
|
||||
for (let key in args) {
|
||||
Reflect.set(this, key, Reflect.get(args, key, args), this)
|
||||
Reflect.deleteProperty(this.__dirty_props__, key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Superview extends View {
|
||||
subviewById(id: string): View | undefined {
|
||||
for (let v of this.allSubviews()) {
|
||||
if (v.viewId === id) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
abstract allSubviews(): Iterable<View>
|
||||
|
||||
isDirty() {
|
||||
if (super.isDirty()) {
|
||||
return true
|
||||
} else {
|
||||
for (const v of this.allSubviews()) {
|
||||
if (v.isDirty()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
clean() {
|
||||
for (let v of this.allSubviews()) {
|
||||
v.clean()
|
||||
}
|
||||
super.clean()
|
||||
}
|
||||
|
||||
toModel() {
|
||||
const subviews = []
|
||||
for (let v of this.allSubviews()) {
|
||||
if (v != undefined) {
|
||||
v.superview = this
|
||||
if (v.isDirty()) {
|
||||
subviews.push(v.toModel())
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dirtyProps.subviews = subviews
|
||||
return super.toModel()
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Group extends Superview {
|
||||
|
||||
readonly children: View[] = new Proxy([], {
|
||||
set: (target, index, value) => {
|
||||
const ret = Reflect.set(target, index, value)
|
||||
// Let getDirty return true
|
||||
this.dirtyProps.children = this.children.map(e => e.viewId)
|
||||
return ret
|
||||
}
|
||||
})
|
||||
|
||||
allSubviews() {
|
||||
return this.children
|
||||
}
|
||||
|
||||
addChild(view: View) {
|
||||
this.children.push(view)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user