Merge branch 'feature/animation' into 'master'
Feature/animation See merge request !35
This commit is contained in:
commit
abd9fcdd0a
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package pub.doric;
|
package pub.doric;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.github.pengfeizhou.jscore.JSDecoder;
|
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||||
@ -161,6 +163,7 @@ public class DoricContext {
|
|||||||
|
|
||||||
public void reload(String script) {
|
public void reload(String script) {
|
||||||
this.script = script;
|
this.script = script;
|
||||||
|
this.mRootNode.setId("");
|
||||||
getDriver().createContext(mContextId, script, source);
|
getDriver().createContext(mContextId, script, source);
|
||||||
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams);
|
callEntity(DoricConstant.DORIC_ENTITY_INIT, this.initParams);
|
||||||
}
|
}
|
||||||
@ -192,4 +195,15 @@ public class DoricContext {
|
|||||||
public IDoricNavBar getDoricNavBar() {
|
public IDoricNavBar getDoricNavBar() {
|
||||||
return this.doricNavBar;
|
return this.doricNavBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AnimatorSet animatorSet;
|
||||||
|
|
||||||
|
public void setAnimatorSet(AnimatorSet animatorSet) {
|
||||||
|
this.animatorSet = animatorSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatorSet getAnimatorSet() {
|
||||||
|
return this.animatorSet;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import android.text.TextUtils;
|
|||||||
import pub.doric.loader.DoricAssetJSLoader;
|
import pub.doric.loader.DoricAssetJSLoader;
|
||||||
import pub.doric.loader.DoricHttpJSLoader;
|
import pub.doric.loader.DoricHttpJSLoader;
|
||||||
import pub.doric.loader.IDoricJSLoader;
|
import pub.doric.loader.IDoricJSLoader;
|
||||||
|
import pub.doric.plugin.AnimatePlugin;
|
||||||
import pub.doric.plugin.NavBarPlugin;
|
import pub.doric.plugin.NavBarPlugin;
|
||||||
import pub.doric.plugin.NavigatorPlugin;
|
import pub.doric.plugin.NavigatorPlugin;
|
||||||
import pub.doric.plugin.NetworkPlugin;
|
import pub.doric.plugin.NetworkPlugin;
|
||||||
@ -89,6 +90,7 @@ public class DoricRegistry {
|
|||||||
this.registerNativePlugin(NavigatorPlugin.class);
|
this.registerNativePlugin(NavigatorPlugin.class);
|
||||||
this.registerNativePlugin(NavBarPlugin.class);
|
this.registerNativePlugin(NavBarPlugin.class);
|
||||||
this.registerNativePlugin(PopoverPlugin.class);
|
this.registerNativePlugin(PopoverPlugin.class);
|
||||||
|
this.registerNativePlugin(AnimatePlugin.class);
|
||||||
|
|
||||||
this.registerViewNode(RootNode.class);
|
this.registerViewNode(RootNode.class);
|
||||||
this.registerViewNode(TextNode.class);
|
this.registerViewNode(TextNode.class);
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package pub.doric.plugin;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.github.pengfeizhou.jscore.JSObject;
|
||||||
|
import com.github.pengfeizhou.jscore.JavaValue;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import pub.doric.DoricContext;
|
||||||
|
import pub.doric.async.AsyncResult;
|
||||||
|
import pub.doric.extension.bridge.DoricMethod;
|
||||||
|
import pub.doric.extension.bridge.DoricPlugin;
|
||||||
|
import pub.doric.extension.bridge.DoricPromise;
|
||||||
|
import pub.doric.shader.RootNode;
|
||||||
|
import pub.doric.shader.ViewNode;
|
||||||
|
import pub.doric.utils.DoricLog;
|
||||||
|
import pub.doric.utils.ThreadMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: pub.doric.plugin
|
||||||
|
* @Author: pengfei.zhou
|
||||||
|
* @CreateDate: 2019-11-29
|
||||||
|
*/
|
||||||
|
@DoricPlugin(name = "animate")
|
||||||
|
public class AnimatePlugin extends DoricJavaPlugin {
|
||||||
|
public AnimatePlugin(DoricContext doricContext) {
|
||||||
|
super(doricContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
public void submit(DoricPromise promise) {
|
||||||
|
promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
public void animateRender(final JSObject jsObject, final DoricPromise promise) {
|
||||||
|
getDoricContext().getDriver().asyncCall(new Callable<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object call() throws Exception {
|
||||||
|
final long duration = jsObject.getProperty("duration").asNumber().toLong();
|
||||||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||||||
|
getDoricContext().setAnimatorSet(animatorSet);
|
||||||
|
String viewId = jsObject.getProperty("id").asString().value();
|
||||||
|
RootNode rootNode = getDoricContext().getRootNode();
|
||||||
|
if (TextUtils.isEmpty(rootNode.getId())) {
|
||||||
|
rootNode.setId(viewId);
|
||||||
|
rootNode.blend(jsObject.getProperty("props").asObject());
|
||||||
|
} else {
|
||||||
|
ViewNode viewNode = getDoricContext().targetViewNode(viewId);
|
||||||
|
if (viewNode != null) {
|
||||||
|
viewNode.blend(jsObject.getProperty("props").asObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getDoricContext().setAnimatorSet(null);
|
||||||
|
animatorSet.setDuration(duration);
|
||||||
|
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
promise.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animatorSet.start();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, ThreadMode.UI).setCallback(new AsyncResult.Callback<Object>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(Object result) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
DoricLog.e("Shader.render:error%s", t.getLocalizedMessage());
|
||||||
|
promise.reject(new JavaValue(t.getLocalizedMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish() {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -174,7 +174,11 @@ public class ShaderPlugin extends DoricJavaPlugin {
|
|||||||
if (clz == DoricPromise.class) {
|
if (clz == DoricPromise.class) {
|
||||||
return doricPromise;
|
return doricPromise;
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
|
return DoricUtils.toJavaObject(clz, jsValue);
|
||||||
|
} catch (Exception e) {
|
||||||
return jsValue;
|
return jsValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -912,7 +912,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
|
|||||||
ViewCompat.offsetTopAndBottom(mRefreshView, offset);
|
ViewCompat.offsetTopAndBottom(mRefreshView, offset);
|
||||||
mCurrentTargetOffsetTop = mRefreshView.getTop();
|
mCurrentTargetOffsetTop = mRefreshView.getTop();
|
||||||
if (mRefreshView.getMeasuredHeight() > 0) {
|
if (mRefreshView.getMeasuredHeight() > 0) {
|
||||||
mRefreshView.setProgressRotation((float) mRefreshView.getBottom() / (float) mRefreshView.getMeasuredHeight());
|
mRefreshView.setProgressRotation((float) mRefreshView.getBottom() / (float) mRefreshView.getMeasuredHeight() * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package pub.doric.shader;
|
package pub.doric.shader;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.ArgbEvaluator;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
@ -123,19 +128,72 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
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":
|
||||||
|
if (isAnimating()) {
|
||||||
|
addAnimator(ObjectAnimator.ofFloat(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
getWidth(),
|
||||||
|
prop.asNumber().toFloat()));
|
||||||
|
} else {
|
||||||
setWidth(prop.asNumber().toFloat());
|
setWidth(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "height":
|
case "height":
|
||||||
|
if (isAnimating()) {
|
||||||
|
addAnimator(ObjectAnimator.ofFloat(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
getHeight(),
|
||||||
|
prop.asNumber().toFloat()));
|
||||||
|
} else {
|
||||||
setHeight(prop.asNumber().toFloat());
|
setHeight(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "x":
|
case "x":
|
||||||
|
if (isAnimating()) {
|
||||||
|
addAnimator(ObjectAnimator.ofFloat(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
getX(),
|
||||||
|
prop.asNumber().toFloat()));
|
||||||
|
} else {
|
||||||
setX(prop.asNumber().toFloat());
|
setX(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "y":
|
case "y":
|
||||||
|
if (isAnimating()) {
|
||||||
|
addAnimator(ObjectAnimator.ofFloat(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
getY(),
|
||||||
|
prop.asNumber().toFloat()));
|
||||||
|
} else {
|
||||||
setY(prop.asNumber().toFloat());
|
setY(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "bgColor":
|
case "bgColor":
|
||||||
view.setBackgroundColor(prop.asNumber().toInt());
|
if (isAnimating()) {
|
||||||
|
ObjectAnimator animator = ObjectAnimator.ofInt(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
getBgColor(),
|
||||||
|
prop.asNumber().toInt());
|
||||||
|
animator.setEvaluator(new ArgbEvaluator());
|
||||||
|
addAnimator(animator);
|
||||||
|
} else {
|
||||||
|
setBgColor(prop.asNumber().toInt());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "rotation":
|
||||||
|
if (isAnimating()) {
|
||||||
|
addAnimator(ObjectAnimator.ofFloat(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
getRotation(),
|
||||||
|
prop.asNumber().toFloat()));
|
||||||
|
} else {
|
||||||
|
setRotation(prop.asNumber().toFloat());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "onClick":
|
case "onClick":
|
||||||
final String functionId = prop.asString().value();
|
final String functionId = prop.asString().value();
|
||||||
@ -244,30 +302,6 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
return mId;
|
return mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setWidth(float width) {
|
|
||||||
if (mLayoutParams.width >= 0) {
|
|
||||||
mLayoutParams.width = DoricUtils.dp2px(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setHeight(float height) {
|
|
||||||
if (mLayoutParams.height >= 0) {
|
|
||||||
mLayoutParams.height = DoricUtils.dp2px(height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setX(float x) {
|
|
||||||
if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
||||||
((ViewGroup.MarginLayoutParams) mLayoutParams).leftMargin = DoricUtils.dp2px(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setY(float y) {
|
|
||||||
if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
||||||
((ViewGroup.MarginLayoutParams) mLayoutParams).topMargin = DoricUtils.dp2px(y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setLayoutConfig(JSObject layoutConfig) {
|
protected void setLayoutConfig(JSObject layoutConfig) {
|
||||||
if (mSuperNode != null) {
|
if (mSuperNode != null) {
|
||||||
mSuperNode.blendSubLayoutConfig(this, layoutConfig);
|
mSuperNode.blendSubLayoutConfig(this, layoutConfig);
|
||||||
@ -329,30 +363,95 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DoricMethod
|
protected boolean isAnimating() {
|
||||||
public int getWidth() {
|
return getDoricContext().getAnimatorSet() != null;
|
||||||
return getNodeView().getWidth();
|
}
|
||||||
|
|
||||||
|
protected void addAnimator(Animator animator) {
|
||||||
|
if (getDoricContext().getAnimatorSet() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getDoricContext().getAnimatorSet().play(animator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DoricMethod
|
@DoricMethod
|
||||||
public int getHeight() {
|
public float getWidth() {
|
||||||
return getNodeView().getHeight();
|
return DoricUtils.px2dp(getNodeView().getWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@DoricMethod
|
@DoricMethod
|
||||||
public void setRotation(JSValue jsValue) {
|
public float getHeight() {
|
||||||
float rotation = jsValue.asNumber().toFloat();
|
return DoricUtils.px2dp(getNodeView().getHeight());
|
||||||
while (rotation > 1) {
|
|
||||||
rotation = rotation - 1;
|
|
||||||
}
|
}
|
||||||
while (rotation < -1) {
|
|
||||||
rotation = rotation + 1;
|
@DoricMethod
|
||||||
}
|
public void setRotation(float rotation) {
|
||||||
getNodeView().setRotation(rotation * 360);
|
getNodeView().setRotation(rotation * 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DoricMethod
|
@DoricMethod
|
||||||
public float getRotation() {
|
public float getRotation() {
|
||||||
return getNodeView().getRotation() / 360;
|
return getNodeView().getRotation() / 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
protected void setWidth(float width) {
|
||||||
|
if (mLayoutParams.width >= 0) {
|
||||||
|
mLayoutParams.width = DoricUtils.dp2px(width);
|
||||||
|
mView.requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
protected void setHeight(float height) {
|
||||||
|
if (mLayoutParams.height >= 0) {
|
||||||
|
mLayoutParams.height = DoricUtils.dp2px(height);
|
||||||
|
mView.requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
protected void setX(float x) {
|
||||||
|
if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
((ViewGroup.MarginLayoutParams) mLayoutParams).leftMargin = DoricUtils.dp2px(x);
|
||||||
|
mView.requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
protected void setY(float y) {
|
||||||
|
if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
((ViewGroup.MarginLayoutParams) mLayoutParams).topMargin = DoricUtils.dp2px(y);
|
||||||
|
mView.requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
public float getX() {
|
||||||
|
if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
return DoricUtils.px2dp(((ViewGroup.MarginLayoutParams) mLayoutParams).leftMargin);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
public float getY() {
|
||||||
|
if (mLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
||||||
|
return DoricUtils.px2dp(((ViewGroup.MarginLayoutParams) mLayoutParams).topMargin);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
public int getBgColor() {
|
||||||
|
if (mView.getBackground() instanceof ColorDrawable) {
|
||||||
|
return ((ColorDrawable) mView.getBackground()).getColor();
|
||||||
|
}
|
||||||
|
return Color.TRANSPARENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DoricMethod
|
||||||
|
public void setBgColor(int color) {
|
||||||
|
mView.setBackgroundColor(color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,6 @@ export default [
|
|||||||
'src/NavbarDemo',
|
'src/NavbarDemo',
|
||||||
'src/RefreshableDemo',
|
'src/RefreshableDemo',
|
||||||
'src/FlowLayoutDemo',
|
'src/FlowLayoutDemo',
|
||||||
'src/PopoverDemo'
|
'src/PopoverDemo',
|
||||||
|
'src/AnimatorDemo',
|
||||||
]
|
]
|
128
demo/src/AnimatorDemo.ts
Normal file
128
demo/src/AnimatorDemo.ts
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import { animate, Group, Panel, gravity, Color, LayoutSpec, vlayout, scroller, layoutConfig, IVLayout, modal, IText, network, View, stack, IHLayout, hlayout, IView, text } from "doric";
|
||||||
|
import { title, colors, box } from "./utils";
|
||||||
|
|
||||||
|
function thisLabel(str: string) {
|
||||||
|
return text({
|
||||||
|
text: str,
|
||||||
|
width: 100,
|
||||||
|
height: 50,
|
||||||
|
bgColor: colors[4],
|
||||||
|
textSize: 20,
|
||||||
|
textColor: Color.WHITE,
|
||||||
|
layoutConfig: layoutConfig().exactly(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entry
|
||||||
|
class AnimatorDemo extends Panel {
|
||||||
|
build(rootView: Group): void {
|
||||||
|
const view = box(2)
|
||||||
|
let idx = 0
|
||||||
|
vlayout([
|
||||||
|
title("Animator zDemo"),
|
||||||
|
vlayout(
|
||||||
|
[
|
||||||
|
hlayout([
|
||||||
|
thisLabel('Reset').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
view.width = view.height = 20
|
||||||
|
view.x = view.y = 0
|
||||||
|
view.rotation = 0
|
||||||
|
view.bgColor = colors[2]
|
||||||
|
},
|
||||||
|
duration: 1500,
|
||||||
|
}).then(() => {
|
||||||
|
modal(context).toast('Fininshed')
|
||||||
|
}).catch(e => {
|
||||||
|
modal(context).toast(`${e}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('Move X').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
view.x = view.x || 0
|
||||||
|
view.x += 100
|
||||||
|
},
|
||||||
|
duration: 1000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('Move Y').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
view.y = view.y || 0
|
||||||
|
view.y += 100
|
||||||
|
},
|
||||||
|
duration: 1000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]).apply({ space: 10 } as IHLayout),
|
||||||
|
hlayout([
|
||||||
|
thisLabel('Width').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
view.width += 100
|
||||||
|
},
|
||||||
|
duration: 1000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('Height').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
view.height += 100
|
||||||
|
},
|
||||||
|
duration: 1000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]).apply({ space: 10 } as IHLayout),
|
||||||
|
hlayout([
|
||||||
|
thisLabel('BgColor').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
view.bgColor = colors[(idx++) % colors.length]
|
||||||
|
},
|
||||||
|
duration: 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
thisLabel('Rotation').apply({
|
||||||
|
onClick: () => {
|
||||||
|
animate(this)({
|
||||||
|
animations: () => {
|
||||||
|
if (view.rotation) {
|
||||||
|
view.rotation += 0.5
|
||||||
|
} else {
|
||||||
|
view.rotation = 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
duration: 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]).apply({ space: 10 } as IHLayout),
|
||||||
|
]
|
||||||
|
).apply({ space: 10 } as IVLayout),
|
||||||
|
stack([
|
||||||
|
view
|
||||||
|
]).apply({
|
||||||
|
layoutConfig: layoutConfig().atmost(),
|
||||||
|
bgColor: colors[1].alpha(0.3 * 255),
|
||||||
|
}),
|
||||||
|
]).apply({
|
||||||
|
layoutConfig: layoutConfig().atmost(),
|
||||||
|
gravity: gravity().center(),
|
||||||
|
space: 10,
|
||||||
|
} as IVLayout).in(rootView)
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,11 @@ function fromDir(startPath, filter) {
|
|||||||
fromDir(filename, filter);
|
fromDir(filename, filter);
|
||||||
}
|
}
|
||||||
else if (filename.indexOf(filter) >= 0) {
|
else if (filename.indexOf(filter) >= 0) {
|
||||||
|
try {
|
||||||
doMerge(startPath, files[i])
|
doMerge(startPath, files[i])
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -82,6 +82,7 @@ - (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)reload:(NSString *)script {
|
- (void)reload:(NSString *)script {
|
||||||
|
self.rootNode.viewId = nil;
|
||||||
self.script = script;
|
self.script = script;
|
||||||
[self.driver createContext:self.contextId script:script source:self.source];
|
[self.driver createContext:self.contextId script:script source:self.source];
|
||||||
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
|
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#import "DoricFlowLayoutItemNode.h"
|
#import "DoricFlowLayoutItemNode.h"
|
||||||
#import "DoricFlowLayoutNode.h"
|
#import "DoricFlowLayoutNode.h"
|
||||||
#import "DoricPopoverPlugin.h"
|
#import "DoricPopoverPlugin.h"
|
||||||
|
#import "DoricAnimatePlugin.h"
|
||||||
|
|
||||||
@interface DoricRegistry ()
|
@interface DoricRegistry ()
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ - (void)innerRegister {
|
|||||||
[self registerNativePlugin:DoricNavigatorPlugin.class withName:@"navigator"];
|
[self registerNativePlugin:DoricNavigatorPlugin.class withName:@"navigator"];
|
||||||
[self registerNativePlugin:DoricNavBarPlugin.class withName:@"navbar"];
|
[self registerNativePlugin:DoricNavBarPlugin.class withName:@"navbar"];
|
||||||
[self registerNativePlugin:DoricPopoverPlugin.class withName:@"popover"];
|
[self registerNativePlugin:DoricPopoverPlugin.class withName:@"popover"];
|
||||||
|
[self registerNativePlugin:DoricAnimatePlugin.class withName:@"animate"];
|
||||||
|
|
||||||
[self registerViewNode:DoricStackNode.class withName:@"Stack"];
|
[self registerViewNode:DoricStackNode.class withName:@"Stack"];
|
||||||
[self registerViewNode:DoricVLayoutNode.class withName:@"VLayout"];
|
[self registerViewNode:DoricVLayoutNode.class withName:@"VLayout"];
|
||||||
|
10
iOS/Pod/Classes/Plugin/DoricAnimatePlugin.h
Normal file
10
iOS/Pod/Classes/Plugin/DoricAnimatePlugin.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//
|
||||||
|
// Created by pengfei.zhou on 2019/11/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "DoricNativePlugin.h"
|
||||||
|
|
||||||
|
@interface DoricAnimatePlugin : DoricNativePlugin
|
||||||
|
@end
|
33
iOS/Pod/Classes/Plugin/DoricAnimatePlugin.m
Normal file
33
iOS/Pod/Classes/Plugin/DoricAnimatePlugin.m
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by pengfei.zhou on 2019/11/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "DoricAnimatePlugin.h"
|
||||||
|
#import "DoricRootNode.h"
|
||||||
|
|
||||||
|
@implementation DoricAnimatePlugin
|
||||||
|
|
||||||
|
- (void)submit:(NSDictionary *)args withPromise:(DoricPromise *)promise {
|
||||||
|
[promise resolve:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)animateRender:(NSDictionary *)args withPromise:(DoricPromise *)promise {
|
||||||
|
NSNumber *duration = args[@"duration"];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
NSString *viewId = args[@"id"];
|
||||||
|
[UIView animateWithDuration:[duration floatValue] / 1000
|
||||||
|
animations:^{
|
||||||
|
if (self.doricContext.rootNode.viewId == nil) {
|
||||||
|
self.doricContext.rootNode.viewId = viewId;
|
||||||
|
[self.doricContext.rootNode blend:args[@"props"]];
|
||||||
|
} else {
|
||||||
|
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
|
||||||
|
[viewNode blend:args[@"props"]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completion:^(BOOL finished) {
|
||||||
|
[promise resolve:nil];
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@end
|
@ -23,7 +23,6 @@
|
|||||||
#import "DoricShaderPlugin.h"
|
#import "DoricShaderPlugin.h"
|
||||||
#import "DoricRootNode.h"
|
#import "DoricRootNode.h"
|
||||||
#import "DoricUtil.h"
|
#import "DoricUtil.h"
|
||||||
#import "Doric.h"
|
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL
|
|||||||
|
|
||||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||||
if (scrollView.contentOffset.y <= 0) {
|
if (scrollView.contentOffset.y <= 0) {
|
||||||
[self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height];
|
[self.swipePullingDelegate setProgressRotation:-scrollView.contentOffset.y / self.headerView.height * 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +123,8 @@ - (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop
|
|||||||
view.y = [(NSNumber *) prop floatValue];
|
view.y = [(NSNumber *) prop floatValue];
|
||||||
} else if ([name isEqualToString:@"bgColor"]) {
|
} else if ([name isEqualToString:@"bgColor"]) {
|
||||||
view.backgroundColor = DoricColor(prop);
|
view.backgroundColor = DoricColor(prop);
|
||||||
|
} else if ([name isEqualToString:@"rotation"]) {
|
||||||
|
[self setRotation:prop];
|
||||||
} else if ([name isEqualToString:@"layoutConfig"]) {
|
} else if ([name isEqualToString:@"layoutConfig"]) {
|
||||||
if (self.superNode && [prop isKindOfClass:[NSDictionary class]]) {
|
if (self.superNode && [prop isKindOfClass:[NSDictionary class]]) {
|
||||||
[self.superNode blendSubNode:self layoutConfig:prop];
|
[self.superNode blendSubNode:self layoutConfig:prop];
|
||||||
@ -238,13 +240,13 @@ - (void)setRotation:(NSNumber *)rotation {
|
|||||||
if (rotation.floatValue == 0) {
|
if (rotation.floatValue == 0) {
|
||||||
self.view.transform = CGAffineTransformIdentity;
|
self.view.transform = CGAffineTransformIdentity;
|
||||||
} else {
|
} else {
|
||||||
self.view.transform = CGAffineTransformMakeRotation(M_PI * rotation.floatValue * 2);
|
self.view.transform = CGAffineTransformMakeRotation(M_PI * rotation.floatValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSNumber *)getRotation {
|
- (NSNumber *)getRotation {
|
||||||
float radius = atan2f((float) self.view.transform.b, (float) self.view.transform.a);
|
float radius = atan2f((float) self.view.transform.b, (float) self.view.transform.a);
|
||||||
float degree = (float) (radius / M_PI / 2);
|
float degree = (float) (radius / M_PI);
|
||||||
return @(degree);
|
return @(degree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
js-framework/src/native/animate.ts
Normal file
48
js-framework/src/native/animate.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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 { Panel } from "../ui/panel"
|
||||||
|
import { takeLet } from "../pattern/candies"
|
||||||
|
|
||||||
|
export function animate(panel: Panel) {
|
||||||
|
return (args: {
|
||||||
|
animations: () => void,
|
||||||
|
duration: number,
|
||||||
|
}) => {
|
||||||
|
return takeLet(panel.context.animate)(it => {
|
||||||
|
return it.submit().then(() => {
|
||||||
|
args.animations()
|
||||||
|
return takeLet(panel.getRootView())(root => {
|
||||||
|
if (root.isDirty()) {
|
||||||
|
const model = root.toModel();
|
||||||
|
(model as any).duration = args.duration
|
||||||
|
const ret = it.animateRender(model)
|
||||||
|
root.clean()
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
for (let v of panel.allHeadViews()) {
|
||||||
|
if (v.isDirty()) {
|
||||||
|
const model = v.toModel()
|
||||||
|
const ret = it.animateRender(model)
|
||||||
|
it.clean()
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('Cannot find any animated elements')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}) as Promise<any>
|
||||||
|
}
|
||||||
|
}
|
@ -19,3 +19,4 @@ export * from './navigator'
|
|||||||
export * from './network'
|
export * from './network'
|
||||||
export * from './storage'
|
export * from './storage'
|
||||||
export * from './popover'
|
export * from './popover'
|
||||||
|
export * from './animate'
|
||||||
|
154
js-framework/src/ui/animation.ts
Normal file
154
js-framework/src/ui/animation.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* 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 enum RepeatMode {
|
||||||
|
RESTART,
|
||||||
|
REVERSE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Animation {
|
||||||
|
duration = 100
|
||||||
|
startDelay = 0
|
||||||
|
repeatCount = 1
|
||||||
|
repeatMode = RepeatMode.RESTART
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AnimationSetBuilder {
|
||||||
|
currentNode: Node
|
||||||
|
group: AnimationSet
|
||||||
|
|
||||||
|
constructor(group: AnimationSet, anim: Animation) {
|
||||||
|
this.currentNode = group.getNodeForAnimation(anim)
|
||||||
|
this.group = group
|
||||||
|
}
|
||||||
|
|
||||||
|
with(animation: Animation) {
|
||||||
|
const node = this.group.getNodeForAnimation(animation)
|
||||||
|
this.currentNode.addSibling(node)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
after(animation: Animation) {
|
||||||
|
const node = this.group.getNodeForAnimation(animation)
|
||||||
|
this.currentNode.addParent(node)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
before(animation: Animation) {
|
||||||
|
const node = this.group.getNodeForAnimation(animation)
|
||||||
|
this.currentNode.addChild(node)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Node {
|
||||||
|
children: Set<Node> = new Set
|
||||||
|
siblings: Set<Node> = new Set
|
||||||
|
parents: Set<Node> = new Set
|
||||||
|
animation: Animation
|
||||||
|
built = false
|
||||||
|
|
||||||
|
constructor(anim: Animation) {
|
||||||
|
this.animation = anim
|
||||||
|
}
|
||||||
|
|
||||||
|
addParent(node: Node) {
|
||||||
|
if (!this.parents.has(node)) {
|
||||||
|
this.parents.add(node);
|
||||||
|
node.addChild(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addSibling(node: Node) {
|
||||||
|
if (!this.siblings.has(node)) {
|
||||||
|
this.siblings.add(node);
|
||||||
|
node.addSibling(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(node: Node) {
|
||||||
|
if (!this.children.has(node)) {
|
||||||
|
this.children.add(node)
|
||||||
|
node.addParent(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class AnimationSet {
|
||||||
|
nodeMap: Map<Animation, Node> = new Map
|
||||||
|
nodes: Node[] = []
|
||||||
|
|
||||||
|
getNodeForAnimation(anim: Animation) {
|
||||||
|
let node = this.nodeMap.get(anim)
|
||||||
|
if (node === undefined) {
|
||||||
|
node = new Node(anim)
|
||||||
|
this.nodeMap.set(anim, node)
|
||||||
|
this.nodes.push(node)
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
play(animation: Animation) {
|
||||||
|
return new AnimationSetBuilder(this, animation)
|
||||||
|
}
|
||||||
|
|
||||||
|
playTogether(animations: Animation[]) {
|
||||||
|
if (animations.length == 1) {
|
||||||
|
this.play(animations[0]);
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < animations.length - 1; i++) {
|
||||||
|
this.play(animations[i]).with(animations[i + 1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playSequentially(animations: Animation[]) {
|
||||||
|
if (animations.length == 1) {
|
||||||
|
this.play(animations[0]);
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < animations.length - 1; i++) {
|
||||||
|
this.play(animations[i]).before(animations[i + 1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
findSiblings(node: Node, siblings: Set<Node>) {
|
||||||
|
if (!siblings.has(node)) {
|
||||||
|
siblings.add(node)
|
||||||
|
node.siblings.forEach(e => {
|
||||||
|
this.findSiblings(e, siblings)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createDependencyGraph() {
|
||||||
|
this.nodes.forEach(node => {
|
||||||
|
if (node.built) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.findSiblings(node, node.siblings)
|
||||||
|
node.siblings.delete(node)
|
||||||
|
node.siblings.forEach(e => {
|
||||||
|
e.parents.forEach(p => {
|
||||||
|
node.addParent(p)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
node.built = true
|
||||||
|
|
||||||
|
node.siblings.forEach(s => {
|
||||||
|
node.parents.forEach(p => {
|
||||||
|
s.addParent(p)
|
||||||
|
})
|
||||||
|
s.built = true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -15,3 +15,4 @@
|
|||||||
*/
|
*/
|
||||||
export * from './view'
|
export * from './view'
|
||||||
export * from './panel'
|
export * from './panel'
|
||||||
|
export * from './animation'
|
@ -49,7 +49,9 @@ export abstract class Panel {
|
|||||||
addHeadView(v: View) {
|
addHeadView(v: View) {
|
||||||
this.headviews.set(v.viewId, v)
|
this.headviews.set(v.viewId, v)
|
||||||
}
|
}
|
||||||
|
allHeadViews() {
|
||||||
|
return this.headviews.values()
|
||||||
|
}
|
||||||
removeHeadView(v: View | string) {
|
removeHeadView(v: View | string) {
|
||||||
if (v instanceof View) {
|
if (v instanceof View) {
|
||||||
this.headviews.delete(v.viewId)
|
this.headviews.delete(v.viewId)
|
||||||
|
@ -61,6 +61,9 @@ export abstract class View implements Modeling, IView {
|
|||||||
@Property
|
@Property
|
||||||
bgColor?: Color | GradientColor
|
bgColor?: Color | GradientColor
|
||||||
|
|
||||||
|
@Property
|
||||||
|
rotation?: number
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
corners?: number | { leftTop?: number; rightTop?: number; leftBottom?: number; rightBottom?: number }
|
corners?: number | { leftTop?: number; rightTop?: number; leftBottom?: number; rightBottom?: number }
|
||||||
|
|
||||||
|
@ -62,6 +62,10 @@ export class Color implements Modeling {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alpha(v: number) {
|
||||||
|
return new Color((this._value & 0xffffff) | ((v & 0xff) << 24))
|
||||||
|
}
|
||||||
|
|
||||||
toModel() {
|
toModel() {
|
||||||
return this._value
|
return this._value
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user