Merge branch 'feature/scrollview' into 'master'

Feature/scrollview



See merge request !13
This commit is contained in:
pengfeizhou 2019-11-19 11:22:35 +08:00
commit 3c0a270878
26 changed files with 2821 additions and 91 deletions

View File

@ -19,6 +19,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".DemoActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,123 @@
/*
* 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.demo;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import pub.doric.DoricContext;
import pub.doric.DoricDriver;
import pub.doric.dev.DevPanel;
import pub.doric.dev.event.EnterDebugEvent;
import pub.doric.dev.event.QuitDebugEvent;
import pub.doric.engine.ChangeEngineCallback;
import pub.doric.utils.DoricUtils;
/**
* @Description: pub.doric.demo
* @Author: pengfei.zhou
* @CreateDate: 2019-11-19
*/
public class DemoActivity extends AppCompatActivity {
private DoricContext doricContext;
private DevPanel devPanel = new DevPanel();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String source = getIntent().getStringExtra("source");
FrameLayout frameLayout = new FrameLayout(this);
addContentView(frameLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
doricContext = DoricContext.create(this, DoricUtils.readAssetFile("demo/" + source), "test");
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
doricContext.getRootNode().setRootView(frameLayout);
}
@Override
protected void onResume() {
super.onResume();
doricContext.onShow();
}
@Override
protected void onPause() {
super.onPause();
doricContext.onHidden();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
doricContext.teardown();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEnterDebugEvent(EnterDebugEvent enterDebugEvent) {
DoricDriver.getInstance().changeJSEngine(false, new ChangeEngineCallback() {
@Override
public void changed() {
runOnUiThread(new Runnable() {
@Override
public void run() {
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
});
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onQuitDebugEvent(QuitDebugEvent quitDebugEvent) {
DoricDriver.getInstance().changeJSEngine(true, new ChangeEngineCallback() {
@Override
public void changed() {
runOnUiThread(new Runnable() {
@Override
public void run() {
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
});
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_MENU == event.getKeyCode()) {
devPanel.show(getSupportFragmentManager(), "DevPanel");
}
return super.onKeyDown(keyCode, event);
}
}

View File

@ -15,102 +15,92 @@
*/
package pub.doric.demo;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import pub.doric.dev.DevPanel;
import pub.doric.DoricContext;
import pub.doric.DoricDriver;
import pub.doric.dev.LocalServer;
import pub.doric.dev.event.EnterDebugEvent;
import pub.doric.dev.event.QuitDebugEvent;
import pub.doric.engine.ChangeEngineCallback;
import pub.doric.utils.DoricUtils;
public class MainActivity extends AppCompatActivity {
private DevPanel devPanel = new DevPanel();
private DoricContext doricContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doricContext = DoricContext.create(this, DoricUtils.readAssetFile("demo/ListDemo.js"), "test");
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
doricContext.getRootNode().setRootView((FrameLayout) findViewById(R.id.root));
LocalServer localServer = new LocalServer(getApplicationContext(), 8910);
RecyclerView recyclerView = findViewById(R.id.root);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
try {
localServer.start();
String[] demos = getAssets().list("demo");
List<String> ret = new ArrayList<>();
for (String str : demos) {
if (str.endsWith("js")) {
ret.add(str);
}
}
recyclerView.setAdapter(new MyAdapter(ret.toArray(new String[0])));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
public static class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
EventBus.getDefault().register(this);
}
private final String[] data;
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEnterDebugEvent(EnterDebugEvent enterDebugEvent) {
DoricDriver.getInstance().changeJSEngine(false, new ChangeEngineCallback() {
@Override
public void changed() {
runOnUiThread(new Runnable() {
@Override
public void run() {
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
});
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onQuitDebugEvent(QuitDebugEvent quitDebugEvent) {
DoricDriver.getInstance().changeJSEngine(true, new ChangeEngineCallback() {
@Override
public void changed() {
runOnUiThread(new Runnable() {
@Override
public void run() {
doricContext.init(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
});
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.KEYCODE_MENU == event.getKeyCode()) {
devPanel.show(getSupportFragmentManager(), "DevPanel");
public MyAdapter(String[] demos) {
this.data = demos;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
TextView textView = new TextView(parent.getContext());
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
DoricUtils.dp2px(50)));
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
return new RecyclerView.ViewHolder(textView) {
@Override
public String toString() {
return super.toString();
}
};
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final TextView tv = (TextView) holder.itemView;
tv.setText(data[position]);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(tv.getContext(), DemoActivity.class);
intent.putExtra("source", data[position]);
tv.getContext().startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return data.length;
}
return super.onKeyDown(keyCode, event);
}
}

View File

@ -1,12 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
tools:context=".MainActivity" />

View File

@ -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.ScrollerNode;
import pub.doric.shader.list.ListItemNode;
import pub.doric.shader.list.ListNode;
import pub.doric.shader.RootNode;
@ -70,6 +71,7 @@ public class DoricRegistry {
this.registerViewNode(HLayoutNode.class);
this.registerViewNode(ListNode.class);
this.registerViewNode(ListItemNode.class);
this.registerViewNode(ScrollerNode.class);
initRegistry(this);
}

View File

@ -34,8 +34,6 @@ public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
private ArrayList<ViewNode> mChildNodes = new ArrayList<>();
private ArrayList<String> mChildViewIds = new ArrayList<>();
protected boolean mReusable = false;
public GroupNode(DoricContext doricContext) {
super(doricContext);
}
@ -80,9 +78,6 @@ public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
mView.removeView(oldNode.getDoricLayer());
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setId(id);
if (newNode instanceof GroupNode) {
((GroupNode) newNode).mReusable = this.mReusable;
}
newNode.init(this);
newNode.blend(model.getProperty("props").asObject());
mChildNodes.add(idx, newNode);
@ -126,9 +121,6 @@ public abstract class GroupNode<F extends ViewGroup> extends SuperNode<F> {
//Insert
ViewNode newNode = ViewNode.create(getDoricContext(), type);
newNode.setId(id);
if (newNode instanceof GroupNode) {
((GroupNode) newNode).mReusable = this.mReusable;
}
newNode.init(this);
newNode.blend(model.getProperty("props").asObject());
mChildNodes.add(newNode);

View File

@ -0,0 +1,101 @@
/*
* 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;
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.widget.HVScrollView;
/**
* @Description: pub.doric.shader
* @Author: pengfei.zhou
* @CreateDate: 2019-11-18
*/
@DoricPlugin(name = "Scroller")
public class ScrollerNode extends SuperNode<HVScrollView> {
private String mChildViewId;
private ViewNode mChildNode;
public ScrollerNode(DoricContext doricContext) {
super(doricContext);
}
@Override
public ViewNode getSubNodeById(String id) {
return id.equals(mChildNode.getId()) ? mChildNode : null;
}
@Override
protected void blendSubNode(JSObject subProperties) {
if (mChildNode != null) {
mChildNode.blend(subProperties);
}
}
@Override
protected HVScrollView build() {
return new HVScrollView(getContext());
}
@Override
protected void blend(HVScrollView view, String name, JSValue prop) {
if ("content".equals(name)) {
mChildViewId = prop.asString().value();
} else {
super.blend(view, name, prop);
}
}
@Override
public void blend(JSObject jsObject) {
super.blend(jsObject);
JSObject contentModel = getSubModel(mChildViewId);
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 (mChildNode != null) {
if (mChildNode.getId().equals(viewId)) {
//skip
} else {
if (mReusable && type.equals(mChildNode.getType())) {
mChildNode.setId(viewId);
mChildNode.blend(props);
} else {
mView.removeAllViews();
mChildNode = ViewNode.create(getDoricContext(), type);
mChildNode.setId(viewId);
mChildNode.init(this);
mChildNode.blend(props);
mView.addView(mChildNode.getDoricLayer());
}
}
} else {
mChildNode = ViewNode.create(getDoricContext(), type);
mChildNode.setId(viewId);
mChildNode.init(this);
mChildNode.blend(props);
mView.addView(mChildNode.getDoricLayer());
}
}
}

View File

@ -35,6 +35,7 @@ import pub.doric.utils.DoricUtils;
*/
public abstract class SuperNode<V extends View> extends ViewNode<V> {
private Map<String, JSObject> subNodes = new HashMap<>();
protected boolean mReusable = false;
public SuperNode(DoricContext doricContext) {
super(doricContext);

View File

@ -37,7 +37,9 @@ public class TextNode extends ViewNode<TextView> {
@Override
protected TextView build() {
return new TextView(getContext());
TextView tv = new TextView(getContext());
tv.setGravity(Gravity.CENTER);
return tv;
}
@Override

View File

@ -55,6 +55,9 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
private DoricLayer doricLayer;
public void init(SuperNode superNode) {
if (this instanceof SuperNode) {
((SuperNode<T>) this).mReusable = superNode.mReusable;
}
this.mSuperNode = superNode;
this.mLayoutParams = superNode.generateDefaultLayoutParams();
this.doricLayer = new DoricLayer(getContext());

File diff suppressed because it is too large Load Diff

View File

@ -2,4 +2,5 @@ export default [
'src/Counter',
'src/Snake',
'src/ListDemo',
'src/ScrollerDemo',
]

59
demo/src/ScrollerDemo.ts Normal file
View File

@ -0,0 +1,59 @@
import { Group, Panel, List, text, gravity, Color, Stack, LayoutSpec, list, NativeCall, listItem, log, vlayout, Gravity, hlayout, scroller } from "doric";
const colors = [
"#f0932b",
"#eb4d4b",
"#6ab04c",
"#e056fd",
"#686de0",
"#30336b",
]
@Entry
class ScrollerPanel extends Panel {
build(rootView: Group): void {
rootView.addChild(scroller(vlayout(
[
// ...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(e => text({
// text: colors[e % colors.length],
// textColor: Color.parse('#ffffff'),
// textSize: 20,
// bgColor: Color.parse(colors[e % colors.length]),
// layoutConfig: {
// widthSpec: LayoutSpec.EXACTLY,
// heightSpec: LayoutSpec.EXACTLY,
// },
// width: 200,
// height: 50,
// })),
...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(i => hlayout([
...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(j => text({
text: colors[(i + j) % colors.length],
textColor: Color.parse('#ffffff'),
textSize: 20,
bgColor: Color.parse(colors[(i + j) % colors.length]),
layoutConfig: {
widthSpec: LayoutSpec.EXACTLY,
heightSpec: LayoutSpec.EXACTLY,
},
width: 80,
height: 50,
})),
]).also(it => it.space = 20)),
hlayout([
...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5].map(e => text({
text: colors[e % colors.length],
textColor: Color.parse('#ffffff'),
textSize: 20,
bgColor: Color.parse(colors[e % colors.length]),
layoutConfig: {
widthSpec: LayoutSpec.EXACTLY,
heightSpec: LayoutSpec.EXACTLY,
},
width: 200,
height: 50,
})),
]
),
]
).also(it => it.space = 20)))
}
}

View File

@ -21,6 +21,7 @@
E2334B0822E9D2070098A085 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334B0722E9D2070098A085 /* ExampleTests.m */; };
E2334B1322E9D2070098A085 /* ExampleUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334B1222E9D2070098A085 /* ExampleUITests.m */; };
E2BF7BF7237E8E9F001B0EDC /* ListDemo.js in Resources */ = {isa = PBXBuildFile; fileRef = E2BF7BF6237E8E9F001B0EDC /* ListDemo.js */; };
E2F447F42383924B00073C7F /* ScrollerDemo.js in Resources */ = {isa = PBXBuildFile; fileRef = E2F447F32383924B00073C7F /* ScrollerDemo.js */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -69,6 +70,7 @@
E2334B1222E9D2070098A085 /* ExampleUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleUITests.m; sourceTree = "<group>"; };
E2334B1422E9D2070098A085 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E2BF7BF6237E8E9F001B0EDC /* ListDemo.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = ListDemo.js; sourceTree = "<group>"; };
E2F447F32383924B00073C7F /* ScrollerDemo.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = ScrollerDemo.js; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -125,6 +127,7 @@
E21DC9D12302865E00660C5C /* src */ = {
isa = PBXGroup;
children = (
E2F447F32383924B00073C7F /* ScrollerDemo.js */,
E2BF7BF6237E8E9F001B0EDC /* ListDemo.js */,
E21DC9D22302865E00660C5C /* Snake.js */,
E21DC9D32302865E00660C5C /* Counter.js */,
@ -298,6 +301,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2F447F42383924B00073C7F /* ScrollerDemo.js in Resources */,
E2BF7BF7237E8E9F001B0EDC /* ListDemo.js in Resources */,
E21DC9D42302870000660C5C /* Snake.js in Resources */,
E21DC9D52302870000660C5C /* Counter.js in Resources */,

View File

@ -26,7 +26,7 @@ @implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"ListDemo" ofType:@"js"];
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"ScrollerDemo" ofType:@"js"];
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
self.doricContext = [[DoricContext alloc] initWithScript:jsContent source:@"test.js"];
[self.doricContext.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) {

View File

@ -30,6 +30,7 @@
#import "DoricImageNode.h"
#import "DoricListNode.h"
#import "DoricListItemNode.h"
#import "DoricScrollerNode.h"
@interface DoricRegistry ()
@ -62,6 +63,7 @@ - (void)innerRegister {
[self registerViewNode:DoricImageNode.class withName:@"Image"];
[self registerViewNode:DoricListNode.class withName:@"List"];
[self registerViewNode:DoricListItemNode.class withName:@"ListItem"];
[self registerViewNode:DoricScrollerNode.class withName:@"Scroller"];
}
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name {

View File

@ -25,7 +25,6 @@
NS_ASSUME_NONNULL_BEGIN
@interface DoricGroupNode <V:UIView *> : DoricSuperNode<V>
@property(nonatomic, assign) BOOL reusable;
@end
NS_ASSUME_NONNULL_END

View File

@ -34,7 +34,6 @@ - (instancetype)initWithContext:(DoricContext *)doricContext {
if (self = [super initWithContext:doricContext]) {
_childNodes = @[];
_childViewIds = @[];
_reusable = NO;
}
return self;
}

View File

@ -38,6 +38,11 @@ - (instancetype)initWithContext:(DoricContext *)doricContext {
return self;
}
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
[super initWithSuperNode:superNode];
self.reusable = YES;
}
- (DoricStackView *)build {
return [DoricListItemView new];
}

View File

@ -0,0 +1,9 @@
//
// Created by pengfei.zhou on 2019/11/19.
//
#import <Foundation/Foundation.h>
#import "DoricSuperNode.h"
@interface DoricScrollerNode : DoricSuperNode<UIScrollView *>
@end

View File

@ -0,0 +1,90 @@
//
// Created by pengfei.zhou on 2019/11/19.
//
#import "DoricScrollerNode.h"
#import "DoricExtensions.h"
@interface DoricScrollView : UIScrollView
@end
@implementation DoricScrollView
- (void)layoutSubviews {
[super layoutSubviews];
if (self.subviews.count > 0) {
UIView *child = self.subviews[0];
[self setContentSize:child.frame.size];
}
}
- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) {
UIView *child = self.subviews[0];
CGSize childSize = [child sizeThatFits:size];
return CGSizeMake(MIN(size.width, childSize.width), MIN(size.height, childSize.height));
}
return CGSizeZero;
}
@end
@interface DoricScrollerNode ()
@property(nonatomic, strong) DoricViewNode *childNode;
@property(nonatomic, copy) NSString *childViewId;
@end
@implementation DoricScrollerNode
- (UIScrollView *)build {
return [DoricScrollView new];
}
- (void)blend:(NSDictionary *)props {
[super blend:props];
NSDictionary *childModel = [self subModelOf:self.childViewId];
if (!childModel) {
return;
}
NSString *viewId = childModel[@"id"];
NSString *type = childModel[@"type"];
NSDictionary *childProps = childModel[@"props"];
if (self.childNode) {
if ([self.childNode.viewId isEqualToString:viewId]) {
//skip
} else {
if (self.reusable && [type isEqualToString:self.childNode.type]) {
[self.childNode also:^(DoricViewNode *it) {
it.viewId = viewId;
[it blend:childProps];
}];
} else {
[self.childNode.view removeFromSuperview];
self.childNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:self];
[it blend:childProps];
[self.view addSubview:it.view];
}];
}
}
} else {
self.childNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:self];
[it blend:childProps];
[self.view addSubview:it.view];
}];
}
}
- (void)blendView:(UIScrollView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"content" isEqualToString:name]) {
self.childViewId = prop;
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (void)blendSubNode:(NSDictionary *)subModel {
[self.childNode blend:subModel];
}
@end

View File

@ -21,6 +21,8 @@
#import "DoricViewNode.h"
@interface DoricSuperNode<V:UIView *> : DoricViewNode<V>
@property(nonatomic, assign) BOOL reusable;
- (DoricLayoutConfig *)generateDefaultLayoutParams;
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig;

View File

@ -81,6 +81,9 @@ - (instancetype)initWithContext:(DoricContext *)doricContext {
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
if ([self isKindOfClass:[DoricSuperNode class]]) {
((DoricSuperNode *) self).reusable = superNode.reusable;
}
self.superNode = superNode;
self.view = [[self build] also:^(UIView *it) {
it.layoutConfig = [superNode generateDefaultLayoutParams];

View File

@ -16,6 +16,7 @@
export * from "./src/ui/view"
export * from "./src/ui/layout"
export * from "./src/ui/listview"
export * from "./src/ui/scroller"
export * from "./src/ui/widgets"
export * from "./src/ui/panel"
export * from "./src/ui/declarative"

View File

@ -193,6 +193,18 @@ export function jsObtainContext(id: string) {
}
export function jsReleaseContext(id: string) {
const context = gContexts.get(id)
if (context) {
timerInfos.forEach((v, k) => {
if (v.context === context) {
if (global.nativeClearTimer === undefined) {
return Reflect.apply(_clearTimeout, undefined, arguments)
}
timerInfos.delete(k)
nativeClearTimer(k)
}
})
}
gContexts.delete(id)
}

View File

@ -0,0 +1,43 @@
/*
* 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 { Superview, View, Property, IView, LayoutSpec } from './view'
export function scroller(content: View) {
return (new Scroller).also(v => {
v.layoutConfig = {
widthSpec: LayoutSpec.WRAP_CONTENT,
heightSpec: LayoutSpec.WRAP_CONTENT,
}
v.content = content
})
}
export interface IScroller extends IView {
content: View
}
export class Scroller extends Superview implements IScroller {
content!: View
allSubviews() {
return [this.content]
}
toModel() {
this.dirtyProps.content = this.content.viewId
return super.toModel()
}
}