feat:add RefreshableDemo for Android

This commit is contained in:
pengfei.zhou 2019-11-26 10:31:17 +08:00
parent c766e57c83
commit 362ec833c9
9 changed files with 318 additions and 5 deletions

View File

@ -29,6 +29,8 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -54,7 +56,9 @@ public class MainActivity extends AppCompatActivity {
});
swipeLayout.setBackgroundColor(Color.YELLOW);
swipeLayout.getRefreshView().setBackgroundColor(Color.RED);
swipeLayout.setPullDownHeight(300);
TextView textView = new TextView(this);
textView.setText("This is header");
swipeLayout.getRefreshView().setContent(textView);
RecyclerView recyclerView = findViewById(R.id.root);
recyclerView.setBackgroundColor(Color.WHITE);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

View File

@ -25,6 +25,7 @@ import pub.doric.plugin.NavigatorPlugin;
import pub.doric.plugin.NetworkPlugin;
import pub.doric.plugin.ShaderPlugin;
import pub.doric.plugin.StoragePlugin;
import pub.doric.pullable.RefreshableNode;
import pub.doric.shader.HLayoutNode;
import pub.doric.shader.ImageNode;
import pub.doric.shader.ScrollerNode;
@ -96,6 +97,7 @@ public class DoricRegistry {
this.registerViewNode(ScrollerNode.class);
this.registerViewNode(SliderNode.class);
this.registerViewNode(SlideItemNode.class);
this.registerViewNode(RefreshableNode.class);
initRegistry(this);
}

View File

