feat:refact render child in groupNode

This commit is contained in:
pengfei.zhou 2019-11-14 17:57:12 +08:00
parent 74d31edc26
commit d2f4302e42
6 changed files with 155 additions and 138 deletions

View File

@ -16,6 +16,7 @@
package pub.doric.plugin; package pub.doric.plugin;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.async.AsyncResult;
import pub.doric.extension.bridge.DoricMethod; import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin; import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.utils.DoricLog; import pub.doric.utils.DoricLog;
@ -49,7 +50,23 @@ public class ShaderPlugin extends DoricJavaPlugin {
rootNode.render(jsObject.getProperty("props").asObject()); rootNode.render(jsObject.getProperty("props").asObject());
return null; return null;
} }
}, ThreadMode.UI); }, 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());
}
@Override
public void onFinish() {
}
});
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
DoricLog.e("Shader.render:error%s", e.getLocalizedMessage()); DoricLog.e("Shader.render:error%s", e.getLocalizedMessage());

View File

@ -15,7 +15,6 @@
*/ */
package pub.doric.shader; package pub.doric.shader;
import android.util.SparseArray;
import android.view.ViewGroup; import android.view.ViewGroup;
import pub.doric.DoricContext; import pub.doric.DoricContext;
@ -25,9 +24,6 @@ import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* @Description: com.github.penfeizhou.doric.widget * @Description: com.github.penfeizhou.doric.widget
@ -35,8 +31,8 @@ import java.util.Map;
* @CreateDate: 2019-07-20 * @CreateDate: 2019-07-20
*/ */
public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> { public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
private Map<String, ViewNode> mChildrenNode = new HashMap<>(); private ArrayList<ViewNode> mChildNodes = new ArrayList<>();
private SparseArray<ViewNode> mIndexInfo = new SparseArray<>(); private ArrayList<String> mChildViewIds = new ArrayList<>();
public GroupNode(DoricContext doricContext) { public GroupNode(DoricContext doricContext) {
super(doricContext); super(doricContext);
@ -45,80 +41,90 @@ public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
@Override @Override
protected void blend(F view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) { protected void blend(F view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) {
if ("children".equals(name)) { if ("children".equals(name)) {
JSArray jsArray = prop.asArray(); JSArray ids = prop.asArray();
int i; mChildViewIds.clear();
List<ViewNode> tobeRemoved = new ArrayList<>(); for (int i = 0; i < ids.size(); i++) {
for (i = 0; i < jsArray.size(); i++) { mChildViewIds.add(ids.get(i).asString().value());
JSValue jsValue = jsArray.get(i);
if (!jsValue.isObject()) {
continue;
}
JSObject childObj = jsValue.asObject();
String type = childObj.getProperty("type").asString().value();
String id = childObj.getProperty("id").asString().value();
ViewNode child = mChildrenNode.get(id);
if (child == null) {
child = ViewNode.create(getDoricContext(), type);
child.index = i;
child.mSuperNode = this;
child.mId = id;
mChildrenNode.put(id, child);
} else {
if (i != child.index) {
mIndexInfo.remove(i);
child.index = i;
mView.removeView(child.getDoricLayer());
}
tobeRemoved.remove(child);
}
ViewNode node = mIndexInfo.get(i);
if (node != null && node != child) {
mView.removeViewAt(i);
mIndexInfo.remove(i);
tobeRemoved.add(node);
}
ViewGroup.LayoutParams params = child.getLayoutParams();
if (params == null) {
params = generateDefaultLayoutParams();
}
child.blend(childObj.getProperty("props").asObject(), params);
if (mIndexInfo.get(i) == null) {
mView.addView(child.getDoricLayer(), i, child.getLayoutParams());
mIndexInfo.put(i, child);
}
} }
int count = mView.getChildCount();
while (i < count) {
ViewNode node = mIndexInfo.get(i);
if (node != null) {
mChildrenNode.remove(node.getId());
mIndexInfo.remove(i);
tobeRemoved.remove(node);
mView.removeView(node.getDoricLayer());
}
i++;
}
for (ViewNode node : tobeRemoved) {
mChildrenNode.remove(node.getId());
}
} else if ("subviews".equals(name)) {
// Currently do nothing,because its subview always contained in props.children
// super.blend(view, layoutParams, name, prop);
} else { } else {
super.blend(view, layoutParams, name, prop); super.blend(view, layoutParams, name, prop);
} }
} }
@Override
public void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) {
super.blend(jsObject, layoutParams);
configChildNode();
}
private void configChildNode() {
for (int idx = 0; idx < mChildViewIds.size(); idx++) {
String id = mChildViewIds.get(idx);
JSObject model = getSubModel(id);
String type = model.getProperty("type").asString().value();
if (idx < mChildNodes.size()) {
ViewNode oldNode = mChildNodes.get(idx);
if (id.equals(oldNode.getId())) {
//The same,skip
} else {
//Find in remaining nodes
int position = -1;
for (int start = idx + 1; start < mChildNodes.size(); start++) {
ViewNode node = mChildNodes.get(start);
if (id.equals(node.getId())) {
//Found
position = start;
break;
}
}
if (position >= 0) {
//Found swap idx,position
ViewNode reused = mChildNodes.remove(position);
ViewNode abandoned = mChildNodes.remove(idx);
mChildNodes.set(idx, reused);
mChildNodes.set(position, abandoned);
//View swap index
mView.removeView(reused.getDoricLayer());
mView.addView(reused.getDoricLayer(), idx);
mView.removeView(abandoned.getDoricLayer());
mView.addView(abandoned.getDoricLayer(), position);
} else {
//Not found,insert
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setSuperNode(this);
newNode.setId(id);
ViewGroup.LayoutParams params = generateDefaultLayoutParams();
newNode.blend(model.getProperty("props").asObject(), params);
mChildNodes.set(idx, newNode);
mView.addView(newNode.getDoricLayer(), idx, newNode.getLayoutParams());
}
}
} else {
//Insert
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setSuperNode(this);
newNode.setId(id);
ViewGroup.LayoutParams params = generateDefaultLayoutParams();
newNode.blend(model.getProperty("props").asObject(), params);
mChildNodes.add(newNode);
mView.addView(newNode.getDoricLayer(), idx, newNode.getLayoutParams());
}
}
int size = mChildNodes.size();
for (int idx = mChildViewIds.size(); idx < size; idx++) {
ViewNode viewNode = mChildNodes.remove(mChildViewIds.size());
mView.removeView(viewNode.getDoricLayer());
}
}
@Override @Override
protected void blendSubNode(JSObject subProp) { protected void blendSubNode(JSObject subProp) {
String subNodeId = subProp.getProperty("id").asString().value(); String subNodeId = subProp.getProperty("id").asString().value();
for (ViewNode node : mChildrenNode.values()) { for (ViewNode node : mChildNodes) {
if (subNodeId.equals(node.getId())) { if (subNodeId.equals(node.getId())) {
node.blend(subProp, node.getLayoutParams()); node.blend(subProp.getProperty("props").asObject(), node.getLayoutParams());
break;
} }
} }
} }

View File

@ -22,6 +22,9 @@ import com.github.pengfeizhou.jscore.JSArray;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
import java.util.HashMap;
import java.util.Map;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.utils.DoricUtils; import pub.doric.utils.DoricUtils;
@ -31,6 +34,8 @@ import pub.doric.utils.DoricUtils;
* @CreateDate: 2019-11-13 * @CreateDate: 2019-11-13
*/ */
public abstract class SuperNode<V extends View> extends ViewNode<V> { public abstract class SuperNode<V extends View> extends ViewNode<V> {
private Map<String, JSObject> subNodes = new HashMap<>();
public SuperNode(DoricContext doricContext) { public SuperNode(DoricContext doricContext) {
super(doricContext); super(doricContext);
} }
@ -42,16 +47,33 @@ public abstract class SuperNode<V extends View> extends ViewNode<V> {
@Override @Override
protected void blend(V view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) { protected void blend(V view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) {
if (name.equals("subviews")) { if (name.equals("subviews")) {
JSArray subviews = prop.asArray(); if (prop.isArray()) {
for (int i = 0; i < subviews.size(); i++) { JSArray subviews = prop.asArray();
JSObject subProp = subviews.get(i).asObject(); for (int i = 0; i < subviews.size(); i++) {
blendSubNode(subProp); JSObject subNode = subviews.get(i).asObject();
mixinSubNode(subNode);
blendSubNode(subNode);
}
} }
} else { } else {
super.blend(view, layoutParams, name, prop); super.blend(view, layoutParams, name, prop);
} }
} }
private void mixinSubNode(JSObject subNode) {
String id = subNode.getProperty("id").asString().value();
JSObject targetNode = subNodes.get(id);
if (targetNode == null) {
subNodes.put(id, subNode);
} else {
mixin(subNode, targetNode);
}
}
public JSObject getSubModel(String id) {
return subNodes.get(id);
}
protected abstract void blendSubNode(JSObject subProperties); protected abstract void blendSubNode(JSObject subProperties);
protected void blendSubLayoutConfig(ViewNode viewNode, JSObject jsObject) { protected void blendSubLayoutConfig(ViewNode viewNode, JSObject jsObject) {
@ -70,7 +92,6 @@ public abstract class SuperNode<V extends View> extends ViewNode<V> {
break; break;
default: default:
break; break;
} }
} }
if (heightSpec.isNumber()) { if (heightSpec.isNumber()) {
@ -104,4 +125,37 @@ public abstract class SuperNode<V extends View> extends ViewNode<V> {
} }
} }
} }
private void mixin(JSObject src, JSObject target) {
JSValue srcProps = src.getProperty("props");
JSValue targetProps = target.getProperty("props");
if (srcProps.isObject()) {
if (targetProps.isObject()) {
for (String key : srcProps.asObject().propertySet()) {
JSValue jsValue = srcProps.asObject().getProperty(key);
if ("children".equals(key) && jsValue.isArray()) {
JSValue targetChildren = targetProps.asObject().getProperty("children");
if (targetChildren.isArray() && targetChildren.asArray().size() == jsValue.asArray().size()) {
for (int i = 0; i < jsValue.asArray().size(); i++) {
JSValue childSrc = jsValue.asArray().get(i);
JSValue childTarget = targetChildren.asArray().get(i);
if (childSrc.isObject()) {
if (childTarget.isObject()) {
mixin(childSrc.asObject(), childTarget.asObject());
} else {
targetChildren.asArray().put(i, childSrc);
}
}
}
}
continue;
}
targetProps.asObject().setProperty(key, jsValue);
}
} else {
target.setProperty("props", srcProps);
}
}
}
} }

