add slider
This commit is contained in:
parent
c8353a48d2
commit
353ff356a5
@ -28,6 +28,8 @@ import pub.doric.shader.StackNode;
|
||||
import pub.doric.shader.TextNode;
|
||||
import pub.doric.shader.VLayoutNode;
|
||||
import pub.doric.shader.ViewNode;
|
||||
import pub.doric.shader.slider.SlideItemNode;
|
||||
import pub.doric.shader.slider.SliderNode;
|
||||
import pub.doric.utils.DoricMetaInfo;
|
||||
import pub.doric.plugin.DoricJavaPlugin;
|
||||
import pub.doric.plugin.ModalPlugin;
|
||||
@ -72,6 +74,8 @@ public class DoricRegistry {
|
||||
this.registerViewNode(ListNode.class);
|
||||
this.registerViewNode(ListItemNode.class);
|
||||
this.registerViewNode(ScrollerNode.class);
|
||||
this.registerViewNode(SliderNode.class);
|
||||
this.registerViewNode(SlideItemNode.class);
|
||||
initRegistry(this);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ import pub.doric.shader.ViewNode;
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-11-12
|
||||
*/
|
||||
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
|
||||
class ListAdapter extends RecyclerView.Adapter<ListAdapter.DoricViewHolder> {
|
||||
|
||||
private final ListNode listNode;
|
||||
String renderItemFuncId;
|
||||
|
@ -81,7 +81,7 @@ public class ListNode extends SuperNode<RecyclerView> {
|
||||
clearSubModel();
|
||||
break;
|
||||
case "batchCount":
|
||||
this.listAdapter.batchCount = 15;
|
||||
this.listAdapter.batchCount = prop.asNumber().toInt();
|
||||
break;
|
||||
default:
|
||||
super.blend(view, name, prop);
|
||||
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.slider;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
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.JSNull;
|
||||
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
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-11-12
|
||||
*/
|
||||
class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> {
|
||||
|
||||
private final SliderNode sliderNode;
|
||||
int itemCount = 0;
|
||||
int batchCount = 3;
|
||||
SparseArray<String> itemValues = new SparseArray<>();
|
||||
|
||||
SlideAdapter(SliderNode sliderNode) {
|
||||
this.sliderNode = sliderNode;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DoricViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
SlideItemNode node = (SlideItemNode) ViewNode.create(sliderNode.getDoricContext(), "SlideItem");
|
||||
node.init(sliderNode);
|
||||
return new DoricViewHolder(node, node.getDoricLayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull DoricViewHolder holder, int position) {
|
||||
JSValue jsValue = getItemModel(position);
|
||||
if (jsValue.isObject()) {
|
||||
JSObject jsObject = jsValue.asObject();
|
||||
holder.slideItemNode.setId(jsObject.getProperty("id").asString().value());
|
||||
holder.slideItemNode.blend(jsObject.getProperty("props").asObject());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return itemCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
JSValue value = getItemModel(position);
|
||||
if (value.isObject()) {
|
||||
if (value.asObject().getProperty("identifier").isString()) {
|
||||
return value.asObject().getProperty("identifier").asString().value().hashCode();
|
||||
}
|
||||
}
|
||||
return super.getItemViewType(position);
|
||||
}
|
||||
|
||||
private JSValue getItemModel(final int position) {
|
||||
String id = itemValues.get(position);
|
||||
if (TextUtils.isEmpty(id)) {
|
||||
AsyncResult<JSDecoder> asyncResult = sliderNode.callJSResponse(
|
||||
"renderBunchedItems",
|
||||
position,
|
||||
batchCount);
|
||||
try {
|
||||
JSDecoder jsDecoder = asyncResult.synchronous().get();
|
||||
JSValue result = jsDecoder.decode();
|
||||
if (result.isArray()) {
|
||||
JSArray jsArray = result.asArray();
|
||||
for (int i = 0; i < jsArray.size(); i++) {
|
||||
JSObject itemModel = jsArray.get(i).asObject();
|
||||
String itemId = itemModel.getProperty("id").asString().value();
|
||||
itemValues.put(i + position, itemId);
|
||||
sliderNode.setSubModel(itemId, itemModel);
|
||||
}
|
||||
return sliderNode.getSubModel(itemValues.get(position));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new JSNull();
|
||||
} else {
|
||||
JSObject childModel = sliderNode.getSubModel(id);
|
||||
if (childModel == null) {
|
||||
return new JSNull();
|
||||
} else {
|
||||
return childModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void blendSubNode(JSObject subProperties) {
|
||||
for (int i = 0; i < itemValues.size(); i++) {
|
||||
if (subProperties.getProperty("id").asString().value().equals(itemValues.valueAt(i))) {
|
||||
notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DoricViewHolder extends RecyclerView.ViewHolder {
|
||||
SlideItemNode slideItemNode;
|
||||
|
||||
DoricViewHolder(SlideItemNode node, @NonNull View itemView) {
|
||||
super(itemView);
|
||||
slideItemNode = node;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.slider;
|
||||
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.github.pengfeizhou.jscore.JSObject;
|
||||
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 = "SlideItem")
|
||||
public class SlideItemNode extends StackNode {
|
||||
public String identifier = "";
|
||||
|
||||
public SlideItemNode(DoricContext doricContext) {
|
||||
super(doricContext);
|
||||
this.mReusable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void blend(FrameLayout view, String name, JSValue prop) {
|
||||
if ("identifier".equals(name)) {
|
||||
this.identifier = prop.asString().value();
|
||||
} else {
|
||||
super.blend(view, name, prop);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blend(JSObject jsObject) {
|
||||
super.blend(jsObject);
|
||||
getDoricLayer().getLayoutParams().width = getLayoutParams().width;
|
||||
getDoricLayer().getLayoutParams().height = getLayoutParams().height;
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.slider;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.PagerSnapHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.github.pengfeizhou.jscore.JSObject;
|
||||
import com.github.pengfeizhou.jscore.JSValue;
|
||||
|
||||
import pub.doric.DoricContext;
|
||||
import pub.doric.extension.bridge.DoricPlugin;
|
||||
import pub.doric.shader.SuperNode;
|
||||
import pub.doric.shader.ViewNode;
|
||||
|
||||
/**
|
||||
* @Description: pub.doric.shader
|
||||
* @Author: pengfei.zhou
|
||||
* @CreateDate: 2019-11-19
|
||||
*/
|
||||
@DoricPlugin(name = "Slider")
|
||||
public class SliderNode extends SuperNode<RecyclerView> {
|
||||
private final SlideAdapter slideAdapter;
|
||||
|
||||
public SliderNode(DoricContext doricContext) {
|
||||
super(doricContext);
|
||||
this.slideAdapter = new SlideAdapter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView build() {
|
||||
RecyclerView recyclerView = new RecyclerView(getContext());
|
||||
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
|
||||
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
PagerSnapHelper mPagerSnapHelper = new PagerSnapHelper();
|
||||
mPagerSnapHelper.attachToRecyclerView(recyclerView);
|
||||
recyclerView.setAdapter(this.slideAdapter);
|
||||
return recyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewNode getSubNodeById(String id) {
|
||||
RecyclerView.LayoutManager manager = mView.getLayoutManager();
|
||||
if (manager == null) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < manager.getChildCount(); i++) {
|
||||
View view = manager.getChildAt(i);
|
||||
if (view == null) {
|
||||
continue;
|
||||
}
|
||||
SlideAdapter.DoricViewHolder viewHolder = (SlideAdapter.DoricViewHolder) mView.getChildViewHolder(view);
|
||||
if (id.equals(viewHolder.slideItemNode.getId())) {
|
||||
return viewHolder.slideItemNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void blendSubNode(JSObject subProperties) {
|
||||
slideAdapter.blendSubNode(subProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blend(JSObject jsObject) {
|
||||
super.blend(jsObject);
|
||||
if (mView != null) {
|
||||
mView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
slideAdapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void blend(RecyclerView view, String name, JSValue prop) {
|
||||
switch (name) {
|
||||
case "itemCount":
|
||||
this.slideAdapter.itemCount = prop.asNumber().toInt();
|
||||
break;
|
||||
case "renderItem":
|
||||
// If reset renderItem,should reset native cache.
|
||||
this.slideAdapter.itemValues.clear();
|
||||
clearSubModel();
|
||||
break;
|
||||
case "batchCount":
|
||||
this.slideAdapter.batchCount = prop.asNumber().toInt();
|
||||
break;
|
||||
default:
|
||||
super.blend(view, name, prop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
55
demo/src/SliderDemo.ts
Normal file
55
demo/src/SliderDemo.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, slider, slideItem } from "doric";
|
||||
const colors = [
|
||||
"#f0932b",
|
||||
"#eb4d4b",
|
||||
"#6ab04c",
|
||||
"#e056fd",
|
||||
"#686de0",
|
||||
"#30336b",
|
||||
]
|
||||
@Entry
|
||||
class SliderPanel extends Panel {
|
||||
build(rootView: Group): void {
|
||||
rootView.addChild(vlayout([
|
||||
text({
|
||||
text: "SliderDemo",
|
||||
layoutConfig: {
|
||||
widthSpec: LayoutSpec.AT_MOST,
|
||||
heightSpec: LayoutSpec.EXACTLY,
|
||||
},
|
||||
textSize: 30,
|
||||
textColor: Color.parse("#535c68"),
|
||||
bgColor: Color.parse("#dff9fb"),
|
||||
textAlignment: gravity().center(),
|
||||
height: 50,
|
||||
}),
|
||||
slider({
|
||||
itemCount: 3,
|
||||
renderPage: (idx) => {
|
||||
return slideItem(text({
|
||||
layoutConfig: {
|
||||
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||
heightSpec: LayoutSpec.EXACTLY,
|
||||
alignment: gravity().center(),
|
||||
},
|
||||
text: `Cell At Line ${idx}`,
|
||||
textAlignment: gravity().center(),
|
||||
textColor: Color.parse("#ffffff"),
|
||||
textSize: 20,
|
||||
height: 50,
|
||||
bgColor: Color.parse('#00ff00'),
|
||||
}))
|
||||
},
|
||||
layoutConfig: {
|
||||
widthSpec: LayoutSpec.AT_MOST,
|
||||
heightSpec: LayoutSpec.AT_MOST,
|
||||
},
|
||||
}),
|
||||
]).also(it => {
|
||||
it.layoutConfig = {
|
||||
widthSpec: LayoutSpec.AT_MOST,
|
||||
heightSpec: LayoutSpec.AT_MOST,
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
@ -1,7 +1,18 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
|
||||
/*
|
||||
* 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 <Foundation/Foundation.h>
|
||||
#import "DoricSuperNode.h"
|
||||
|
||||
|
@ -1,7 +1,18 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
|
||||
/*
|
||||
* 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 "DoricScrollerNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
export * from "./src/ui/view"
|
||||
export * from "./src/ui/layout"
|
||||
export * from "./src/ui/listview"
|
||||
export * from "./src/ui/list"
|
||||
export * from "./src/ui/slider"
|
||||
export * from "./src/ui/scroller"
|
||||
export * from "./src/ui/widgets"
|
||||
export * from "./src/ui/panel"
|
||||
|
@ -16,7 +16,8 @@
|
||||
import { View, LayoutSpec } from './view'
|
||||
import { Stack, HLayout, VLayout } from './layout'
|
||||
import { IText, IImage, Text, Image } from './widgets'
|
||||
import { IList, List } from './listview'
|
||||
import { IList, List } from './list'
|
||||
import { ISlider, Slider } from './slider'
|
||||
|
||||
export function text(config: IText) {
|
||||
const ret = new Text
|
||||
@ -85,3 +86,11 @@ export function list(config: IList) {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
export function slider(config: ISlider) {
|
||||
const ret = new Slider
|
||||
for (let key in config) {
|
||||
Reflect.set(ret, key, Reflect.get(config, key, config), ret)
|
||||
}
|
||||
return ret
|
||||
}
|
72
js-framework/src/ui/slider.ts
Normal file
72
js-framework/src/ui/slider.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { Superview, View, LayoutSpec, Property, IView } from "./view";
|
||||
import { Stack } from "./layout";
|
||||
|
||||
export function slideItem(item: View) {
|
||||
return (new SlideItem).also((it) => {
|
||||
it.layoutConfig = {
|
||||
widthSpec: LayoutSpec.WRAP_CONTENT,
|
||||
heightSpec: LayoutSpec.WRAP_CONTENT,
|
||||
}
|
||||
it.addChild(item)
|
||||
})
|
||||
}
|
||||
|
||||
export class SlideItem extends Stack {
|
||||
/**
|
||||
* Set to reuse native view
|
||||
*/
|
||||
@Property
|
||||
identifier?: string
|
||||
}
|
||||
|
||||
export interface ISlider extends IView {
|
||||
renderPage: (index: number) => SlideItem
|
||||
itemCount: number
|
||||
batchCount?: number
|
||||
}
|
||||
|
||||
export class Slider extends Superview implements ISlider {
|
||||
private cachedViews: Map<string, SlideItem> = new Map
|
||||
|
||||
private ignoreDirtyCallOnce = false
|
||||
|
||||
allSubviews() {
|
||||
return this.cachedViews.values()
|
||||
}
|
||||
@Property
|
||||
itemCount = 0
|
||||
|
||||
@Property
|
||||
renderPage!: (index: number) => SlideItem
|
||||
|
||||
@Property
|
||||
batchCount = 3
|
||||
|
||||
|
||||
private getItem(itemIdx: number) {
|
||||
let view = this.cachedViews.get(`${itemIdx}`)
|
||||
if (view === undefined) {
|
||||
view = this.renderPage(itemIdx)
|
||||
view.superview = this
|
||||
this.cachedViews.set(`${itemIdx}`, view)
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
isDirty() {
|
||||
if (this.ignoreDirtyCallOnce) {
|
||||
this.ignoreDirtyCallOnce = false
|
||||
//Ignore the dirty call once.
|
||||
return false
|
||||
}
|
||||
return super.isDirty()
|
||||
}
|
||||
|
||||
private renderBunchedItems(start: number, length: number) {
|
||||
this.ignoreDirtyCallOnce = true;
|
||||
return new Array(Math.min(length, this.itemCount - start)).fill(0).map((_, idx) => {
|
||||
const slideItem = this.getItem(start + idx)
|
||||
return slideItem.toModel()
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user