Android 類似UC瀏覽器的效果:向上滑動地址欄隱藏功能
思路
要求
ScrollView 嵌套 地址欄 和 WebView
手指滑屏向下滾動(網(wǎng)頁向上),如果網(wǎng)頁有滾動條,首先把 地址欄 滾動到消失,然后 WebView 才開始滾動;
手指滑屏向上滾動(網(wǎng)頁向下),如果地址欄隱藏,那么 地址欄 首先慢慢顯示,然后 WebView 才開始滾動。
實現(xiàn)方案
- 根據(jù) View 的 onInterceptTouchEvent 和 onTouchEvent 原理。把 ScrollView 設(shè)置為 WebView 的一個變量,在 WebView的 onInterceptTouchEvent 方法里檢測到 MotionEvent.ACTION_DOWN 事件后中斷事件,在 WebView 的 onTouchEvent 事件中根據(jù)具體情況決定是把 MotionEvent.ACTION_MOVE 事件傳送給 ScrollView 還是留給自己
- 由于MotionEvent.ACTION_MOVE 事件傳送給 ScrollView 后無法在一次 Touch 事件中再接收,所以會導(dǎo)致如果有地址欄,向下滑動第一次只能滑動到 ScrollView 消失
- +
- Hack網(wǎng)頁,加入JS腳本,前行讓網(wǎng)頁頂部空出來一段空白,空白處覆蓋地址欄
- 優(yōu)點是WebView大小不變化,容易控制
- 缺點是比較復(fù)雜要處理各種網(wǎng)頁元素,各種 position 情況,實現(xiàn)復(fù)雜,效率低
- 由手勢接管所有觸發(fā)操作,再由它分發(fā)給需要滾動的控件
本文方法
資源
SrollView下面包含節(jié)點地址欄,WebView控件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/root" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <samples.zjc.com.testbrowserfeature.MyScrollView android:id="@+id/scrollView" android:scrollbars="none" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/toolBar" android:background="#5ff0" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/urlEdit" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content"/> <Button android:id="@+id/goButton" android:text="Go" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <samples.zjc.com.testbrowserfeature.MyWebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="100dp" /> </LinearLayout> </samples.zjc.com.testbrowserfeature.MyScrollView> </RelativeLayout>
ScrollView繼承自 ScrollView
onTouchEvent 中阻止 MotionEvent.ACTION_MOVE 事件 public class MyScrollView extends ScrollView { public MyScrollView(Context context) { super(context); } public MyScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean onTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_MOVE) { return true; } return super.onTouchEvent(ev); } }
MyWebView繼承自 WebView
onTouchEvent 中阻止 MotionEvent.ACTION_MOVE 事件
onDrawListner
計算豎直滾動范圍
public class MyWebView extends WebView { public interface MyWebViewListener { void afterDraw(WebView webView); } private MyWebViewListener mListener; private int mMoveCheckedCnt; public MyWebView(Context context) { super(context); } public MyWebView(Context context, AttributeSet attrs) { super(context, attrs); } public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) { super(context, attrs, defStyleAttr, privateBrowsing); } public void setListener(MyWebViewListener listener) { mListener = listener; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mMoveCheckedCnt = 0; flingScroll(0, 0); break; case MotionEvent.ACTION_MOVE: mMoveCheckedCnt++; return false; case MotionEvent.ACTION_UP: if(mMoveCheckedCnt >= 2) { event.setAction(MotionEvent.ACTION_CANCEL); mMoveCheckedCnt = 0; } break; } return super.onTouchEvent(event); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); MyWebViewListener listener = mListener; if(listener != null) { listener.afterDraw(this); } } public int getVScrollRange() { int v = computeVerticalScrollRange() - computeVerticalScrollExtent(); if(v < 0) { v = 0; } return v; } }
主窗口
GlobalLayoutListener 獲取地址欄和滾動視圖高度
GestureDetector 邏輯分發(fā) - 決定是滑動webview還是改變webview高度從而改變ScrollView滾動范圍(ScrollView總是滾動到最底)
WebView 重畫之后檢測當(dāng)前地址欄偏移
public class MainActivity extends AppCompatActivity implements MyWebView.MyWebViewListener { MyWebView mWebView; GestureDetector mGesture = null; View mToolBar; int mToolBarHeight; MyScrollView mScrollView; int mScrollViewHeight; int mScrollOffset; EditText mUrlEdit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (MyWebView) findViewById(R.id.webView); mWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } }); mWebView.setListener(this); mWebView.loadUrl("http://www.sohu.com"); mUrlEdit = (EditText) findViewById(R.id.urlEdit); findViewById(R.id.goButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String url = mUrlEdit.getText().toString(); if (!url.startsWith("http://") && !url.startsWith("https://")) { url = "http://" + url; } mWebView.loadUrl(url); } }); mToolBar = findViewById(R.id.toolBar); mScrollView = (MyScrollView)findViewById(R.id.scrollView); ScrollView scrollView = (ScrollView) mScrollView; findViewById(R.id.root).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mToolBarHeight = mToolBar.getHeight(); mScrollViewHeight = mScrollView.getHeight(); adjustScrollView(); } }); mGesture = new GestureDetector(this, new GestureListener()); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { mGesture.onTouchEvent(ev); return super.dispatchTouchEvent(ev); } @Override public void afterDraw(WebView webView) { if (mWebView.getVScrollRange() < mScrollOffset) { mScrollOffset = mWebView.getVScrollRange(); adjustScrollView(); } } class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDoubleTap(MotionEvent e) { Log.e("Temp", "onDoubleTap"); return super.onDoubleTap(e); } @Override public boolean onDown(MotionEvent e) { Log.e("Temp", "onDown"); return super.onDown(e); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.e("Temp", "onFling:velocityX = " + velocityX + " velocityY" + velocityY); int effectX = (int) velocityX; int effectY = (int) velocityY; if (effectOnScrollViewByScroll((velocityY < 0 ? 1 : -1) * 8000)) { effectY = 0; } mWebView.flingScroll(-effectX, -effectY); return super.onFling(e1, e2, velocityX, velocityY); } @Override public void onLongPress(MotionEvent e) { Log.e("Temp", "onLongPress"); super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.e("Temp", "onScroll:distanceX = " + distanceX + " distanceY = " + distanceY); int effectX = (int) distanceX; int effectY = (int) distanceY; if (effectOnScrollViewByScroll((int) distanceY)) { effectY = 0; } mWebView.scrollBy(effectX, effectY); return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onSingleTapUp(MotionEvent e) { Log.e("Temp", "onSingleTapUp"); return super.onSingleTapUp(e); } } private boolean effectOnScrollViewByScroll(int distanceY) { if (distanceY > 0) { // scroll up, the web will scroll down if (mScrollOffset >= mToolBarHeight || mScrollOffset >= mWebView.getVScrollRange()) { return false; } mScrollOffset += distanceY; if (mScrollOffset > mToolBarHeight) { mScrollOffset = mToolBarHeight; } if (mScrollOffset > mWebView.getVScrollRange()) { mScrollOffset = mWebView.getVScrollRange(); } } else { if (mScrollOffset <= 0) { return false; } mScrollOffset += distanceY; if (mScrollOffset <= 0) { mScrollOffset = 0; } } adjustScrollView(); return true; } private void adjustScrollView() { Log.e("Temp", "offset is " + mScrollOffset); ViewGroup.LayoutParams layoutParams = mWebView.getLayoutParams(); int newHeight = (mScrollViewHeight - mToolBarHeight) + mScrollOffset; Log.e("Temp", "newHeight is " + newHeight + ", layoutParams.height" + layoutParams.height); if (newHeight != layoutParams.height) { layoutParams.height = newHeight; mWebView.setLayoutParams(layoutParams); new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { mScrollView.fullScroll(ScrollView.FOCUS_DOWN); } }); } } }
總結(jié)
以上所述是小編給大家介紹的Android 類似UC瀏覽器的效果:向上滑動地址欄隱藏功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Android GridView不改變背景色實現(xiàn)網(wǎng)格線效果
這篇文章主要介紹了Android GridView不改變背景色實現(xiàn)網(wǎng)格線效果,需要的朋友可以參考下2016-03-03activity全屏實現(xiàn)沉浸式效果,并且單獨觸摸不會彈出虛擬按鍵的方法
今天小編就為大家分享一篇activity全屏實現(xiàn)沉浸式效果,并且單獨觸摸不會彈出虛擬按鍵的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Android開發(fā)實現(xiàn)廣告無限循環(huán)功能示例
這篇文章主要介紹了Android開發(fā)實現(xiàn)廣告無限循環(huán)功能,結(jié)合完整實例形式分析了Android廣告圖片輪播功能的具體實現(xiàn)步驟與相關(guān)功能、布局等操作技巧,需要的朋友可以參考下2017-11-11

Android創(chuàng)建與解析XML(三)——詳解Sax方式

Android中SurfaceTexture TextureView SurfaceView GLSurfaceView

Flutter源碼分析之自定義控件(RenderBox)指南