feat:add RefreshableDemo for Android
This commit is contained in:
parent
c766e57c83
commit
362ec833c9
@ -29,6 +29,8 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import org.w3c.dom.Text;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -54,7 +56,9 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
});
|
});
|
||||||
swipeLayout.setBackgroundColor(Color.YELLOW);
|
swipeLayout.setBackgroundColor(Color.YELLOW);
|
||||||
swipeLayout.getRefreshView().setBackgroundColor(Color.RED);
|
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 recyclerView = findViewById(R.id.root);
|
||||||
recyclerView.setBackgroundColor(Color.WHITE);
|
recyclerView.setBackgroundColor(Color.WHITE);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
@ -25,6 +25,7 @@ import pub.doric.plugin.NavigatorPlugin;
|
|||||||
import pub.doric.plugin.NetworkPlugin;
|
import pub.doric.plugin.NetworkPlugin;
|
||||||
import pub.doric.plugin.ShaderPlugin;
|
import pub.doric.plugin.ShaderPlugin;
|
||||||
import pub.doric.plugin.StoragePlugin;
|
import pub.doric.plugin.StoragePlugin;
|
||||||
|
import pub.doric.pullable.RefreshableNode;
|
||||||
import pub.doric.shader.HLayoutNode;
|
import pub.doric.shader.HLayoutNode;
|
||||||
import pub.doric.shader.ImageNode;
|
import pub.doric.shader.ImageNode;
|
||||||
import pub.doric.shader.ScrollerNode;
|
import pub.doric.shader.ScrollerNode;
|
||||||
@ -96,6 +97,7 @@ public class DoricRegistry {
|
|||||||
this.registerViewNode(ScrollerNode.class);
|
this.registerViewNode(ScrollerNode.class);
|
||||||
this.registerViewNode(SliderNode.class);
|
this.registerViewNode(SliderNode.class);
|
||||||
this.registerViewNode(SlideItemNode.class);
|
this.registerViewNode(SlideItemNode.class);
|
||||||
|
this.registerViewNode(RefreshableNode.class);
|
||||||
initRegistry(this);
|
initRegistry(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
|
|||||||
|
|
||||||
private void createProgressView() {
|
private void createProgressView() {
|
||||||
mRefreshView = new DoricRefreshView(getContext());
|
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);
|
addView(mRefreshView, layoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,8 +441,16 @@ public class DoricSwipeLayout extends ViewGroup implements NestedScrollingParent
|
|||||||
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
|
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
|
||||||
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
|
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
|
||||||
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
|
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
|
||||||
mRefreshView.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
|
mRefreshView.measure(
|
||||||
MeasureSpec.makeMeasureSpec(mPullDownHeight, MeasureSpec.EXACTLY));
|
MeasureSpec.makeMeasureSpec(
|
||||||
|
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
|
||||||
|
MeasureSpec.EXACTLY),
|
||||||
|
MeasureSpec.makeMeasureSpec(
|
||||||
|
(getMeasuredHeight() - getPaddingTop() - getPaddingBottom()) / 3,
|
||||||
|
MeasureSpec.UNSPECIFIED));
|
||||||
|
if (mPullDownHeight != mRefreshView.getMeasuredHeight()) {
|
||||||
|
setPullDownHeight(mRefreshView.getMeasuredHeight());
|
||||||
|
}
|
||||||
mCircleViewIndex = -1;
|
mCircleViewIndex = -1;
|
||||||
// Get the index of the circleview.
|
// Get the index of the circleview.
|
||||||
for (int index = 0; index < getChildCount(); index++) {
|
for (int index = 0; index < getChildCount(); index++) {
|
||||||
|
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
@ -12,4 +12,5 @@ export default [
|
|||||||
'src/StorageDemo',
|
'src/StorageDemo',
|
||||||
'src/NavigatorDemo',
|
'src/NavigatorDemo',
|
||||||
'src/NavbarDemo',
|
'src/NavbarDemo',
|
||||||
|
'src/RefreshableDemo',
|
||||||
]
|
]
|
72
demo/src/RefreshableDemo.ts
Normal file
72
demo/src/RefreshableDemo.ts
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ export * from "./src/ui/scroller"
|
|||||||
export * from "./src/ui/widgets"
|
export * from "./src/ui/widgets"
|
||||||
export * from "./src/ui/panel"
|
export * from "./src/ui/panel"
|
||||||
export * from "./src/ui/declarative"
|
export * from "./src/ui/declarative"
|
||||||
|
export * from "./src/ui/refreshable"
|
||||||
export * from "./src/util/color"
|
export * from "./src/util/color"
|
||||||
export * from './src/util/log'
|
export * from './src/util/log'
|
||||||
export * from './src/util/types'
|
export * from './src/util/types'
|
||||||
|
60
js-framework/src/ui/refreshable.ts
Normal file
60
js-framework/src/ui/refreshable.ts
Normal 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
|
||||||
|
}
|
@ -266,7 +266,7 @@ export abstract class View implements Modeling, IView {
|
|||||||
|
|
||||||
nativeChannel(context: any, name: string) {
|
nativeChannel(context: any, name: string) {
|
||||||
let thisView: View | undefined = this
|
let thisView: View | undefined = this
|
||||||
return function (...args: any) {
|
return function (args: any = undefined) {
|
||||||
const func = context.shader.command
|
const func = context.shader.command
|
||||||
const viewIds = []
|
const viewIds = []
|
||||||
while (thisView != undefined) {
|
while (thisView != undefined) {
|
||||||
|
Reference in New Issue
Block a user