From 40de94021c0d5e139f8c8696d19ce493f252b772 Mon Sep 17 00:00:00 2001 From: "jianbai.gbj" Date: Mon, 13 Nov 2017 18:09:08 +0800 Subject: [PATCH] [WEEX-109][android] support scroll start scroll end event on scroller list template list --- .../com/taobao/weex/common/Constants.java | 2 + .../taobao/weex/ui/component/WXScroller.java | 43 ++++++- .../helper/ScrollStartEndHelper.java | 116 ++++++++++++++++++ .../ui/component/list/BasicListComponent.java | 35 +++++- .../list/template/WXRecyclerTemplateList.java | 39 ++++-- 5 files changed, 219 insertions(+), 16 deletions(-) create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java index 32c91ba684..5145f9e222 100644 --- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java @@ -278,6 +278,8 @@ public interface Event { String ONPULLING_DOWN = "pullingdown"; String ONPULLING_UP = "pullingup"; String SCROLL = "scroll"; + String SCROLL_START = "scrollstart"; + String SCROLL_END = "scrollend"; String CLICKBACKITEM = "clickbackitem"; String RESUME_EVENT = "WXApplicationDidBecomeActiveEvent"; String PAUSE_EVENT = "WXApplicationWillResignActiveEvent"; diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java index 9e5625957c..9885d62107 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java @@ -42,6 +42,7 @@ import com.taobao.weex.common.WXThread; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.ComponentCreator; +import com.taobao.weex.ui.component.helper.ScrollStartEndHelper; import com.taobao.weex.ui.component.helper.WXStickyHelper; import com.taobao.weex.ui.view.IWXScroller; import com.taobao.weex.ui.view.WXBaseRefreshLayout; @@ -78,6 +79,14 @@ public class WXScroller extends WXVContainer implements WXScrollViewL private boolean mForceLoadmoreNextTime = false; private int mOffsetAccuracy = 10; private Point mLastReport = new Point(-1, -1); + private boolean mHasAddScrollEvent = false; + + /** + * scroll start and scroll end event + * */ + private ScrollStartEndHelper mScrollStartEndHelper; + + public static class Creator implements ComponentCreator { public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException { @@ -102,6 +111,7 @@ public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVC private boolean isScrollable = true; + @Deprecated public WXScroller(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) { this(instance,dom,parent); @@ -148,11 +158,17 @@ public ViewGroup getInnerView() { @Override public void addEvent(String type) { super.addEvent(type); - if (Constants.Event.SCROLL.equals(type) && getInnerView() != null) { + if (ScrollStartEndHelper.isScrollEvent(type) + && getInnerView() != null && !mHasAddScrollEvent) { + mHasAddScrollEvent = true; if (getInnerView() instanceof WXScrollView) { ((WXScrollView) getInnerView()).addScrollViewListener(new WXScrollViewListener() { @Override public void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy) { + getScrollStartEndHelper().onScrolled(x, y); + if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){ + return; + } if (shouldReport(x, y)) { fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy); } @@ -177,6 +193,10 @@ public void onScroll(WXScrollView scrollView, int x, int y) { ((WXHorizontalScrollView) getInnerView()).addScrollViewListener(new WXHorizontalScrollView.ScrollViewListener() { @Override public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy) { + getScrollStartEndHelper().onScrolled(x, y); + if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){ + return; + } if (shouldReport(x, y)) { fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy); } @@ -187,6 +207,16 @@ public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int } private void fireScrollEvent(Rect contentFrame, int x, int y, int oldx, int oldy) { + fireEvent(Constants.Event.SCROLL, getScrollEvent(x, y)); + } + + public Map getScrollEvent(int x, int y){ + Rect contentFrame = new Rect(); + if (getInnerView() instanceof WXScrollView) { + contentFrame = ((WXScrollView) getInnerView()).getContentFrame(); + }else if (getInnerView() instanceof WXHorizontalScrollView) { + contentFrame = ((WXHorizontalScrollView) getInnerView()).getContentFrame(); + } Map event = new HashMap<>(2); Map contentSize = new HashMap<>(2); Map contentOffset = new HashMap<>(2); @@ -201,8 +231,7 @@ private void fireScrollEvent(Rect contentFrame, int x, int y, int oldx, int oldy event.put(Constants.Name.CONTENT_SIZE, contentSize); event.put(Constants.Name.CONTENT_OFFSET, contentOffset); - - fireEvent(Constants.Event.SCROLL, event); + return event; } private boolean shouldReport(int x, int y) { @@ -719,4 +748,12 @@ protected void onLoadMore(WXScrollView scrollView, int x, int y) { public void resetLoadmore() { mForceLoadmoreNextTime = true; } + + + public ScrollStartEndHelper getScrollStartEndHelper() { + if(mScrollStartEndHelper == null){ + mScrollStartEndHelper = new ScrollStartEndHelper(this); + } + return mScrollStartEndHelper; + } } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java new file mode 100644 index 0000000000..15163e1bc9 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java @@ -0,0 +1,116 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 com.taobao.weex.ui.component.helper; + +import android.os.Handler; +import android.os.Looper; +import com.taobao.weex.common.Constants; +import com.taobao.weex.ui.component.WXComponent; +import com.taobao.weex.ui.component.WXScroller; +import com.taobao.weex.ui.component.list.BasicListComponent; +import com.taobao.weex.ui.component.list.ListComponentView; +import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList; +import com.taobao.weex.utils.WXUtils; + +import java.util.Map; + + +/** + * Created by furture on 2017/11/13. + */ + +public class ScrollStartEndHelper implements Runnable{ + + private Handler handler; + private WXComponent component; + private boolean hasStart; + private long minInterval; + + private int x; + private int y; + + public ScrollStartEndHelper(WXComponent component) { + this.component = component; + this.handler = new Handler(Looper.getMainLooper()); + this.minInterval = WXUtils.getNumberInt(component.getDomObject().getAttrs().get("minscrolldelayinterval"), 32); + } + + /** + * @param x scroll offset or dx, which is not accurate + * @param y scroll offset or dy, which is not accurate + * */ + public void onScrolled(int x, int y){ + if((component.getDomObject().getEvents().contains(Constants.Event.SCROLL_START) + || component.getDomObject().getEvents().contains(Constants.Event.SCROLL_END))){ + this.x = x; + this.y = y; + if(!hasStart){ + if(component.getDomObject().getEvents().contains(Constants.Event.SCROLL_START)){ + component.fireEvent(Constants.Event.SCROLL_START, getScrollEvent(x, y)); + } + hasStart = true; + } + handler.removeCallbacks(this); + handler.postDelayed(this, minInterval); + } + } + + + @Override + public void run() { + if(component.isDestoryed()){ + return; + } + if(component.getDomObject().getEvents().contains(Constants.Event.SCROLL_END)){ + component.fireEvent(Constants.Event.SCROLL_END, getScrollEvent(this.x, this.y)); + } + hasStart = false; + } + + private Map getScrollEvent(int offsetX, int offsetY){ + if(component instanceof BasicListComponent){ + BasicListComponent basicListComponent = (BasicListComponent) component; + if(basicListComponent.getHostView() instanceof ListComponentView){ + ListComponentView componentView = (ListComponentView) basicListComponent.getHostView(); + if(componentView != null){ + return basicListComponent.getScrollEvent(componentView.getInnerView(), offsetX, offsetY); + } + } + }else if(component instanceof WXRecyclerTemplateList){ + WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) component; + return templateList.getScrollEvent(templateList.getHostView().getInnerView(), offsetX, offsetY); + }else if(component instanceof WXScroller){ + WXScroller scroller = (WXScroller) component; + return scroller.getScrollEvent(offsetX, offsetY); + } + return null; + } + + + public static boolean isScrollEvent(String type){ + if(Constants.Event.SCROLL.equals(type)){ + return true; + }else if(Constants.Event.SCROLL_START.equals(type)){ + return true; + }else if(Constants.Event.SCROLL_END.equals(type)){ + return true; + } + return false; + } +} diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java index bf518703be..e8920d39c3 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java @@ -58,13 +58,13 @@ import com.taobao.weex.ui.component.WXLoading; import com.taobao.weex.ui.component.WXRefresh; import com.taobao.weex.ui.component.WXVContainer; +import com.taobao.weex.ui.component.helper.ScrollStartEndHelper; import com.taobao.weex.ui.component.helper.WXStickyHelper; import com.taobao.weex.ui.view.listview.WXRecyclerView; import com.taobao.weex.ui.view.listview.adapter.IOnLoadMoreListener; import com.taobao.weex.ui.view.listview.adapter.IRecyclerAdapterListener; import com.taobao.weex.ui.view.listview.adapter.ListBaseViewHolder; import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter; -import com.taobao.weex.ui.view.listview.adapter.TransformItemDecoration; import com.taobao.weex.ui.view.listview.adapter.WXRecyclerViewOnScrollListener; import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXResourceUtils; @@ -78,7 +78,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** @@ -113,6 +112,7 @@ public abstract class BasicListComponent getScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY){ if(getOrientation() == Constants.Orientation.VERTICAL){ offsetY = - calcContentOffset(recyclerView); } @@ -1274,8 +1291,7 @@ private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth())); event.put(Constants.Name.CONTENT_SIZE, contentSize); event.put(Constants.Name.CONTENT_OFFSET, contentOffset); - - fireEvent(Constants.Event.SCROLL, event); + return event; } private boolean shouldReport(int offsetX, int offsetY) { @@ -1356,4 +1372,11 @@ private int calcContentOffset(RecyclerView recyclerView) { //Unhandled LayoutManager type return -1; } + + public ScrollStartEndHelper getScrollStartEndHelper() { + if(mScrollStartEndHelper == null){ + mScrollStartEndHelper = new ScrollStartEndHelper(this); + } + return mScrollStartEndHelper; + } } diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java index 76bcce06f1..2e2992f25e 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java @@ -44,16 +44,13 @@ import com.alibaba.fastjson.JSONObject; import com.taobao.weex.WXEnvironment; import com.taobao.weex.WXSDKInstance; -import com.taobao.weex.WXSDKManager; import com.taobao.weex.annotation.Component; import com.taobao.weex.annotation.JSMethod; -import com.taobao.weex.bridge.WXBridgeManager; import com.taobao.weex.common.Constants; import com.taobao.weex.common.ICheckBindingScroller; import com.taobao.weex.common.OnWXScrollListener; import com.taobao.weex.dom.WXAttr; import com.taobao.weex.dom.WXCellDomObject; -import com.taobao.weex.dom.WXDomHandler; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.dom.WXEvent; import com.taobao.weex.dom.WXRecyclerDomObject; @@ -70,6 +67,7 @@ import com.taobao.weex.ui.component.WXVContainer; import com.taobao.weex.ui.component.binding.Layouts; import com.taobao.weex.ui.component.binding.Statements; +import com.taobao.weex.ui.component.helper.ScrollStartEndHelper; import com.taobao.weex.ui.component.list.RecyclerTransform; import com.taobao.weex.ui.component.list.WXCell; import com.taobao.weex.ui.view.listview.WXRecyclerView; @@ -132,6 +130,7 @@ public class WXRecyclerTemplateList extends WXVContainer imp private boolean isScrollable = true; private int mOffsetAccuracy = 10; private Point mLastReport = new Point(-1, -1); + private boolean mHasAddScrollEvent = false; private JSONArray listData; private String listDataKey = Constants.Name.Recycler.LIST_DATA; @@ -148,6 +147,13 @@ public class WXRecyclerTemplateList extends WXVContainer imp private int templateCacheSize = 2; + /** + * scroll start and scroll end event + * */ + private ScrollStartEndHelper mScrollStartEndHelper; + + + /** * sticky helper * */ @@ -827,7 +833,11 @@ public void updateProperties(Map props) { @Override public void addEvent(String type) { super.addEvent(type); - if (Constants.Event.SCROLL.equals(type) && getHostView() != null && getHostView().getInnerView() != null) { + if (ScrollStartEndHelper.isScrollEvent(type) + && getHostView() != null + && getHostView().getInnerView() != null + && !mHasAddScrollEvent) { + mHasAddScrollEvent = true; WXRecyclerView innerView = getHostView().getInnerView(); innerView.addOnScrollListener(new RecyclerView.OnScrollListener() { private int offsetXCorrection, offsetYCorrection; @@ -852,7 +862,10 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { offsetX = offsetX - offsetXCorrection; offsetY = offsetY - offsetYCorrection; } - + getScrollStartEndHelper().onScrolled(offsetX, offsetY); + if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){ + return; + } if (mFirstEvent) { //skip first event mFirstEvent = false; @@ -868,6 +881,10 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY) { + fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, offsetX, offsetY)); + } + + public Map getScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY){ offsetY = -calcContentOffset(recyclerView); int contentWidth = recyclerView.getMeasuredWidth() + recyclerView.computeHorizontalScrollRange(); int contentHeight = calcContentSize(); @@ -883,10 +900,11 @@ private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int offsetY contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth())); event.put(Constants.Name.CONTENT_SIZE, contentSize); event.put(Constants.Name.CONTENT_OFFSET, contentOffset); - - fireEvent(Constants.Event.SCROLL, event); + return event; } + + private boolean shouldReport(int offsetX, int offsetY) { if (mLastReport.x == -1 && mLastReport.y == -1) { mLastReport.x = offsetX; @@ -1639,4 +1657,11 @@ private static void doInitLazyCell(WXCell component, String template, boolean i } } } + + public ScrollStartEndHelper getScrollStartEndHelper() { + if(mScrollStartEndHelper == null){ + mScrollStartEndHelper = new ScrollStartEndHelper(this); + } + return mScrollStartEndHelper; + } }