/* * Copyright (C) 2014 The AppCan Open Source Project. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.zywx.wbpalmstar.engine; import org.json.JSONObject; import org.zywx.wbpalmstar.base.BUtility; import org.zywx.wbpalmstar.base.WebViewSdkCompat; import org.zywx.wbpalmstar.engine.external.Compat; import org.zywx.wbpalmstar.engine.universalex.EUExScript; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.widget.LinearLayout; import android.widget.Scroller; public class EBounceView extends LinearLayout { private int mLastY; private Context mContext; private Scroller mScroller; public EBrowserView mBrwView; private EBounceViewHeader mTailView; private EBounceViewHeader mHeaderView; private int mRefrshHeight; private int mBounceViewHeight; private boolean mShowTopView; private boolean mShowBottomView; private boolean mBounce; private boolean mIsTop; private boolean mIsBottom; private boolean mTopLoading; private boolean mBottomLoading; private boolean mTopNotify; private boolean mBottomNotify; private boolean mTopAutoRefresh = false; private boolean isSupportSwipeCallback = true;// 兼容旧引擎,把默认值从false改为true,要防止与多浮动窗口的手势冲突需要调用接口设置为false private int mTopState; private int mBottomState; private int mTopBund; private int mBotomBund; private int mTouchSlop; public String mPullStr; public String mPullingStr; public String mReleaseStr; static final int F_VIEW_STATE_DRAG = 0; static final int F_VIEW_STATE_RELEASE = 1; static final int F_BOUNCEVIEW_STATE_PULL_RELOAD = 0; static final int F_BOUNCEVIEW_STATE_RELEASE_RELOAD = 1; static final int F_BOUNCEVIEW_STATE_LOADING = 2; public static final int F_SET_BOUNCEVIEW_TYPE_STR1 = 0; public static final int F_SET_BOUNCEVIEW_TYPE_STR2 = 1; public static final int F_SET_BOUNCEVIEW_TYPE_STR3 = 2; public static final int F_SET_BOUNCEVIEW_TYPE_STR4 = 3; public static final int F_SET_BOUNCEVIEW_TYPE_STR5 = 4; private float mDensity = ESystemInfo.getIntence().mDensity; public EBounceView(Context context) { super(context); mContext = context; mScroller = new Scroller(mContext); mRefrshHeight = ESystemInfo.getIntence().mDefaultBounceHeight; mBounceViewHeight = (ESystemInfo.getIntence().mHeightPixels / 3) * 2; setAnimationCacheEnabled(false); setAlwaysDrawnWithCacheEnabled(false); setOrientation(VERTICAL); mTopBund = -mRefrshHeight; mBotomBund = mRefrshHeight; mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() / 2; } @Override public void addView(View child) { mHeaderView = new EBounceViewHeader(mContext, EViewEntry.F_BOUNCE_TYPE_TOP); LayoutParams hlp = new LinearLayout.LayoutParams(Compat.FILL, mBounceViewHeight); hlp.topMargin = -mBounceViewHeight; hlp.gravity = Gravity.CENTER; addView(mHeaderView, hlp); mHeaderView.setVisibility(GONE); mBrwView = (EBrowserView) child; LayoutParams wlp = new LinearLayout.LayoutParams(Compat.FILL, Compat.FILL); wlp.weight = 1.0f; addView(mBrwView, wlp); mTailView = new EBounceViewHeader(mContext, EViewEntry.F_BOUNCE_TYPE_BOTTOM); LayoutParams tlp = new LinearLayout.LayoutParams(Compat.FILL, mBounceViewHeight); tlp.bottomMargin = -mBounceViewHeight; tlp.gravity = Gravity.CENTER; addView(mTailView, tlp); mTailView.setVisibility(GONE); } private VelocityTracker mVelocityTracker; @Override public boolean onInterceptTouchEvent(MotionEvent e) { int action = e.getAction(); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(e); if (!mBounce) { switch (action) { case MotionEvent.ACTION_UP: handlerTracker(); break; } return false; } int y = (int) e.getRawY(); switch (action) { case MotionEvent.ACTION_DOWN: mLastY = y; break; case MotionEvent.ACTION_MOVE: int m = y - mLastY; boolean can = (m >= 0 ? m : -m) > mTouchSlop; if (m > 0 && !mBottomLoading && can && !mTopAutoRefresh) { if (topCanBounce()) { mIsTop = true; if (mTopNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_TOP, F_BOUNCEVIEW_STATE_PULL_RELOAD); } return true; } } else if (m < 0 && !mTopLoading && can) { if (bottomCanBounce()) { mIsBottom = true; if (mBottomNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_BOTTOM, F_BOUNCEVIEW_STATE_PULL_RELOAD); } return true; } } mLastY = y; break; case MotionEvent.ACTION_UP: handlerTracker(); break; } return false; } @Override public boolean onTouchEvent(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); int y = (int) event.getRawY(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mLastY = y; break; case MotionEvent.ACTION_MOVE: int m = y - mLastY; if (mIsTop) { moveDown(m); } else if (mIsBottom) { moveUp(m); } mLastY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_OUTSIDE: reverse(); handlerTracker(); break; } return true; } private boolean handlerTracker() { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000); int velocityX = (int) (velocityTracker.getXVelocity() / mDensity); int velocityY = (int) (velocityTracker.getYVelocity() / mDensity); endDrag(); return onTracker(velocityX, velocityY); } private void endDrag() { if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } private boolean onTracker(int velocityX, int velocityY) { boolean trigger = false; if (isSupportSwipeCallback) { final int absY = (velocityY < 0) ? -velocityY : velocityY; final int absX = (velocityX < 0) ? -velocityX : velocityX; int rate = ESystemInfo.getIntence().mSwipeRate; if ((velocityX > rate) && (absX > absY)) { mBrwView.loadUrl(EUExScript.F_UEX_SCRIPT_SWIPE_RIGHT); trigger = true; } else if ((velocityX < -rate) && (absX > absY)) { mBrwView.loadUrl(EUExScript.F_UEX_SCRIPT_SWIPE_LEFT); trigger = true; } } return trigger; } private void moveDown(int moveY) { int f1 = getScrollY(); int f2 = 0; if (moveY > 0) { f2 = (int) (moveY * 0.5F); } else { f2 = (int) (moveY * 0.7F); int bound = f1 - f2; if (bound >= 0) { f2 = f2 + bound; scrollBy(0, -f2); return; } } scrollBy(0, -f2); if (f1 <= mTopBund && mTopState == F_VIEW_STATE_DRAG) { if (mShowTopView && mTopNotify) { mHeaderView.setArrowVisibility(VISIBLE); mHeaderView.setProgressBarVisibility(GONE); mHeaderView.showReleaseToReloadText(); mHeaderView.rotateArrowImage(EBounceViewHeader.F_ROTATE_UP); } if (mTopLoading) { mTopLoading = false; } mTopState = F_VIEW_STATE_RELEASE; } else if (f1 > mTopBund && mTopState == F_VIEW_STATE_RELEASE) { if (mShowTopView && mTopNotify) { mHeaderView.setArrowVisibility(VISIBLE); mHeaderView.setProgressBarVisibility(GONE); mHeaderView.showPullToReloadText(); mHeaderView.rotateArrowImage(EBounceViewHeader.F_ROTATE_DOWN); } mTopState = F_VIEW_STATE_DRAG; } return; } private void moveUp(int moveY) { int f1 = getScrollY(); int f2 = 0; if (moveY < 0) { f2 = (int) (moveY * 0.5F); } else { f2 = (int) (moveY * 0.7F); int bound = f1 - f2; if (bound <= 0) { f2 = f2 + bound; scrollBy(0, -f2); return; } } scrollBy(0, -f2); if (f1 >= mBotomBund && mBottomState == F_VIEW_STATE_DRAG) { if (mShowBottomView && mBottomNotify) { mTailView.setArrowVisibility(VISIBLE); mTailView.setProgressBarVisibility(GONE); mTailView.showReleaseToReloadText(); mTailView.rotateArrowImage(EBounceViewHeader.F_ROTATE_DOWN); } if (mBottomLoading) { mBottomLoading = false; } mBottomState = F_VIEW_STATE_RELEASE; } else if (f1 < mBotomBund && mBottomState == F_VIEW_STATE_RELEASE) { if (mShowBottomView && mBottomNotify) { mTailView.setArrowVisibility(VISIBLE); mTailView.setProgressBarVisibility(GONE); mTailView.showPullToReloadText(); mTailView.rotateArrowImage(EBounceViewHeader.F_ROTATE_UP); } mBottomState = F_VIEW_STATE_DRAG; } return; } private void reverse() { int sy = getScrollY(); if (mIsTop) { if (sy <= mTopBund && mTopNotify) { topRefreshing(); } else { backToTop(); } } else if (mIsBottom) { if (sy >= mBotomBund && mBottomNotify) { bottomRefreshing(); } else { backToBottom(); } } } public void topBounceViewRefresh() { if (!mTopLoading) { scrollTo(0, mTopBund); if (mShowTopView) { mHeaderView.setArrowVisibility(GONE); mHeaderView.setProgressBarVisibility(VISIBLE); mHeaderView.setTextVisibility(VISIBLE); mHeaderView.showLoadingText(); } mTopAutoRefresh = true; mTopLoading = true; if (mTopNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_TOP, F_BOUNCEVIEW_STATE_LOADING); } } } private void topRefreshing() { if (mTopNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_TOP, F_BOUNCEVIEW_STATE_RELEASE_RELOAD); } mTopLoading = true; mTopState = F_VIEW_STATE_DRAG; int sy = getScrollY(); int dist = mTopBund - sy; if (mShowTopView) { mHeaderView.setArrowVisibility(GONE); mHeaderView.setProgressBarVisibility(VISIBLE); mHeaderView.setTextVisibility(VISIBLE); mHeaderView.showLoadingText(); } mScroller.startScroll(0, sy, 0, dist); postInvalidate(); if (mTopNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_TOP, F_BOUNCEVIEW_STATE_LOADING); } } private void bottomRefreshing() { if (mBottomNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_BOTTOM, F_BOUNCEVIEW_STATE_RELEASE_RELOAD); } mBottomLoading = true; mBottomState = F_VIEW_STATE_DRAG; int sy = getScrollY(); int dist = sy - mBotomBund; if (mShowBottomView) { mTailView.setArrowVisibility(GONE); mTailView.setProgressBarVisibility(VISIBLE); mTailView.setTextVisibility(VISIBLE); mTailView.showLoadingText(); } mScroller.startScroll(0, -sy, 0, dist); postInvalidate(); if (mBottomNotify) { mBrwView.onBounceStateChange(EViewEntry.F_BOUNCE_TYPE_BOTTOM, F_BOUNCEVIEW_STATE_LOADING); } } private void backToTop() { if (mTopAutoRefresh) { scrollTo(0, 0); mTopAutoRefresh = false; } else { int sy = getScrollY(); int dist = 0 - sy; mScroller.startScroll(0, sy, 0, dist); postInvalidate(); } } private void backToBottom() { int sy = getScrollY(); int dist = sy; mScroller.startScroll(0, -sy, 0, dist); postInvalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { int sy = mScroller.getCurrY(); if (mIsTop) { scrollTo(0, sy); } else if (mIsBottom) { scrollTo(0, -sy); } postInvalidate(); if (sy == 0) { mIsTop = false; mIsBottom = false; // mTopLoading = false; // mBottomLoading = false; } } } private void finishRefresh(int type) { switch (type) { case EViewEntry.F_BOUNCE_TYPE_TOP: if (!mTopLoading) { return; } if (mShowTopView) { mHeaderView.setArrowVisibility(VISIBLE); mHeaderView.setProgressBarVisibility(GONE); mHeaderView.showPullToReloadText(); mHeaderView.rotateArrowImage(EBounceViewHeader.F_ROTATE_DOWN); } backToTop(); break; case EViewEntry.F_BOUNCE_TYPE_BOTTOM: if (!mBottomLoading) { return; } if (mShowBottomView) { mTailView.setArrowVisibility(VISIBLE); mTailView.setProgressBarVisibility(GONE); mTailView.showPullToReloadText(); mTailView.rotateArrowImage(EBounceViewHeader.F_ROTATE_UP); } backToBottom(); break; } clear(); } private void clear() { mTopLoading = false; mBottomLoading = false; } private boolean topCanBounce() { boolean b1 = mBrwView.getScrollYWrap() == 0; if (b1) { return true; } else { return false; } } private boolean bottomCanBounce() { float nowScale= mBrwView.getScaleWrap(); int h1 ; int h2 = mBrwView.getScrollYWrap() + mBrwView.getHeightWrap(); if ("crosswalk".equals(WebViewSdkCompat.type)){ h1 = (int) (mBrwView.getContentHeight() ); }else{ h1 = (int) (mBrwView.getContentHeight() * nowScale); } if (h1 <= h2 + 5) { return true; } else { return false; } } public int getBounce() { int result=mBounce ? 1 : 0; mBrwView.cbBounceState(result); return result; } public void setBounce(boolean flag) { mBounce = flag; mHeaderView.setVisibility(VISIBLE); mTailView.setVisibility(VISIBLE); } public void showBounceView(int inType, int inColor, int inFlag) { switch (inType) { case EViewEntry.F_BOUNCE_TYPE_TOP: mShowTopView = inFlag != 1 ? false : true; if (!mShowTopView) { mHeaderView.componentsDisable(); } mHeaderView.setBackgroundColor(inColor); break; case EViewEntry.F_BOUNCE_TYPE_BOTTOM: mShowBottomView = inFlag != 1 ? false : true; if (!mShowBottomView) { mTailView.componentsDisable(); } mTailView.setBackgroundColor(inColor); break; } } public void resetBounceView(int inType) { finishRefresh(inType); } public void release() { finishRefresh(EViewEntry.F_BOUNCE_TYPE_TOP); finishRefresh(EViewEntry.F_BOUNCE_TYPE_BOTTOM); } public void hiddenBounceView(int inType) { switch (inType) { case EViewEntry.F_BOUNCE_TYPE_TOP: mHeaderView.setVisibility(INVISIBLE); mTopNotify = false; break; case EViewEntry.F_BOUNCE_TYPE_BOTTOM: mTailView.setVisibility(INVISIBLE); mBottomNotify = false; break; } } public void notifyBounceEvent(int inType, int inStatus) { switch (inType) { case EViewEntry.F_BOUNCE_TYPE_TOP: mTopNotify = inStatus != 1 ? false : true; if (mTopNotify) { mHeaderView.componentsEnable(); } break; case EViewEntry.F_BOUNCE_TYPE_BOTTOM: mBottomNotify = inStatus != 1 ? false : true; if (mBottomNotify) { mTailView.componentsEnable(); } break; } } public void setBounceParms(int type, JSONObject json, String guestId) { String imagePath = null; String textColor = null; String levelText = null; String pullToReloadText = null; String releaseToReloadText = null; String loadingText = null; String loadingImagePath = null; imagePath = json.optString("imagePath"); if (null != imagePath) { imagePath = BUtility.makeRealPath(imagePath, mBrwView.getCurrentWidget().m_widgetPath, mBrwView.getCurrentWidget().m_wgtType); } textColor = json.optString("textColor"); levelText = json.optString("levelText"); pullToReloadText = json.optString("pullToReloadText"); releaseToReloadText = json.optString("releaseToReloadText"); loadingText = json.optString("loadingText"); if (null != guestId && guestId.equals("donghang")) { loadingImagePath = json.optString("loadingImagePath"); if (null != loadingImagePath) { loadingImagePath = BUtility.makeRealPath(loadingImagePath, mBrwView.getCurrentWidget().m_widgetPath, mBrwView.getCurrentWidget().m_wgtType); } } switch (type) { case EViewEntry.F_BOUNCE_TYPE_TOP: if (null != imagePath && 0 != imagePath.trim().length()) { mHeaderView.setArrowhead(imagePath); } if (null != loadingImagePath && 0 != loadingImagePath.trim().length()) { mHeaderView.setLoadingPic(loadingImagePath); } if ((null == textColor || 0 == textColor.trim().length()) && (null == pullToReloadText || 0 == pullToReloadText.trim().length()) && (null == releaseToReloadText || 0 == releaseToReloadText.trim().length()) && (null == loadingText || 0 == loadingText.trim().length())) { mHeaderView.setContentEmpty(true); } else { if (null != textColor && 0 != textColor.trim().length()) { int color = mBrwView.parseColor(textColor); mHeaderView.setTextColor(color); } if (null != levelText && 0 != levelText.trim().length()) { mHeaderView.setLevelText(levelText); } if (null != releaseToReloadText && 0 != releaseToReloadText.trim().length()) { mHeaderView.setReleaseToReloadText(releaseToReloadText); } if (null != loadingText && 0 != loadingText.trim().length()) { mHeaderView.setLoadingText(loadingText); } if (null != pullToReloadText && 0 != pullToReloadText.trim().length()) { mHeaderView.setPullToReloadText(pullToReloadText); } } break; case EViewEntry.F_BOUNCE_TYPE_BOTTOM: if (null != imagePath && 0 != imagePath.trim().length()) { mTailView.setArrowhead(imagePath); } if (null != loadingImagePath && 0 != loadingImagePath.trim().length()) { mTailView.setLoadingPic(loadingImagePath); } if ((null == textColor || 0 == textColor.trim().length()) && (null == pullToReloadText || 0 == pullToReloadText.trim().length()) && (null == releaseToReloadText || 0 == releaseToReloadText.trim().length()) && (null == loadingText || 0 == loadingText.trim().length())) { mTailView.setContentEmpty(true); } else { if (null != textColor && 0 != textColor.trim().length()) { int color = mBrwView.parseColor(textColor); mTailView.setTextColor(color); } if (null != levelText && 0 != levelText.trim().length()) { mTailView.setLevelText(levelText); } if (null != releaseToReloadText && 0 != releaseToReloadText.trim().length()) { mTailView.setReleaseToReloadText(releaseToReloadText); } if (null != loadingText && 0 != loadingText.trim().length()) { mTailView.setLoadingText(loadingText); } if (null != pullToReloadText && 0 != pullToReloadText.trim().length()) { mTailView.setPullToReloadText(pullToReloadText); } } break; } } /** * @param flag * @param bgColor * @param baseUrl * @param mEBrowserView * @author wanglei * @createAt 20151124 * @ps 与原EBrowserView的setBrwViewBackground类似,原方法只设置EBrowserView的背景 * 当网页设置弹动效果后,上下滑动到边缘后,会露出EBrowserView下面的网页,故应给EBrowserView * 父对象EBounceView设置背景, EBrowserView背景设成透明。 */ public void setBounceViewBackground(boolean flag, String bgColor, String baseUrl, EBrowserView mEBrowserView) { if (flag) { if(bgColor.startsWith("#") || bgColor.startsWith("rgb")){ int color = BUtility.parseColor(bgColor); setBackgroundColor(color); }else{ String path = BUtility.makeRealPath(BUtility.makeUrl(mEBrowserView.getCurrentUrl(baseUrl),bgColor), mEBrowserView.getCurrentWidget().m_widgetPath, mEBrowserView.getCurrentWidget().m_wgtType); Bitmap bitmap = BUtility.getLocalImg(mContext, path); Drawable d = null; if(bitmap != null){ d = new BitmapDrawable(mContext.getResources(), bitmap); } int version = Build.VERSION.SDK_INT; if(version < 16){ setBackgroundDrawable(d); setBackgroundColor(Color.argb(0, 0, 0, 0)); }else{ setBackground(d); setBackgroundColor(Color.argb(0, 0, 0, 0)); } } } else { setBackgroundColor(Color.TRANSPARENT); } } public void setIsSupportSwipeCallback(boolean isSupport) { isSupportSwipeCallback = isSupport; } }