add ListView DEMO ,show

This commit is contained in:
pengfei.zhou 2019-11-13 16:32:52 +08:00
parent eea7eb5d27
commit 6bf224aa9a
17 changed files with 167 additions and 39 deletions

View File

@ -49,7 +49,6 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
doricContext = DoricContext.create(this, DoricUtils.readAssetFile("demo/Snake.js"), "test"); doricContext = DoricContext.create(this, DoricUtils.readAssetFile("demo/Snake.js"), "test");
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
// doricContext.callEntity("log");
doricContext.getRootNode().setRootView((FrameLayout) findViewById(R.id.root)); doricContext.getRootNode().setRootView((FrameLayout) findViewById(R.id.root));
LocalServer localServer = new LocalServer(getApplicationContext(), 8910); LocalServer localServer = new LocalServer(getApplicationContext(), 8910);

View File

@ -20,6 +20,7 @@ import android.text.TextUtils;
import pub.doric.plugin.ShaderPlugin; import pub.doric.plugin.ShaderPlugin;
import pub.doric.shader.HLayoutNode; import pub.doric.shader.HLayoutNode;
import pub.doric.shader.ImageNode; import pub.doric.shader.ImageNode;
import pub.doric.shader.list.ListItemNode;
import pub.doric.shader.list.ListNode; import pub.doric.shader.list.ListNode;
import pub.doric.shader.RootNode; import pub.doric.shader.RootNode;
import pub.doric.shader.StackNode; import pub.doric.shader.StackNode;
@ -68,6 +69,7 @@ public class DoricRegistry {
this.registerViewNode(VLayoutNode.class); this.registerViewNode(VLayoutNode.class);
this.registerViewNode(HLayoutNode.class); this.registerViewNode(HLayoutNode.class);
this.registerViewNode(ListNode.class); this.registerViewNode(ListNode.class);
this.registerViewNode(ListItemNode.class);
initRegistry(this); initRegistry(this);
} }

View File

@ -64,6 +64,15 @@ public class SettableFuture<T> {
return mResult; return mResult;
} }
public T get() {
try {
mReadyLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return mResult;
}
public static class TimeoutException extends RuntimeException { public static class TimeoutException extends RuntimeException {
public TimeoutException() { public TimeoutException() {

View File

@ -197,7 +197,7 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
values.add(DoricUtils.toJavaValue(arg)); values.add(DoricUtils.toJavaValue(arg));
} }
return mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method, return mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method,
values.toArray(new JavaValue[values.size()]), true); values.toArray(new JavaValue[values.size()]), false);
} }
@Override @Override

View File

@ -41,7 +41,7 @@ public class RemoteJSExecutor {
.readTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS)
.build(); .build();
final Request request = new Request.Builder().url("ws://192.168.25.175:2080").build(); final Request request = new Request.Builder().url("ws://192.168.24.79:2080").build();
final Thread current = Thread.currentThread(); final Thread current = Thread.currentThread();
webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() { webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {

View File

@ -68,7 +68,7 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
if (i != child.index) { if (i != child.index) {
mIndexInfo.remove(i); mIndexInfo.remove(i);
child.index = i; child.index = i;
mView.removeView(child.getView()); mView.removeView(child.getDoricLayer());
} }
tobeRemoved.remove(child); tobeRemoved.remove(child);
} }
@ -87,7 +87,7 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
} }
child.blend(childObj.getProperty("props").asObject(), params); child.blend(childObj.getProperty("props").asObject(), params);
if (mIndexInfo.get(i) == null) { if (mIndexInfo.get(i) == null) {
mView.addView(child.getView(), i, child.getLayoutParams()); mView.addView(child.getDoricLayer(), i, child.getLayoutParams());
mIndexInfo.put(i, child); mIndexInfo.put(i, child);
} }
} }
@ -98,7 +98,7 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
mChildrenNode.remove(node.getId()); mChildrenNode.remove(node.getId());
mIndexInfo.remove(i); mIndexInfo.remove(i);
tobeRemoved.remove(node); tobeRemoved.remove(node);
mView.removeView(node.getView()); mView.removeView(node.getDoricLayer());
} }
i++; i++;
} }

