add ListView DEMO ,show
This commit is contained in:
parent
eea7eb5d27
commit
6bf224aa9a
@ -49,7 +49,6 @@ public class MainActivity extends AppCompatActivity {
|
||||
setContentView(R.layout.activity_main);
|
||||
doricContext = DoricContext.create(this, DoricUtils.readAssetFile("demo/Snake.js"), "test");
|
||||
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
// doricContext.callEntity("log");
|
||||
doricContext.getRootNode().setRootView((FrameLayout) findViewById(R.id.root));
|
||||
|
||||
LocalServer localServer = new LocalServer(getApplicationContext(), 8910);
|
||||
|
@ -20,6 +20,7 @@ import android.text.TextUtils;
|
||||
import pub.doric.plugin.ShaderPlugin;
|
||||
import pub.doric.shader.HLayoutNode;
|
||||
import pub.doric.shader.ImageNode;
|
||||
import pub.doric.shader.list.ListItemNode;
|
||||
import pub.doric.shader.list.ListNode;
|
||||
import pub.doric.shader.RootNode;
|
||||
import pub.doric.shader.StackNode;
|
||||
@ -68,6 +69,7 @@ public class DoricRegistry {
|
||||
this.registerViewNode(VLayoutNode.class);
|
||||
this.registerViewNode(HLayoutNode.class);
|
||||
this.registerViewNode(ListNode.class);
|
||||
this.registerViewNode(ListItemNode.class);
|
||||
initRegistry(this);
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,15 @@ public class SettableFuture<T> {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
try {
|
||||
mReadyLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return mResult;
|
||||
}
|
||||
|
||||
public static class TimeoutException extends RuntimeException {
|
||||
|
||||
public TimeoutException() {
|
||||
|
@ -197,7 +197,7 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
|
||||
values.add(DoricUtils.toJavaValue(arg));
|
||||
}
|
||||
return mDoricJSE.invokeMethod(DoricConstant.GLOBAL_DORIC, method,
|
||||
values.toArray(new JavaValue[values.size()]), true);
|
||||
values.toArray(new JavaValue[values.size()]), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,7 +41,7 @@ public class RemoteJSExecutor {
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(10, TimeUnit.SECONDS)
|
||||
.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();
|
||||
webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
|
||||
|
@ -68,7 +68,7 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
|
||||
if (i != child.index) {
|
||||
mIndexInfo.remove(i);
|
||||
child.index = i;
|
||||
mView.removeView(child.getView());
|
||||
mView.removeView(child.getDoricLayer());
|
||||
}
|
||||
tobeRemoved.remove(child);
|
||||
}
|
||||
@ -87,7 +87,7 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
|
||||
}
|
||||
child.blend(childObj.getProperty("props").asObject(), params);
|
||||
if (mIndexInfo.get(i) == null) {
|
||||
mView.addView(child.getView(), i, child.getLayoutParams());
|
||||
mView.addView(child.getDoricLayer(), i, child.getLayoutParams());
|
||||
mIndexInfo.put(i, child);
|
||||
}
|
||||
}
|
||||
@ -98,7 +98,7 @@ public abstract class GroupNode<F extends ViewGroup> extends ViewNode<F> {
|
||||
mChildrenNode.remove(node.getId());
|
||||
mIndexInfo.remove(i);
|
||||
tobeRemoved.remove(node);
|
||||
mView.removeView(node.getView());
|
||||
mView.removeView(node.getDoricLayer());
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class RootNode extends StackNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView() {
|
||||
public View getDoricLayer() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,13 @@ import android.widget.FrameLayout;
|
||||
|
||||
import pub.doric.DoricContext;
|
||||
import pub.doric.DoricRegistry;
|
||||
import pub.doric.async.AsyncResult;
|
||||
import pub.doric.utils.DoricContextHolder;
|
||||
import pub.doric.utils.DoricConstant;
|
||||
import pub.doric.utils.DoricMetaInfo;
|
||||
import pub.doric.utils.DoricUtils;
|
||||
|
||||
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||
import com.github.pengfeizhou.jscore.JSObject;
|
||||
import com.github.pengfeizhou.jscore.JSValue;
|
||||
|
||||
@ -40,7 +42,7 @@ import java.util.LinkedList;
|
||||
public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
||||
protected T mView;
|
||||
int index;
|
||||
GroupNode mParent;
|
||||
ViewNode mParent;
|
||||
String mId;
|
||||
private ViewGroup.LayoutParams mLayoutParams;
|
||||
|
||||
@ -50,7 +52,11 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
||||
|
||||
private DoricLayer doricLayer;
|
||||
|
||||
public View getView() {
|
||||
public void setParentNode(ViewNode parentNode) {
|
||||
mParent = parentNode;
|
||||
}
|
||||
|
||||
public View getDoricLayer() {
|
||||
return doricLayer;
|
||||
}
|
||||
|
||||
@ -60,19 +66,21 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
||||
|
||||
protected abstract T build(JSObject jsObject);
|
||||
|
||||
void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) {
|
||||
public void blend(JSObject jsObject, ViewGroup.LayoutParams layoutParams) {
|
||||
mLayoutParams = layoutParams;
|
||||
if (mView == null) {
|
||||
mView = build(jsObject);
|
||||
}
|
||||
if (getView() == null) {
|
||||
if (getDoricLayer() == null) {
|
||||
doricLayer = new DoricLayer(getContext());
|
||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(layoutParams.width, layoutParams.height);
|
||||
doricLayer.addView(mView, params);
|
||||
}
|
||||
if (jsObject != null) {
|
||||
for (String prop : jsObject.propertySet()) {
|
||||
blend(mView, layoutParams, prop, jsObject.getProperty(prop));
|
||||
}
|
||||
}
|
||||
ViewGroup.LayoutParams params = mView.getLayoutParams();
|
||||
if (params != null) {
|
||||
params.width = layoutParams.width;
|
||||
@ -120,8 +128,8 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
||||
});
|
||||
break;
|
||||
case "layoutConfig":
|
||||
if (prop.isObject() && mParent != null) {
|
||||
mParent.blendChild(this, prop.asObject());
|
||||
if (prop.isObject() && mParent instanceof GroupNode) {
|
||||
((GroupNode) mParent).blendChild(this, prop.asObject());
|
||||
}
|
||||
break;
|
||||
case "border":
|
||||
@ -178,14 +186,14 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
|
||||
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];
|
||||
nArgs[0] = getIdList();
|
||||
nArgs[1] = funcId;
|
||||
if (args.length > 0) {
|
||||
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) {
|
||||
|
@ -22,7 +22,12 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||
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
|
||||
@ -33,7 +38,7 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
|
||||
|
||||
private final ListNode listNode;
|
||||
String renderItemFuncId;
|
||||
String renderBunchedItemsFuncId;
|
||||
private final String renderBunchedItemsFuncId = "renderBunchedItems";
|
||||
int itemCount = 0;
|
||||
int batchCount = 15;
|
||||
private SparseArray<JSObject> itemObjects = new SparseArray<>();
|
||||
@ -45,12 +50,15 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
|
||||
@NonNull
|
||||
@Override
|
||||
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
|
||||
public void onBindViewHolder(@NonNull DoricViewHolder holder, int position) {
|
||||
|
||||
JSObject jsObject = getItemModel(position);
|
||||
holder.listItemNode.blend(jsObject.getProperty("props").asObject(), holder.itemView.getLayoutParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,18 +68,44 @@ public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolde
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
JSValue value = getItemModel(position).getProperty("identifier");
|
||||
if (value.isString()) {
|
||||
return value.asString().hashCode();
|
||||
}
|
||||
return super.getItemViewType(position);
|
||||
}
|
||||
|
||||
|
||||
private void jsCallRenderItem() {
|
||||
listNode.callJSResponse(renderItemFuncId);
|
||||
private JSObject getItemModel(int position) {
|
||||
JSObject itemModel = itemObjects.get(position);
|
||||
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 {
|
||||
public DoricViewHolder(@NonNull View itemView) {
|
||||
static class DoricViewHolder extends RecyclerView.ViewHolder {
|
||||
ListItemNode listItemNode;
|
||||
|
||||
public DoricViewHolder(ListItemNode node, @NonNull View itemView) {
|
||||
super(itemView);
|
||||
listItemNode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ package pub.doric.shader.list;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.github.pengfeizhou.jscore.JSObject;
|
||||
@ -42,7 +43,23 @@ public class ListNode extends ViewNode<RecyclerView> {
|
||||
|
||||
@Override
|
||||
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
|
||||
@ -54,9 +71,6 @@ public class ListNode extends ViewNode<RecyclerView> {
|
||||
case "renderItem":
|
||||
this.listAdapter.renderItemFuncId = prop.asString().value();
|
||||
break;
|
||||
case "renderBunchedItemsFuncId":
|
||||
this.listAdapter.renderBunchedItemsFuncId = prop.asString().value();
|
||||
break;
|
||||
case "batchCount":
|
||||
this.listAdapter.batchCount = 15;
|
||||
break;
|
||||
|
@ -14,4 +14,9 @@ org.gradle.jvmargs=-Xmx1536m
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
# To re-enable the build cache, either delete the following
|
||||
# line or set the property to 'true'.
|
||||
android.enableBuildCache=false
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
class ListPanel extends Panel {
|
||||
@ -22,5 +22,4 @@ class ListPanel extends Panel {
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -230,6 +230,7 @@ export function jsCallEntityMethod(contextId: string, methodName: string, args?:
|
||||
hookBeforeNativeCall(context)
|
||||
const ret = Reflect.apply(Reflect.get(context.entity, methodName), context.entity, argumentsList)
|
||||
hookAfterNativeCall(context)
|
||||
loge(methodName, ret)
|
||||
return ret
|
||||
} else {
|
||||
loge(`Cannot find method for context id:${contextId},method name is:${methodName}`)
|
||||
|
@ -34,7 +34,6 @@ export class ListItem extends Stack {
|
||||
*/
|
||||
@Property
|
||||
identifier?: string
|
||||
list!: List
|
||||
}
|
||||
|
||||
export class List extends Superview {
|
||||
@ -61,14 +60,16 @@ export class List extends Superview {
|
||||
let view = this.cachedViews.get(`${itemIdx}`)
|
||||
if (view === undefined) {
|
||||
view = this.renderItem(itemIdx)
|
||||
view.list = this
|
||||
view.superview = this
|
||||
this.cachedViews.set(`${itemIdx}`, view)
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
@Property
|
||||
private renderBunchedItems(items: number[]): ListItem[] {
|
||||
return items.map(e => this.getItem(e))
|
||||
private renderBunchedItems(start: number, length: number) {
|
||||
return new Array(Math.min(length, this.itemCount - start)).fill(0).map((_, idx) => {
|
||||
const listItem = this.getItem(start + idx)
|
||||
return listItem.toModel()
|
||||
})
|
||||
}
|
||||
}
|
@ -94,7 +94,7 @@ export abstract class Panel {
|
||||
for (let i = 2; i < arguments.length; i++) {
|
||||
argumentsList.push(arguments[i])
|
||||
}
|
||||
Reflect.apply(v.responseCallback, v, argumentsList)
|
||||
return Reflect.apply(v.responseCallback, v, argumentsList)
|
||||
}
|
||||
|
||||
private retrospectView(ids: string[]): View {
|
||||
|
@ -121,7 +121,10 @@ export abstract class View implements Modeling, IView {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -228,7 +231,7 @@ export abstract class View implements Modeling, IView {
|
||||
for (let i = 1; i < arguments.length; i++) {
|
||||
argumentsList.push(arguments[i])
|
||||
}
|
||||
Reflect.apply(f, this, argumentsList)
|
||||
return Reflect.apply(f, this, argumentsList)
|
||||
} else {
|
||||
loge(`Cannot find callback:${id} for ${JSON.stringify(this.toModel())}`)
|
||||
}
|
||||
|
Reference in New Issue
Block a user