From 394800150e3053fcfcd982854cafe6acf8f4fea3 Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Sat, 7 Dec 2019 15:49:55 +0800 Subject: [PATCH] feat:fix HVScrollView nested horizontal scroll --- .../main/java/pub/doric/DoricRegistry.java | 2 + .../main/java/pub/doric/shader/GroupNode.java | 6 +- .../doric/shader/slider/NestedSliderNode.java | 207 ++++++++++++++++++ .../java/pub/doric/widget/HVScrollView.java | 13 +- 4 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 doric/src/main/java/pub/doric/shader/slider/NestedSliderNode.java diff --git a/doric/src/main/java/pub/doric/DoricRegistry.java b/doric/src/main/java/pub/doric/DoricRegistry.java index 6172e9dd..b95669ed 100644 --- a/doric/src/main/java/pub/doric/DoricRegistry.java +++ b/doric/src/main/java/pub/doric/DoricRegistry.java @@ -41,6 +41,7 @@ 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.NestedSliderNode; import pub.doric.shader.slider.SlideItemNode; import pub.doric.shader.slider.SliderNode; import pub.doric.utils.DoricMetaInfo; @@ -108,6 +109,7 @@ public class DoricRegistry { this.registerViewNode(FlowLayoutNode.class); this.registerViewNode(FlowLayoutItemNode.class); this.registerViewNode(InputNode.class); + this.registerViewNode(NestedSliderNode.class); initRegistry(this); } diff --git a/doric/src/main/java/pub/doric/shader/GroupNode.java b/doric/src/main/java/pub/doric/shader/GroupNode.java index bf6a958a..c940865c 100644 --- a/doric/src/main/java/pub/doric/shader/GroupNode.java +++ b/doric/src/main/java/pub/doric/shader/GroupNode.java @@ -31,8 +31,8 @@ import java.util.ArrayList; * @CreateDate: 2019-07-20 */ public abstract class GroupNode extends SuperNode { - private ArrayList mChildNodes = new ArrayList<>(); - private ArrayList mChildViewIds = new ArrayList<>(); + protected ArrayList mChildNodes = new ArrayList<>(); + protected ArrayList mChildViewIds = new ArrayList<>(); public GroupNode(DoricContext doricContext) { super(doricContext); @@ -57,7 +57,7 @@ public abstract class GroupNode extends SuperNode { configChildNode(); } - private void configChildNode() { + protected void configChildNode() { for (int idx = 0; idx < mChildViewIds.size(); idx++) { String id = mChildViewIds.get(idx); JSObject model = getSubModel(id); diff --git a/doric/src/main/java/pub/doric/shader/slider/NestedSliderNode.java b/doric/src/main/java/pub/doric/shader/slider/NestedSliderNode.java new file mode 100644 index 00000000..204164ef --- /dev/null +++ b/doric/src/main/java/pub/doric/shader/slider/NestedSliderNode.java @@ -0,0 +1,207 @@ +/* + * 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.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import com.github.pengfeizhou.jscore.JSObject; +import com.github.pengfeizhou.jscore.JSValue; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; + +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.GroupNode; +import pub.doric.shader.ViewNode; + +/** + * @Description: pub.doric.shader.slider + * @Author: pengfei.zhou + * @CreateDate: 2019-12-07 + */ +@DoricPlugin(name = "NestedSlider") +public class NestedSliderNode extends GroupNode implements ViewPager.OnPageChangeListener { + private ArrayList slideItems = new ArrayList<>(); + private String onPageSlidedFuncId; + + public NestedSliderNode(DoricContext doricContext) { + super(doricContext); + } + + @Override + protected ViewPager build() { + ViewPager viewPager = new ViewPager(getContext()); + viewPager.setAdapter(new PagerAdapter() { + @Override + public int getCount() { + return slideItems.size(); + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NotNull Object object) { + return view == object; + } + + @Override + public void destroyItem(@NotNull ViewGroup container, int position, @NotNull Object object) { + container.removeView(slideItems.get(position)); + } + + @NotNull + @Override + public Object instantiateItem(@NotNull ViewGroup container, int position) { + container.addView(slideItems.get(position), 0); + return slideItems.get(position); + } + }); + viewPager.addOnPageChangeListener(this); + return viewPager; + } + + @Override + protected void blend(ViewPager view, String name, JSValue prop) { + switch (name) { + case "onPageSlided": + this.onPageSlidedFuncId = prop.asString().toString(); + break; + default: + super.blend(view, name, prop); + break; + } + } + + @Override + protected void configChildNode() { + for (int idx = 0; idx < mChildViewIds.size(); idx++) { + String id = mChildViewIds.get(idx); + JSObject model = getSubModel(id); + String type = model.getProperty("type").asString().value(); + if (idx < mChildNodes.size()) { + ViewNode oldNode = mChildNodes.get(idx); + if (id.equals(oldNode.getId())) { + //The same,skip + } else { + if (mReusable) { + if (oldNode.getType().equals(type)) { + //Same type,can be reused + oldNode.setId(id); + oldNode.blend(model.getProperty("props").asObject()); + } else { + //Replace this view + mChildNodes.remove(idx); + slideItems.remove(oldNode.getNodeView()); + ViewNode newNode = ViewNode.create(getDoricContext(), type); + newNode.setId(id); + newNode.init(this); + newNode.blend(model.getProperty("props").asObject()); + mChildNodes.add(idx, newNode); + slideItems.add(idx, newNode.getNodeView()); + } + } else { + //Find in remain nodes + int position = -1; + for (int start = idx + 1; start < mChildNodes.size(); start++) { + ViewNode node = mChildNodes.get(start); + if (id.equals(node.getId())) { + //Found + position = start; + break; + } + } + if (position >= 0) { + //Found swap idx,position + ViewNode reused = mChildNodes.remove(position); + ViewNode abandoned = mChildNodes.remove(idx); + mChildNodes.set(idx, reused); + mChildNodes.set(position, abandoned); + //View swap index + slideItems.remove(reused.getNodeView()); + slideItems.add(idx, reused.getNodeView()); + slideItems.remove(abandoned.getNodeView()); + slideItems.add(position, abandoned.getNodeView()); + } else { + //Not found,insert + ViewNode newNode = ViewNode.create(getDoricContext(), type); + newNode.setId(id); + newNode.init(this); + newNode.blend(model.getProperty("props").asObject()); + + mChildNodes.add(idx, newNode); + slideItems.add(idx, newNode.getNodeView()); + } + } + } + } else { + //Insert + ViewNode newNode = ViewNode.create(getDoricContext(), type); + newNode.setId(id); + newNode.init(this); + newNode.blend(model.getProperty("props").asObject()); + mChildNodes.add(newNode); + slideItems.add(idx, newNode.getNodeView()); + } + } + int size = mChildNodes.size(); + for (int idx = mChildViewIds.size(); idx < size; idx++) { + ViewNode viewNode = mChildNodes.remove(mChildViewIds.size()); + slideItems.remove(viewNode.getNodeView()); + } + mView.getAdapter().notifyDataSetChanged(); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + if (!TextUtils.isEmpty(onPageSlidedFuncId)) { + callJSResponse(onPageSlidedFuncId, position); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + @DoricMethod + public void slidePage(JSObject params, DoricPromise promise) { + int page = params.getProperty("page").asNumber().toInt(); + boolean smooth = params.getProperty("smooth").asBoolean().value(); + mView.setCurrentItem(page, smooth); + if (!TextUtils.isEmpty(onPageSlidedFuncId)) { + callJSResponse(onPageSlidedFuncId, page); + } + promise.resolve(); + } + + @DoricMethod + public int getSlidedPage() { + return mView.getCurrentItem(); + } +} diff --git a/doric/src/main/java/pub/doric/widget/HVScrollView.java b/doric/src/main/java/pub/doric/widget/HVScrollView.java index 7b86cd49..82456d55 100644 --- a/doric/src/main/java/pub/doric/widget/HVScrollView.java +++ b/doric/src/main/java/pub/doric/widget/HVScrollView.java @@ -669,6 +669,11 @@ public class HVScrollView extends FrameLayout implements NestedScrollingParent, super.requestDisallowInterceptTouchEvent(disallowIntercept); } + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return super.dispatchTouchEvent(ev); + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { /* @@ -715,8 +720,12 @@ public class HVScrollView extends FrameLayout implements NestedScrollingParent, final int y = (int) ev.getY(pointerIndex); final int xDiff = Math.abs(x - mLastMotionX); final int yDiff = Math.abs(y - mLastMotionY); - if ((xDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_HORIZONTAL) == 0) - || (yDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0)) { + if ((xDiff > mTouchSlop + && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_HORIZONTAL) == 0 + && canScrollHorizontally()) + || (yDiff > mTouchSlop + && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0 + && canScrollVertically())) { mIsBeingDragged = true; mLastMotionX = x; mLastMotionY = y;