View File

@ -36,7 +36,7 @@ public class RootNode extends StackNode {
} }
@Override @Override
public View getView() { public View getDoricLayer() {
return mView; return mView;
} }

View File

@ -22,11 +22,13 @@ import android.widget.FrameLayout;
import pub.doric.DoricContext; import pub.doric.DoricContext;
import pub.doric.DoricRegistry; import pub.doric.DoricRegistry;
import pub.doric.async.AsyncResult;
import pub.doric.utils.DoricContextHolder; import pub.doric.utils.DoricContextHolder;
import pub.doric.utils.DoricConstant; import pub.doric.utils.DoricConstant;
import pub.doric.utils.DoricMetaInfo; import pub.doric.utils.DoricMetaInfo;
import pub.doric.utils.DoricUtils; import pub.doric.utils.DoricUtils;
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;
@ -40,7 +42,7 @@ import java.util.LinkedList;
public abstract class ViewNode<T extends View> extends DoricContextHolder { public abstract class ViewNode<T extends View> extends DoricContextHolder {
protected T mView; protected T mView;
int index; int index;
GroupNode mParent; ViewNode mParent;
String mId; String mId;
private ViewGroup.LayoutParams mLayoutParams; private ViewGroup.LayoutParams mLayoutParams;
@ -50,7 +52,11 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
private DoricLayer doricLayer; private DoricLayer doricLayer;
public View getView() { public void setParentNode(ViewNode parentNode) {
mParent = parentNode;
}
public View getDoricLayer() {
return doricLayer; return doricLayer;
} }
@ -60,18 +66,20 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
protected abstract T build(JSObject jsObject); protected abstract T build(JSObject jsObject);
void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) { public void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) {
mLayoutParams = layoutParams; mLayoutParams = layoutParams;
if (mView == null) { if (mView == null) {
mView = build(jsObject); mView = build(jsObject);
} }
if (getView() == null) { if (getDoricLayer() == null) {
doricLayer = new DoricLayer(getContext()); doricLayer = new DoricLayer(getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(layoutParams.width, layoutParams.height); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(layoutParams.width, layoutParams.height);
doricLayer.addView(mView, params); doricLayer.addView(mView, params);
} }
for (String prop : jsObject.propertySet()) { if (jsObject != null) {
blend(mView, layoutParams, prop, jsObject.getProperty(prop)); for (String prop : jsObject.propertySet()) {
blend(mView, layoutParams, prop, jsObject.getProperty(prop));
}
} }
ViewGroup.LayoutParams params = mView.getLayoutParams(); ViewGroup.LayoutParams params = mView.getLayoutParams();
if (params != null) { if (params != null) {
@ -120,8 +128,8 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
}); });
break; break;
case "layoutConfig": case "layoutConfig":
if (prop.isObject() && mParent != null) { if (prop.isObject() && mParent instanceof GroupNode) {
mParent.blendChild(this, prop.asObject()); ((GroupNode) mParent).blendChild(this, prop.asObject());
} }
break; break;
case "border": case "border":
@ -178,14 +186,14 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
return ids.toArray(new String[0]); return ids.toArray(new String[0]);
} }
public void callJSResponse(String funcId, Object... args) { public AsyncResult<JSDecoder> callJSResponse(String funcId, Object... args) {
final Object[] nArgs = new Object[args.length + 2]; final Object[] nArgs = new Object[args.length + 2];
nArgs[0] = getIdList(); nArgs[0] = getIdList();
nArgs[1] = funcId; nArgs[1] = funcId;
if (args.length > 0) { if (args.length > 0) {
System.arraycopy(args, 0, nArgs, 2, args.length); System.arraycopy(args, 0, nArgs, 2, args.length);
} }
getDoricContext().callEntity(DoricConstant.DORIC_ENTITY_RESPONSE, nArgs); return getDoricContext().callEntity(DoricConstant.DORIC_ENTITY_RESPONSE, nArgs);
} }
public static ViewNode create(DoricContext doricContext, String type) { public static ViewNode create(DoricContext doricContext, String type) {

View File

@ -22,7 +22,12 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
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 pub.doric.async.AsyncResult;
import pub.doric.shader.ViewNode;
/** /**
* @Description: com.github.penfeizhou.doric.widget * @Description: com.github.penfeizhou.doric.widget
@ -33,7 +38,7 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
private final ListNode listNode; private final ListNode listNode;
String renderItemFuncId; String renderItemFuncId;
String renderBunchedItemsFuncId; private final String renderBunchedItemsFuncId = "renderBunchedItems";
int itemCount = 0; int itemCount = 0;
int batchCount = 15; int batchCount = 15;
private SparseArray<JSObject> itemObjects = new SparseArray<>(); private SparseArray<JSObject> itemObjects = new SparseArray<>();
@ -45,12 +50,15 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
@NonNull @NonNull
@Override @Override
public DoricViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public DoricViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null; ListItemNode node = (ListItemNode) ViewNode.create(listNode.getDoricContext(), "ListItem");
node.setParentNode(listNode);
return new DoricViewHolder(node, node.getDoricLayer());
} }
@Override @Override
public void onBindViewHolder(@NonNull DoricViewHolder holder, int position) { public void onBindViewHolder(@NonNull DoricViewHolder holder, int position) {
JSObject jsObject = getItemModel(position);
holder.listItemNode.blend(jsObject.getProperty("props").asObject(), holder.itemView.getLayoutParams());
} }
@Override @Override
@ -60,18 +68,44 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
JSValue value = getItemModel(position).getProperty("identifier");
if (value.isString()) {
return value.asString().hashCode();
}
return super.getItemViewType(position); return super.getItemViewType(position);
} }
private JSObject getItemModel(int position) {
private void jsCallRenderItem() { JSObject itemModel = itemObjects.get(position);
listNode.callJSResponse(renderItemFuncId); if (itemModel == null) {
AsyncResult<JSDecoder> asyncResult = listNode.callJSResponse(
renderBunchedItemsFuncId,
position,
batchCount);
try {
JSDecoder jsDecoder = asyncResult.synchronous().get();
JSValue result = jsDecoder.decode();
if (result.isArray()) {
JSValue[] values = result.asArray().toArray();
for (int i = 0; i < values.length; i++) {
itemObjects.put(i + position, values[i].asObject());
}
return values[0].asObject();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return itemModel;
} }
public static class DoricViewHolder extends RecyclerView.ViewHolder { static class DoricViewHolder extends RecyclerView.ViewHolder {
public DoricViewHolder(@NonNull View itemView) { ListItemNode listItemNode;
public DoricViewHolder(ListItemNode node, @NonNull View itemView) {
super(itemView); super(itemView);
listItemNode = node;
} }
} }
} }

View File

@ -0,0 +1,53 @@
/*
* 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.
*/
package pub.doric.shader.list;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.github.pengfeizhou.jscore.JSValue;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.shader.StackNode;
/**
* @Description: com.github.penfeizhou.doric.widget
* @Author: pengfei.zhou
* @CreateDate: 2019-11-12
*/
@DoricPlugin(name = "ListItem")
public class ListItemNode extends StackNode {
public String identifier = "";
public ListItemNode(DoricContext doricContext) {
super(doricContext);
this.mView = this.build(null);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
this.blend(null, params);
getDoricLayer().setLayoutParams(params);
}
@Override
protected void blend(FrameLayout view, ViewGroup.LayoutParams layoutParams, String name, JSValue prop) {
if ("identifier".equals(name)) {
this.identifier = prop.asString().value();
} else {
super.blend(view, layoutParams, name, prop);
}
}
}

View File

@ -17,6 +17,7 @@ package pub.doric.shader.list;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
@ -42,7 +43,23 @@ public class ListNode extends ViewNode<RecyclerView> {
@Override @Override
protected RecyclerView build(JSObject jsObject) { protected RecyclerView build(JSObject jsObject) {
return new RecyclerView(getContext()); RecyclerView recyclerView = new RecyclerView(getContext());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(this.listAdapter);
return recyclerView;
}
@Override
public void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) {
super.blend(jsObject, layoutParams);
if (mView != null) {
mView.post(new Runnable() {
@Override
public void run() {
listAdapter.notifyDataSetChanged();
}
});
}
} }
@Override @Override
@ -54,9 +71,6 @@ public class ListNode extends ViewNode<RecyclerView> {
case "renderItem": case "renderItem":
this.listAdapter.renderItemFuncId = prop.asString().value(); this.listAdapter.renderItemFuncId = prop.asString().value();
break; break;
case "renderBunchedItemsFuncId":
this.listAdapter.renderBunchedItemsFuncId = prop.asString().value();
break;
case "batchCount": case "batchCount":
this.listAdapter.batchCount = 15; this.listAdapter.batchCount = 15;
break; break;

View File

@ -14,4 +14,9 @@ org.gradle.jvmargs=-Xmx1536m
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
# To re-enable the build cache, either delete the following
# line or set the property to 'true'.
android.enableBuildCache=false

View File

@ -1,4 +1,4 @@
import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, ListItem } from "doric"; import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, ListItem, NativeCall } from "doric";
@Entry @Entry
class ListPanel extends Panel { class ListPanel extends Panel {
@ -22,5 +22,4 @@ class ListPanel extends Panel {
return item return item
} }
} }
} }

