diff --git a/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java b/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java index e20f6f86..6a89272d 100644 --- a/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java +++ b/Android/doric/src/main/java/pub/doric/shader/list/ListAdapter.java @@ -22,12 +22,13 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import com.github.pengfeizhou.jscore.JSArray; import com.github.pengfeizhou.jscore.JSDecoder; import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSValue; -import java.util.HashMap; -import java.util.Map; + +import org.json.JSONObject; import pub.doric.async.AsyncResult; import pub.doric.shader.ViewNode; @@ -39,12 +40,12 @@ import pub.doric.shader.ViewNode; */ public class ListAdapter extends RecyclerView.Adapter { - private final ListNode listNode; + final ListNode listNode; String renderItemFuncId; - private final String renderBunchedItemsFuncId = "renderBunchedItems"; + final String renderBunchedItemsFuncId = "renderBunchedItems"; int itemCount = 0; int batchCount = 15; - private SparseArray itemObjects = new SparseArray<>(); + SparseArray itemValues = new SparseArray<>(); public ListAdapter(ListNode listNode) { this.listNode = listNode; @@ -60,9 +61,12 @@ public class ListAdapter extends RecyclerView.Adapter asyncResult = listNode.callJSResponse( renderBunchedItemsFuncId, position, @@ -90,11 +96,11 @@ public class ListAdapter extends RecyclerView.Adapter { break; case "renderItem": this.listAdapter.renderItemFuncId = prop.asString().value(); + // If reset renderItem,should reset native cache. + this.listAdapter.itemValues.clear(); break; case "batchCount": this.listAdapter.batchCount = 15; diff --git a/demo/src/ListDemo.ts b/demo/src/ListDemo.ts index fafa42cf..df14fee2 100644 --- a/demo/src/ListDemo.ts +++ b/demo/src/ListDemo.ts @@ -1,4 +1,4 @@ -import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, ListItem, NativeCall, listItem, log } from "doric"; +import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout } from "doric"; const colors = [ "#f0932b", "#eb4d4b", @@ -10,43 +10,62 @@ const colors = [ @Entry class ListPanel extends Panel { build(rootView: Group): void { - const list = new List - list.layoutConfig = { - widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.AT_MOST, - } - rootView.addChild(list) - list.itemCount = 1000 - list.renderItem = (idx) => { - return listItem(text({ + rootView.addChild(vlayout([ + text({ + text: "ListDemo", layoutConfig: { - widthSpec: LayoutSpec.AT_MOST, - heightSpec: LayoutSpec.WRAP_CONTENT, - margin: { - left: 10, - right: 10, - top: 10, - bottom: 10, - }, - }, - text: `Cell At Line ${idx}`, - textAlignment: gravity().center(), - textColor: Color.parse("#ffffff"), - textSize: 20, - })).also(it => { - it.gravity = gravity().center() - it.bgColor = Color.parse(colors[idx % colors.length]) - it.layoutConfig = { widthSpec: LayoutSpec.AT_MOST, heightSpec: LayoutSpec.EXACTLY, - } - it.height = 50 - it.onClick = () => { - log(`Click item at ${idx}`) - it.bgColor = Color.parse('#000000') - log(`changed,listview is dirty:${list.isDirty()}`) - } - }) - } + }, + textSize: 30, + textColor: Color.parse("#535c68"), + bgColor: Color.parse("#dff9fb"), + textAlignment: gravity().center(), + height: 50, + }), + list({ + itemCount: 1000, + renderItem: (idx: number) => { + return listItem(text({ + layoutConfig: { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.WRAP_CONTENT, + margin: { + left: 10, + right: 10, + top: 10, + bottom: 10, + }, + }, + text: `Cell At Line ${idx}`, + textAlignment: gravity().center(), + textColor: Color.parse("#ffffff"), + textSize: 20, + })).also(it => { + it.gravity = gravity().center() + it.bgColor = Color.parse(colors[idx % colors.length]) + it.layoutConfig = { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.EXACTLY, + } + it.height = 50 + it.onClick = () => { + log(`Click item at ${idx}`) + it.bgColor = Color.parse('#000000') + log(`bgcolor is ${Color.parse('#000000').toModel()}`) + } + }) + }, + layoutConfig: { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.AT_MOST, + }, + }), + ]).also(it => { + it.layoutConfig = { + widthSpec: LayoutSpec.AT_MOST, + heightSpec: LayoutSpec.AT_MOST, + } + })) } } \ No newline at end of file diff --git a/js-framework/src/ui/declarative.ts b/js-framework/src/ui/declarative.ts index bf5ddeda..69b8a454 100644 --- a/js-framework/src/ui/declarative.ts +++ b/js-framework/src/ui/declarative.ts @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { View, } from './view' +import { View, LayoutSpec } from './view' import { Stack, HLayout, VLayout } from './layout' import { IText, IImage, Text, Image } from './widgets' +import { IList, List } from './listview' export function text(config: IText) { const ret = new Text @@ -35,6 +36,10 @@ export function image(config: IImage) { export function stack(views: View[]) { const ret = new Stack + ret.layoutConfig = { + widthSpec: LayoutSpec.WRAP_CONTENT, + heightSpec: LayoutSpec.WRAP_CONTENT, + } for (let v of views) { ret.addChild(v) } @@ -43,6 +48,10 @@ export function stack(views: View[]) { export function hlayout(views: View[]) { const ret = new HLayout + ret.layoutConfig = { + widthSpec: LayoutSpec.WRAP_CONTENT, + heightSpec: LayoutSpec.WRAP_CONTENT, + } for (let v of views) { ret.addChild(v) } @@ -51,8 +60,20 @@ export function hlayout(views: View[]) { export function vlayout(views: View[]) { const ret = new VLayout + ret.layoutConfig = { + widthSpec: LayoutSpec.WRAP_CONTENT, + heightSpec: LayoutSpec.WRAP_CONTENT, + } for (let v of views) { ret.addChild(v) } return ret +} + +export function list(config: IList) { + const ret = new List + for (let key in config) { + Reflect.set(ret, key, Reflect.get(config, key, config), ret) + } + return ret } \ No newline at end of file diff --git a/js-framework/src/ui/listview.ts b/js-framework/src/ui/listview.ts index 41c35fb3..984a5458 100644 --- a/js-framework/src/ui/listview.ts +++ b/js-framework/src/ui/listview.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import { View, Property, LayoutSpec, Superview } from "./view"; -import { Model } from "../util/types"; -import { O_TRUNC } from "constants"; +import { View, Property, LayoutSpec, Superview, IView } from "./view"; import { Stack } from "./layout"; -import { loge } from "../util/log"; + export function listItem(item: View) { return (new ListItem).also((it) => { it.layoutConfig = { @@ -37,7 +35,13 @@ export class ListItem extends Stack { identifier?: string } -export class List extends Superview { +export interface IList extends IView { + renderItem: (index: number) => ListItem + itemCount: number + batchCount?: number +} + +export class List extends Superview implements IList { private cachedViews: Map = new Map allSubviews() { diff --git a/js-framework/src/ui/panel.ts b/js-framework/src/ui/panel.ts index 3aa81b27..5010ef5a 100644 --- a/js-framework/src/ui/panel.ts +++ b/js-framework/src/ui/panel.ts @@ -15,7 +15,7 @@ */ import './../runtime/global' import { View, Group } from "./view"; -import { loge, log } from '../util/log'; +import { loge } from '../util/log'; import { Model } from '../util/types'; import { Root } from './layout'; @@ -113,13 +113,13 @@ export abstract class Panel { } private hookBeforeNativeCall() { + this.__root__.clean() } private hookAfterNativeCall() { if (this.__root__.isDirty()) { const model = this.__root__.toModel() this.nativeRender(model) - this.__root__.clean() } } diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index 0527eb5a..707e237b 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -278,6 +278,13 @@ export abstract class Superview extends View { return false } + clean() { + for (let v of this.allSubviews()) { + v.clean() + } + super.clean() + } + toModel() { const subviews = [] for (let v of this.allSubviews()) { @@ -315,7 +322,7 @@ export abstract class Group extends Superview { return e.toModel() } else { //Dont need return model - return {} + return undefined } }) return this.nativeViewModel diff --git a/js-framework/src/util/types.ts b/js-framework/src/util/types.ts index 7e7132c1..ef2269d6 100644 --- a/js-framework/src/util/types.ts +++ b/js-framework/src/util/types.ts @@ -35,7 +35,7 @@ export function obj2Model(obj: Model): Model { } } -type _M = string | number | boolean | Modeling | { [index: string]: Model | undefined } +type _M = string | number | boolean | Modeling | { [index: string]: Model } | undefined export type Model = _M | Array<_M> export type Binder = (v: T) => void