| /* |
| * 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; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import android.annotation.TargetApi; |
| import android.content.Context; |
| import android.graphics.Point; |
| import android.graphics.Rect; |
| import android.os.Build; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.support.annotation.NonNull; |
| import android.text.TextUtils; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewTreeObserver; |
| import android.widget.FrameLayout; |
| import android.widget.FrameLayout.LayoutParams; |
| import com.taobao.weex.WXEnvironment; |
| import com.taobao.weex.WXSDKInstance; |
| import com.taobao.weex.annotation.Component; |
| import com.taobao.weex.annotation.JSMethod; |
| import com.taobao.weex.common.Constants; |
| import com.taobao.weex.common.ICheckBindingScroller; |
| import com.taobao.weex.common.OnWXScrollListener; |
| import com.taobao.weex.common.WXThread; |
| import com.taobao.weex.ui.ComponentCreator; |
| import com.taobao.weex.ui.action.BasicComponentData; |
| 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; |
| import com.taobao.weex.ui.view.WXHorizontalScrollView; |
| import com.taobao.weex.ui.view.WXScrollView; |
| import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener; |
| import com.taobao.weex.ui.view.refresh.wrapper.BaseBounceView; |
| import com.taobao.weex.ui.view.refresh.wrapper.BounceScrollerView; |
| import com.taobao.weex.utils.WXLogUtils; |
| import com.taobao.weex.utils.WXUtils; |
| import com.taobao.weex.utils.WXViewUtils; |
| |
| /** |
| * Component for scroller. It also support features like |
| * "appear", "disappear" and "sticky" |
| */ |
| @Component(lazyload = false) |
| |
| public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewListener,Scrollable { |
| |
| public static final String DIRECTION = "direction"; |
| protected int mOrientation = Constants.Orientation.VERTICAL; |
| private List<WXComponent> mRefreshs=new ArrayList<>(); |
| /** Use for offset children layout */ |
| private int mChildrenLayoutOffset = 0; |
| 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 { |
| @Override |
| public WXComponent createInstance(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) throws IllegalAccessException, InvocationTargetException, InstantiationException { |
| return new WXScroller(instance, parent, basicComponentData); |
| } |
| } |
| /** |
| * Map for storing appear information |
| **/ |
| private Map<String,AppearanceHelper> mAppearanceComponents = new HashMap<>(); |
| |
| /** |
| * Map for storing component that is sticky. |
| **/ |
| private Map<String, Map<String, WXComponent>> mStickyMap = new HashMap<>(); |
| private FrameLayout mRealView; |
| |
| private int mContentHeight = 0; |
| |
| private WXStickyHelper stickyHelper; |
| private Handler handler=new Handler(Looper.getMainLooper()); |
| |
| private boolean isScrollable = true; |
| |
| @Deprecated |
| public WXScroller(WXSDKInstance instance, WXVContainer parent, String instanceId, boolean isLazy, BasicComponentData basicComponentData) { |
| this(instance, parent, basicComponentData); |
| } |
| |
| public WXScroller(WXSDKInstance instance, WXVContainer parent, BasicComponentData basicComponentData) { |
| super(instance, parent, basicComponentData); |
| stickyHelper = new WXStickyHelper(this); |
| } |
| |
| /** |
| * @return FrameLayout inner ScrollView |
| */ |
| @Override |
| public ViewGroup getRealView() { |
| return mRealView; |
| } |
| |
| |
| @Override |
| public void createViewImpl() { |
| super.createViewImpl(); |
| for (int i = 0; i < mRefreshs.size(); i++) { |
| WXComponent component = mRefreshs.get(i); |
| component.createViewImpl(); |
| checkRefreshOrLoading(component); |
| } |
| } |
| |
| /** |
| * @return ScrollView |
| */ |
| public ViewGroup getInnerView() { |
| if(getHostView() == null) { |
| return null; |
| } |
| if (getHostView() instanceof BounceScrollerView) { |
| return ((BounceScrollerView) getHostView()).getInnerView(); |
| } else { |
| return getHostView(); |
| } |
| } |
| |
| @Override |
| public void addEvent(String type) { |
| super.addEvent(type); |
| 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(!getEvents().contains(Constants.Event.SCROLL)){ |
| return; |
| } |
| if (shouldReport(x, y)) { |
| fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy); |
| } |
| } |
| |
| @Override |
| public void onScrollToBottom(WXScrollView scrollView, int x, int y) { |
| //ignore |
| } |
| |
| @Override |
| public void onScrollStopped(WXScrollView scrollView, int x, int y) { |
| //ignore |
| } |
| |
| @Override |
| public void onScroll(WXScrollView scrollView, int x, int y) { |
| //ignore |
| } |
| }); |
| } else if (getInnerView() instanceof WXHorizontalScrollView) { |
| ((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(!getEvents().contains(Constants.Event.SCROLL)){ |
| return; |
| } |
| if (shouldReport(x, y)) { |
| fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy); |
| } |
| } |
| }); |
| } |
| } |
| } |
| |
| private void fireScrollEvent(Rect contentFrame, int x, int y, int oldx, int oldy) { |
| fireEvent(Constants.Event.SCROLL, getScrollEvent(x, y)); |
| } |
| |
| public Map<String, Object> 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<String, Object> event = new HashMap<>(2); |
| Map<String, Object> contentSize = new HashMap<>(2); |
| Map<String, Object> contentOffset = new HashMap<>(2); |
| |
| int viewport = getInstance().getInstanceViewPortWidth(); |
| |
| contentSize.put(Constants.Name.WIDTH, WXViewUtils.getWebPxByWidth(contentFrame.width(), viewport)); |
| contentSize.put(Constants.Name.HEIGHT, WXViewUtils.getWebPxByWidth(contentFrame.height(), viewport)); |
| |
| contentOffset.put(Constants.Name.X, -WXViewUtils.getWebPxByWidth(x, viewport)); |
| contentOffset.put(Constants.Name.Y, -WXViewUtils.getWebPxByWidth(y, viewport)); |
| |
| event.put(Constants.Name.CONTENT_SIZE, contentSize); |
| event.put(Constants.Name.CONTENT_OFFSET, contentOffset); |
| return event; |
| } |
| |
| private boolean shouldReport(int x, int y) { |
| if (mLastReport.x == -1 && mLastReport.y == -1) { |
| mLastReport.x = x; |
| mLastReport.y = y; |
| return true; |
| } |
| |
| if (mOrientation == Constants.Orientation.HORIZONTAL |
| && Math.abs(x - mLastReport.x) >= mOffsetAccuracy) { |
| mLastReport.x = x; |
| mLastReport.y = y; |
| return true; |
| } |
| |
| if (mOrientation == Constants.Orientation.VERTICAL |
| && Math.abs(y - mLastReport.y) >= mOffsetAccuracy) { |
| mLastReport.x = x; |
| mLastReport.y = y; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Intercept refresh view and loading view |
| */ |
| @Override |
| public void addSubView(View child, int index) { |
| if (child == null || getRealView() == null) { |
| return; |
| } |
| |
| if (child instanceof WXBaseRefreshLayout) { |
| return; |
| } |
| |
| int count = getRealView().getChildCount(); |
| index = index >= count ? -1 : index; |
| if (index == -1) { |
| getRealView().addView(child); |
| } else { |
| getRealView().addView(child, index); |
| } |
| } |
| |
| @Override |
| protected int getChildrenLayoutTopOffset() { |
| if (mChildrenLayoutOffset == 0) { |
| // Child LayoutSize data set after call Layout. So init mChildrenLayoutOffset here |
| final int listSize = mRefreshs.size(); |
| if (listSize > 0) { |
| for (int i = 0; i < listSize; i++) { |
| WXComponent child = mRefreshs.get(i); |
| mChildrenLayoutOffset += child.getLayoutTopOffsetForSibling(); |
| } |
| } |
| } |
| return mChildrenLayoutOffset; |
| } |
| |
| /** |
| * Intercept refresh view and loading view |
| */ |
| @Override |
| public void addChild(WXComponent child, int index) { |
| if (child instanceof WXBaseRefresh) { |
| if (checkRefreshOrLoading(child)) { |
| mRefreshs.add(child); |
| } |
| } |
| super.addChild(child, index); |
| } |
| |
| /** |
| * Setting refresh view and loading view |
| * @param child the refresh_view or loading_view |
| */ |
| |
| private boolean checkRefreshOrLoading(final WXComponent child) { |
| boolean result = false; |
| if (child instanceof WXRefresh && getHostView() != null) { |
| ((BaseBounceView) getHostView()).setOnRefreshListener((WXRefresh) child); |
| Runnable runnable = WXThread.secure(new Runnable(){ |
| @Override |
| public void run() { |
| ((BaseBounceView) getHostView()).setHeaderView(child); |
| } |
| }); |
| handler.postDelayed(runnable,100); |
| result = true; |
| } |
| |
| if (child instanceof WXLoading && getHostView() !=null) { |
| ((BaseBounceView) getHostView()).setOnLoadingListener((WXLoading)child); |
| Runnable runnable= WXThread.secure(new Runnable(){ |
| @Override |
| public void run() { |
| ((BaseBounceView) getHostView()).setFooterView(child); |
| } |
| }); |
| handler.postDelayed(runnable, 100); |
| result = true; |
| } |
| return result; |
| } |
| |
| @Override |
| public void remove(WXComponent child,boolean destory) { |
| super.remove(child,destory); |
| if(child instanceof WXLoading){ |
| ((BaseBounceView)getHostView()).removeFooterView(child); |
| }else if(child instanceof WXRefresh){ |
| ((BaseBounceView)getHostView()).removeHeaderView(child); |
| } |
| } |
| |
| @Override |
| public void destroy() { |
| super.destroy(); |
| if (mAppearanceComponents != null) { |
| mAppearanceComponents.clear(); |
| } |
| if (mStickyMap != null) { |
| mStickyMap.clear(); |
| } |
| if (getInnerView() != null && getInnerView() instanceof IWXScroller) { |
| ((IWXScroller) getInnerView()).destroy(); |
| } |
| } |
| |
| @Override |
| protected MeasureOutput measure(int width, int height) { |
| MeasureOutput measureOutput = new MeasureOutput(); |
| if (this.mOrientation == Constants.Orientation.HORIZONTAL) { |
| int screenW = WXViewUtils.getScreenWidth(WXEnvironment.sApplication); |
| int weexW = WXViewUtils.getWeexWidth(getInstanceId()); |
| measureOutput.width = width > (weexW >= screenW ? screenW : weexW) ? FrameLayout.LayoutParams.MATCH_PARENT |
| : width; |
| measureOutput.height = height; |
| } else { |
| int screenH = WXViewUtils.getScreenHeight(WXEnvironment.sApplication); |
| int weexH = WXViewUtils.getWeexHeight(getInstanceId()); |
| measureOutput.height = height > (weexH >= screenH ? screenH : weexH) ? FrameLayout.LayoutParams.MATCH_PARENT |
| : height; |
| measureOutput.width = width; |
| } |
| return measureOutput; |
| } |
| |
| @Override |
| protected ViewGroup initComponentHostView(@NonNull Context context) { |
| String scroll; |
| if (getAttrs().isEmpty()) { |
| scroll = "vertical"; |
| } else { |
| scroll = getAttrs().getScrollDirection(); |
| } |
| |
| ViewGroup host; |
| if(("horizontal").equals(scroll)){ |
| mOrientation = Constants.Orientation.HORIZONTAL; |
| WXHorizontalScrollView scrollView = new WXHorizontalScrollView(context); |
| mRealView = new FrameLayout(context); |
| scrollView.setScrollViewListener(new WXHorizontalScrollView.ScrollViewListener() { |
| @Override |
| public void onScrollChanged(WXHorizontalScrollView scrollView, int x, int y, int oldx, int oldy) { |
| procAppear(x,y,oldx,oldy); |
| } |
| }); |
| FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( |
| LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); |
| scrollView.addView(mRealView, layoutParams); |
| scrollView.setHorizontalScrollBarEnabled(false); |
| |
| host = scrollView; |
| }else{ |
| mOrientation = Constants.Orientation.VERTICAL; |
| BounceScrollerView scrollerView = new BounceScrollerView(context, mOrientation, this); |
| mRealView = new FrameLayout(context); |
| WXScrollView innerView = scrollerView.getInnerView(); |
| innerView.addScrollViewListener(this); |
| FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( |
| LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); |
| innerView.addView(mRealView, layoutParams); |
| innerView.setVerticalScrollBarEnabled(true); |
| innerView.setNestedScrollingEnabled(WXUtils.getBoolean(getAttrs().get(Constants.Name.NEST_SCROLLING_ENABLED), true)); |
| innerView.addScrollViewListener(new WXScrollViewListener() { |
| @Override |
| public void onScrollChanged(WXScrollView scrollView, int x, int y, int oldx, int oldy) { |
| |
| } |
| |
| @Override |
| public void onScrollToBottom(WXScrollView scrollView, int x, int y) { |
| |
| } |
| |
| @Override |
| public void onScrollStopped(WXScrollView scrollView, int x, int y) { |
| List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners(); |
| if(listeners!=null && listeners.size()>0){ |
| for (OnWXScrollListener listener : listeners) { |
| if (listener != null) { |
| listener.onScrollStateChanged(scrollView,x,y,OnWXScrollListener.IDLE); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void onScroll(WXScrollView scrollView, int x, int y) { |
| List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners(); |
| if(listeners!=null && listeners.size()>0){ |
| for (OnWXScrollListener listener : listeners) { |
| if (listener != null) { |
| if(listener instanceof ICheckBindingScroller){ |
| if(((ICheckBindingScroller) listener).isNeedScroller(getRef(),null)){ |
| listener.onScrolled(scrollView, x, y); |
| } |
| }else { |
| listener.onScrolled(scrollView, x, y); |
| } |
| } |
| } |
| } |
| } |
| }); |
| host = scrollerView; |
| } |
| |
| host.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { |
| @TargetApi(Build.VERSION_CODES.JELLY_BEAN) |
| @Override |
| public void onGlobalLayout() { |
| procAppear(0,0,0,0); |
| View view; |
| if( (view = getHostView()) == null){ |
| return; |
| } |
| if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
| view.getViewTreeObserver().removeOnGlobalLayoutListener(this); |
| }else{ |
| view.getViewTreeObserver().removeGlobalOnLayoutListener(this); |
| } |
| } |
| }); |
| return host; |
| } |
| |
| @Override |
| public int getScrollY() { |
| return getInnerView() == null ? 0 : getInnerView().getScrollY(); |
| } |
| |
| @Override |
| public int getScrollX() { |
| return getInnerView() == null ? 0 : getInnerView().getScrollX(); |
| } |
| |
| @Override |
| public int getOrientation() { |
| return mOrientation; |
| } |
| |
| public Map<String, Map<String, WXComponent>> getStickMap() { |
| return mStickyMap; |
| } |
| |
| @Override |
| protected boolean setProperty(String key, Object param) { |
| switch (key) { |
| case Constants.Name.SHOW_SCROLLBAR: |
| Boolean result = WXUtils.getBoolean(param,null); |
| if (result != null) { |
| setShowScrollbar(result); |
| } |
| return true; |
| case Constants.Name.SCROLLABLE: |
| boolean scrollable = WXUtils.getBoolean(param, true); |
| setScrollable(scrollable); |
| return true; |
| case Constants.Name.OFFSET_ACCURACY: |
| int accuracy = WXUtils.getInteger(param, 10); |
| setOffsetAccuracy(accuracy); |
| return true; |
| default: |
| break; |
| } |
| return super.setProperty(key, param); |
| } |
| |
| @WXComponentProp(name = Constants.Name.SHOW_SCROLLBAR) |
| public void setShowScrollbar(boolean show) { |
| if(getInnerView()==null){ |
| return; |
| } |
| if (mOrientation == Constants.Orientation.VERTICAL) { |
| getInnerView().setVerticalScrollBarEnabled(show); |
| } else { |
| getInnerView().setHorizontalScrollBarEnabled(show); |
| } |
| } |
| |
| @WXComponentProp(name = Constants.Name.SCROLLABLE) |
| public void setScrollable(boolean scrollable) { |
| this.isScrollable = scrollable; |
| View hostView = getInnerView(); |
| if(hostView instanceof WXHorizontalScrollView) { |
| ((WXHorizontalScrollView)hostView).setScrollable(scrollable); |
| }else if(hostView instanceof WXScrollView) { |
| ((WXScrollView)hostView).setScrollable(scrollable); |
| } |
| } |
| |
| @WXComponentProp(name = Constants.Name.OFFSET_ACCURACY) |
| public void setOffsetAccuracy(int accuracy) { |
| float realPx = WXViewUtils.getRealPxByWidth(accuracy, getInstance().getInstanceViewPortWidth()); |
| this.mOffsetAccuracy = (int) realPx; |
| } |
| |
| @Override |
| public boolean isScrollable() { |
| return isScrollable; |
| } |
| |
| |
| @Override |
| public void bindStickStyle(WXComponent component) { |
| stickyHelper.bindStickStyle(component,mStickyMap); |
| } |
| |
| @Override |
| public void unbindStickStyle(WXComponent component) { |
| stickyHelper.unbindStickStyle(component,mStickyMap); |
| } |
| |
| /** |
| * Bind appear event |
| */ |
| @Override |
| public void bindAppearEvent(WXComponent component) { |
| setWatch(AppearanceHelper.APPEAR,component,true); |
| } |
| |
| private void setWatch(int event,WXComponent component,boolean isWatch){ |
| AppearanceHelper item = mAppearanceComponents.get(component.getRef()); |
| if (item == null) { |
| item = new AppearanceHelper(component); |
| mAppearanceComponents.put(component.getRef(),item); |
| } |
| |
| item.setWatchEvent(event,isWatch); |
| |
| //check current components appearance status. |
| procAppear(0,0,0,0); |
| } |
| |
| /** |
| * Bind disappear event |
| */ |
| @Override |
| public void bindDisappearEvent(WXComponent component) { |
| setWatch(AppearanceHelper.DISAPPEAR,component,true); |
| } |
| |
| /** |
| * Remove appear event |
| */ |
| @Override |
| public void unbindAppearEvent(WXComponent component) { |
| setWatch(AppearanceHelper.APPEAR,component,false); |
| } |
| |
| /** |
| * Remove disappear event |
| */ |
| @Override |
| public void unbindDisappearEvent(WXComponent component) { |
| setWatch(AppearanceHelper.DISAPPEAR,component,false); |
| } |
| |
| @Override |
| public void scrollTo(WXComponent component, Map<String, Object> options) { |
| float offsetFloat = 0; |
| boolean smooth = true; |
| |
| if (options != null) { |
| String offset = options.get(Constants.Name.OFFSET) == null ? "0" : options.get(Constants.Name.OFFSET).toString(); |
| smooth = WXUtils.getBoolean(options.get(Constants.Name.ANIMATED), true); |
| if (offset != null) { |
| try { |
| offsetFloat = WXViewUtils.getRealPxByWidth(Float.parseFloat(offset), getInstance().getInstanceViewPortWidth()); |
| }catch (Exception e ){ |
| WXLogUtils.e("Float parseFloat error :"+e.getMessage()); |
| } |
| } |
| } |
| |
| int viewYInScroller=component.getAbsoluteY() - getAbsoluteY(); |
| int viewXInScroller=component.getAbsoluteX() - getAbsoluteX(); |
| |
| scrollBy(viewXInScroller - getScrollX() + (int) offsetFloat, viewYInScroller - getScrollY() + (int) offsetFloat, smooth); |
| } |
| |
| /** |
| * Scroll by specified distance. Horizontal scroll is not supported now. |
| * @param x horizontal distance, not support |
| * @param y vertical distance. Negative for scroll to top |
| */ |
| public void scrollBy(final int x, final int y) { |
| scrollBy(x, y, false); |
| } |
| |
| public void scrollBy(final int x, final int y, final boolean smooth) { |
| if (getInnerView() == null) { |
| return; |
| } |
| |
| getInnerView().postDelayed(new Runnable() { |
| @Override |
| public void run() { |
| if (mOrientation == Constants.Orientation.VERTICAL) { |
| if (smooth) { |
| ((WXScrollView) getInnerView()).smoothScrollBy(0, y); |
| } else { |
| ((WXScrollView) getInnerView()).scrollBy(0, y); |
| } |
| } else { |
| if (smooth) { |
| ((WXHorizontalScrollView) getInnerView()).smoothScrollBy(x, 0); |
| } else { |
| ((WXHorizontalScrollView) getInnerView()).scrollBy(x, 0); |
| } |
| } |
| getInnerView().invalidate(); |
| } |
| }, 16); |
| } |
| |
| @Override |
| public void onScrollChanged(WXScrollView scrollView, int x, int y, |
| int oldx, int oldy) { |
| procAppear( x, y, oldx, oldy); |
| } |
| |
| /** |
| * Process event like appear and disappear |
| */ |
| private void procAppear(int x, int y, int oldx, |
| int oldy) { |
| int moveY = y - oldy; |
| int moveX = x - oldx; |
| String direction = moveY > 0 ? Constants.Value.DIRECTION_UP : |
| moveY < 0 ? Constants.Value.DIRECTION_DOWN : null; |
| if (mOrientation == Constants.Orientation.HORIZONTAL && moveX != 0) { |
| direction = moveX > 0 ? Constants.Value.DIRECTION_RIGHT : Constants.Value.DIRECTION_LEFT; |
| } |
| |
| for (Entry<String, AppearanceHelper> item : mAppearanceComponents.entrySet()) { |
| AppearanceHelper helper = item.getValue(); |
| |
| if (!helper.isWatch()) { |
| continue; |
| } |
| boolean visible = helper.isViewVisible(false); |
| |
| int result = helper.setAppearStatus(visible); |
| if (result != AppearanceHelper.RESULT_NO_CHANGE) { |
| helper.getAwareChild().notifyAppearStateChange(result == AppearanceHelper.RESULT_APPEAR ? Constants.Event.APPEAR : Constants.Event.DISAPPEAR, direction); |
| } |
| } |
| } |
| |
| @Override |
| public void onScrollToBottom(WXScrollView scrollView, int x, int y) { |
| |
| } |
| |
| @Override |
| public void onScrollStopped(WXScrollView scrollView, int x, int y) { |
| } |
| |
| @Override |
| public void onScroll(WXScrollView scrollView, int x, int y) { |
| |
| this.onLoadMore(scrollView, x, y); |
| } |
| |
| /** |
| * Handle loadMore Event.when Scroller has bind loadMore Event and set the attr of loadMoreOffset |
| * it will tell the JS to handle the event of onLoadMore; |
| * @param scrollView the WXScrollView |
| * @param x the X direction |
| * @param y the Y direction |
| */ |
| protected void onLoadMore(WXScrollView scrollView, int x, int y) { |
| try { |
| String offset = getAttrs().getLoadMoreOffset(); |
| if (TextUtils.isEmpty(offset)) { |
| return; |
| } |
| int offsetInt = (int)WXViewUtils.getRealPxByWidth(Float.parseFloat(offset), getInstance().getInstanceViewPortWidth()); |
| |
| int contentH = scrollView.getChildAt(0).getHeight(); |
| int scrollerH = scrollView.getHeight(); |
| int offScreenY = contentH - y - scrollerH; |
| if (offScreenY < offsetInt) { |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.d("[WXScroller-onScroll] offScreenY :" + offScreenY); |
| } |
| if (mContentHeight != contentH || mForceLoadmoreNextTime) { |
| fireEvent(Constants.Event.LOADMORE); |
| mContentHeight = contentH; |
| mForceLoadmoreNextTime = false; |
| } |
| } |
| } catch (Exception e) { |
| WXLogUtils.d("[WXScroller-onScroll] ", e); |
| } |
| |
| } |
| |
| @JSMethod |
| public void resetLoadmore() { |
| mForceLoadmoreNextTime = true; |
| } |
| |
| public ScrollStartEndHelper getScrollStartEndHelper() { |
| if(mScrollStartEndHelper == null){ |
| mScrollStartEndHelper = new ScrollStartEndHelper(this); |
| } |
| return mScrollStartEndHelper; |
| } |
| } |