View File

@ -230,6 +230,7 @@ export function jsCallEntityMethod(contextId: string, methodName: string, args?:
hookBeforeNativeCall(context) hookBeforeNativeCall(context)
const ret = Reflect.apply(Reflect.get(context.entity, methodName), context.entity, argumentsList) const ret = Reflect.apply(Reflect.get(context.entity, methodName), context.entity, argumentsList)
hookAfterNativeCall(context) hookAfterNativeCall(context)
loge(methodName, ret)
return ret return ret
} else { } else {
loge(`Cannot find method for context id:${contextId},method name is:${methodName}`) loge(`Cannot find method for context id:${contextId},method name is:${methodName}`)

View File

@ -34,7 +34,6 @@ export class ListItem extends Stack {
*/ */
@Property @Property
identifier?: string identifier?: string
list!: List
} }
export class List extends Superview { export class List extends Superview {
@ -61,14 +60,16 @@ export class List extends Superview {
let view = this.cachedViews.get(`${itemIdx}`) let view = this.cachedViews.get(`${itemIdx}`)
if (view === undefined) { if (view === undefined) {
view = this.renderItem(itemIdx) view = this.renderItem(itemIdx)
view.list = this view.superview = this
this.cachedViews.set(`${itemIdx}`, view) this.cachedViews.set(`${itemIdx}`, view)
} }
return view return view
} }
@Property private renderBunchedItems(start: number, length: number) {
private renderBunchedItems(items: number[]): ListItem[] { return new Array(Math.min(length, this.itemCount - start)).fill(0).map((_, idx) => {
return items.map(e => this.getItem(e)) const listItem = this.getItem(start + idx)
return listItem.toModel()
})
} }
} }