@ -287,7 +287,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
private void createProgressView() {
mRefreshView = new DoricRefreshView(getContext());
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, 0);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
addView(mRefreshView, layoutParams);
}
@ -441,8 +441,16 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
mRefreshView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mPullDownHeight, MeasureSpec.EXACTLY));
mRefreshView.measure(
MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(
(getMeasuredHeight() - getPaddingTop() - getPaddingBottom()) / 3,
MeasureSpec.UNSPECIFIED));
if (mPullDownHeight != mRefreshView.getMeasuredHeight()) {
setPullDownHeight(mRefreshView.getMeasuredHeight());
}
mCircleViewIndex = -1;
// Get the index of the circleview.
for (int index = 0; index < getChildCount(); index++) {

View File

@ -0,0 +1,165 @@
package pub.doric.pullable;
import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue;
import com.github.pengfeizhou.jscore.JavaValue;
import pub.doric.DoricContext;
import pub.doric.extension.bridge.DoricMethod;
import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.extension.bridge.DoricPromise;
import pub.doric.shader.SuperNode;
import pub.doric.shader.ViewNode;
/**
* @Description: pub.doric.pullable
* @Author: pengfei.zhou
* @CreateDate: 2019-11-26
*/
@DoricPlugin(name = "Refreshable")
public class RefreshableNode extends SuperNode<DoricSwipeLayout> {
private String mContentViewId;
private ViewNode mContentNode;
private String mHeaderViewId;
private ViewNode mHeaderNode;
public RefreshableNode(DoricContext doricContext) {
super(doricContext);
}
@Override
protected DoricSwipeLayout build() {
return new DoricSwipeLayout(getContext());
}
@Override
protected void blend(DoricSwipeLayout view, String name, JSValue prop) {
if ("content".equals(name)) {
mContentViewId = prop.asString().value();
} else if ("header".equals(name)) {
mHeaderViewId = prop.asString().value();
} else {
super.blend(view, name, prop);
}
}
@Override
public void blend(JSObject jsObject) {
super.blend(jsObject);
blendContentNode();
blendHeadNode();
}
private void blendContentNode() {
JSObject contentModel = getSubModel(mContentViewId);
if (contentModel == null) {
return;
}
String viewId = contentModel.getProperty("id").asString().value();
String type = contentModel.getProperty("type").asString().value();
JSObject props = contentModel.getProperty("props").asObject();
if (mContentNode != null) {
if (mContentNode.getId().equals(viewId)) {
//skip
} else {
if (mReusable && type.equals(mContentNode.getType())) {
mContentNode.setId(viewId);
mContentNode.blend(props);
} else {
mView.removeAllViews();
mContentNode = ViewNode.create(getDoricContext(), type);
mContentNode.setId(viewId);
mContentNode.init(this);
mContentNode.blend(props);
mView.addView(mContentNode.getDoricLayer());
}
}
} else {
mContentNode = ViewNode.create(getDoricContext(), type);
mContentNode.setId(viewId);
mContentNode.init(this);
mContentNode.blend(props);
mView.addView(mContentNode.getDoricLayer());
}
}
private void blendHeadNode() {
JSObject headerModel = getSubModel(mHeaderViewId);
if (headerModel == null) {
return;
}
String viewId = headerModel.getProperty("id").asString().value();
String type = headerModel.getProperty("type").asString().value();
JSObject props = headerModel.getProperty("props").asObject();
if (mHeaderNode != null) {
if (mHeaderNode.getId().equals(viewId)) {
//skip
} else {
if (mReusable && type.equals(mHeaderNode.getType())) {
mHeaderNode.setId(viewId);
mHeaderNode.blend(props);
} else {
mHeaderNode = ViewNode.create(getDoricContext(), type);
mHeaderNode.setId(viewId);
mHeaderNode.init(this);
mHeaderNode.blend(props);
mView.getRefreshView().setContent(mHeaderNode.getDoricLayer());
}
}
} else {
mHeaderNode = ViewNode.create(getDoricContext(), type);
mHeaderNode.setId(viewId);
mHeaderNode.init(this);
mHeaderNode.blend(props);
mView.getRefreshView().setContent(mHeaderNode.getDoricLayer());
}
}
@Override
public ViewNode getSubNodeById(String id) {
if (id.equals(mContentViewId)) {
return mContentNode;
}
if (id.equals(mHeaderViewId)) {
return mHeaderNode;
}
return null;
}
@Override
protected void blendSubNode(JSObject subProperties) {
String viewId = subProperties.getProperty("id").asString().value();
ViewNode node = getSubNodeById(viewId);
if (node != null) {
node.blend(subProperties.getProperty("props").asObject());
}
}
@DoricMethod
public void setRefreshable(JSValue jsValue, DoricPromise doricPromise) {
boolean refreshable = jsValue.asBoolean().value();
this.mView.setEnabled(refreshable);
doricPromise.resolve();
}
@DoricMethod
public void setRefreshing(JSValue jsValue, DoricPromise doricPromise) {
boolean refreshing = jsValue.asBoolean().value();
this.mView.setRefreshing(refreshing);
doricPromise.resolve();
}
@DoricMethod
public void isRefreshable(DoricPromise doricPromise) {
doricPromise.resolve(new JavaValue(this.mView.isEnabled()));
}
@DoricMethod
public void isRefreshing(DoricPromise doricPromise) {
doricPromise.resolve(new JavaValue(this.mView.isRefreshing()));
}
}

View File

@ -12,4 +12,5 @@ export default [
'src/StorageDemo',
'src/NavigatorDemo',
'src/NavbarDemo',
'src/RefreshableDemo',
]

View File

@ -0,0 +1,72 @@
import { refreshable, Group, Panel, navbar, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, Text, scroller, layoutConfig, image, IView, IVLayout, ScaleType, modal, IText, network, navigator } from "doric";
import { title, label, colors } from "./utils";
@Entry
class RefreshableDemo extends Panel {
build(rootView: Group): void {
let refreshView = refreshable({
layoutConfig: layoutConfig().atmost(),
header: text({
text: "This is Header",
width: 100,
height: 100,
layoutConfig: layoutConfig().exactly(),
}),
content: scroller(vlayout([
title("Refreshable Demo"),
label('start Refresh').apply({
width: 300,
height: 50,
bgColor: colors[0],
textSize: 30,
textColor: Color.WHITE,
layoutConfig: layoutConfig().exactly(),
onClick: () => {
refreshView.setRefreshing(context, true)
}
} as IText),
label('stop Refresh').apply({
width: 300,
height: 50,
bgColor: colors[0],
textSize: 30,
textColor: Color.WHITE,
layoutConfig: layoutConfig().exactly(),
onClick: () => {
refreshView.setRefreshing(context, false)
}
} as IText),
label('Enable Refresh').apply({
width: 300,
height: 50,
bgColor: colors[0],
textSize: 30,
textColor: Color.WHITE,
layoutConfig: layoutConfig().exactly(),
onClick: () => {
refreshView.setRefreshable(context, true)
}
} as IText),
label('Disable Refresh').apply({
width: 300,
height: 50,
bgColor: colors[0],
textSize: 30,
textColor: Color.WHITE,
layoutConfig: layoutConfig().exactly(),
onClick: () => {
refreshView.setRefreshable(context, false)
}
} as IText),
]).apply({
layoutConfig: layoutConfig().atmost().h(LayoutSpec.WRAP_CONTENT),
gravity: gravity().center(),
space: 10,
} as IVLayout)).apply({
layoutConfig: layoutConfig().atmost(),
})
}).in(rootView)
}
}

View File

@ -21,6 +21,7 @@ export * from "./src/ui/scroller"
export * from "./src/ui/widgets"
export * from "./src/ui/panel"
export * from "./src/ui/declarative"
export * from "./src/ui/refreshable"
export * from "./src/util/color"
export * from './src/util/log'
export * from './src/util/types'

View File

@ -0,0 +1,60 @@
import { View, Property, Superview, IView } from "./view";
import { List } from "./list";
import { Scroller } from "./scroller";
import { BridgeContext } from "../runtime/global";
import { layoutConfig } from "./declarative";
export interface IRefreshable extends IView {
content: List | Scroller
header?: View
onRefresh?: () => void
}
export class Refreshable extends Superview implements IRefreshable {
content!: List | Scroller
header?: View
@Property
onRefresh?: () => void
allSubviews() {
const ret: View[] = [this.content]
if (this.header) {
ret.push(this.header)
}
return ret
}
setRefreshable(context: BridgeContext, refreshable: boolean) {
return this.nativeChannel(context, 'setRefreshable')(refreshable)
}
setRefreshing(context: BridgeContext, refreshing: boolean) {
return this.nativeChannel(context, 'setRefreshing')(refreshing)
}
isRefreshable(context: BridgeContext) {
return this.nativeChannel(context, 'isRefreshable')() as Promise<boolean>
}
isRefreshing(context: BridgeContext) {
return this.nativeChannel(context, 'isRefreshing')() as Promise<boolean>
}
toModel() {
this.dirtyProps.content = this.content.viewId
this.dirtyProps.header = (this.header || {}).viewId
return super.toModel()
}
}
export function refreshable(config: IRefreshable) {
const ret = new Refreshable
ret.layoutConfig = layoutConfig().wrap()
for (let key in config) {
Reflect.set(ret, key, Reflect.get(config, key, config), ret)
}
return ret
}

View File

@ -266,7 +266,7 @@ export abstract class View implements Modeling, IView {
nativeChannel(context: any, name: string) {
let thisView: View | undefined = this
return function (...args: any) {
return function (args: any = undefined) {
const func = context.shader.command
const viewIds = []
while (thisView != undefined) {