View File

@ -27,9 +27,6 @@ import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
import org.json.JSONObject;
import pub.doric.async.AsyncResult; import pub.doric.async.AsyncResult;
import pub.doric.shader.ViewNode; import pub.doric.shader.ViewNode;
@ -111,54 +108,9 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
void blendSubNode(JSObject subProperties) { void blendSubNode(JSObject subProperties) {
String subNodeId = subProperties.getProperty("id").asString().value();
for (int i = 0; i < itemValues.size(); i++) {
JSValue jsValue = itemValues.valueAt(i);
if (jsValue.isObject()) {
JSObject jsObject = jsValue.asObject();
if (subNodeId.equals(jsObject.getProperty("id").asString().value())) {
mixin(subProperties, jsObject);
int position = itemValues.keyAt(i);
notifyItemChanged(position);
break;
}
}
}
}
private void mixin(JSObject src, JSObject target) {
JSValue srcProps = src.getProperty("props");
JSValue targetProps = target.getProperty("props");
if (srcProps.isObject()) {
if (targetProps.isObject()) {
for (String key : srcProps.asObject().propertySet()) {
JSValue jsValue = srcProps.asObject().getProperty(key);
if ("children".equals(key) && jsValue.isArray()) {
JSValue targetChildren = targetProps.asObject().getProperty("children");
if (targetChildren.isArray() && targetChildren.asArray().size() == jsValue.asArray().size()) {
for (int i = 0; i < jsValue.asArray().size(); i++) {
JSValue childSrc = jsValue.asArray().get(i);
JSValue childTarget = targetChildren.asArray().get(i);
if (childSrc.isObject()) {
if (childTarget.isObject()) {
mixin(childSrc.asObject(), childTarget.asObject());
} else {
targetChildren.asArray().put(i, childSrc);
}
}
}
}
continue;
}
targetProps.asObject().setProperty(key, jsValue);
}
} else {
target.setProperty("props", srcProps);
}
}
} }
static class DoricViewHolder extends RecyclerView.ViewHolder { static class DoricViewHolder extends RecyclerView.ViewHolder {
ListItemNode listItemNode; ListItemNode listItemNode;

View File

@ -70,7 +70,7 @@ export class List extends Superview implements IList {
private renderBunchedItems(start: number, length: number) { private renderBunchedItems(start: number, length: number) {
return new Array(Math.min(length, this.itemCount - start)).fill(0).map((_, idx) => { return new Array(Math.min(length, this.itemCount - start)).fill(0).map((_, idx) => {
const listItem = this.getItem(start + idx) const listItem = this.getItem(start + idx)
return listItem.toModel() return listItem.viewId
}) })
} }
} }

View File

@ -303,7 +303,7 @@ export abstract class Group extends Superview {
set: (target, index, value) => { set: (target, index, value) => {
const ret = Reflect.set(target, index, value) const ret = Reflect.set(target, index, value)
// Let getDirty return true // Let getDirty return true
this.dirtyProps.children = [] this.dirtyProps.children = this.children.map(e => e.viewId)
return ret return ret
} }
}) })
@ -315,17 +315,5 @@ export abstract class Group extends Superview {
addChild(view: View) { addChild(view: View) {
this.children.push(view) this.children.push(view)
} }
toModel() {
this.dirtyProps.children = this.children.map(e => {
if (e.isDirty()) {
return e.toModel()
} else {
//Dont need return model
return undefined
}
})
return this.nativeViewModel
}
} }