View File

@ -94,7 +94,7 @@ export abstract class Panel {
for (let i = 2; i < arguments.length; i++) { for (let i = 2; i < arguments.length; i++) {
argumentsList.push(arguments[i]) argumentsList.push(arguments[i])
} }
Reflect.apply(v.responseCallback, v, argumentsList) return Reflect.apply(v.responseCallback, v, argumentsList)
} }
private retrospectView(ids: string[]): View { private retrospectView(ids: string[]): View {

View File

@ -121,7 +121,10 @@ export abstract class View implements Modeling, IView {
} }
private id2Callback(id: string) { private id2Callback(id: string) {
const f = this.callbacks.get(id) let f = this.callbacks.get(id)
if (f === undefined) {
f = Reflect.get(this, id) as Function
}
return f return f
} }
@ -228,7 +231,7 @@ export abstract class View implements Modeling, IView {
for (let i = 1; i < arguments.length; i++) { for (let i = 1; i < arguments.length; i++) {
argumentsList.push(arguments[i]) argumentsList.push(arguments[i])
} }
Reflect.apply(f, this, argumentsList) return Reflect.apply(f, this, argumentsList)
} else { } else {
loge(`Cannot find callback:${id} for ${JSON.stringify(this.toModel())}`) loge(`Cannot find callback:${id} for ${JSON.stringify(this.toModel())}`)
} }