1. 程式人生 > >Android ListView滑動回彈——overScrollBy

Android ListView滑動回彈——overScrollBy

註解 

/**
     * Scroll the view with standard behavior for scrolling beyond the normal
     * content boundaries. Views that call this method should override
     * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the
     * results of an over-scroll operation.
     *
     * Views can use this method to handle any touch or fling-based scrolling.
     *
     * @param deltaX Change in X in pixels
     * @param deltaY Change in Y in pixels
     * @param scrollX Current X scroll value in pixels before applying deltaX
     * @param scrollY Current Y scroll value in pixels before applying deltaY
     * @param scrollRangeX Maximum content scroll range along the X axis
     * @param scrollRangeY Maximum content scroll range along the Y axis
     * @param maxOverScrollX Number of pixels to overscroll by in either direction
     *          along the X axis.
     * @param maxOverScrollY Number of pixels to overscroll by in either direction
     *          along the Y axis.
     * @param isTouchEvent true if this scroll operation is the result of a touch event.
     * @return true if scrolling was clamped to an over-scroll boundary along either
     *          axis, false otherwise.
     */
@SuppressWarnings({"UnusedParameters"})
    protected boolean overScrollBy(int deltaX, int deltaY,
            int scrollX, int scrollY,
            int scrollRangeX, int scrollRangeY,
            int maxOverScrollX, int maxOverScrollY,
            boolean isTouchEvent) 
maxOverScrollX、maxOverScrollY預設為0

注:

只有當listview不能單一螢幕顯示時才有該效果

轉載內容

第一部分  原理分析

      IOS上的bounce功能給人的感覺很爽,當一個可以滾動的區域被拖到邊界時,它允許使用者將內容拖過界,放手後再彈回來,以一種非常棒的方式提示了使用者邊界的存在,是IOS的一大特色。android2.3新增了overscroll功能,聽名字就知道應該是bounce功能的翻版,但也許是出於專利方面的考慮,google的預設實現跟IOS有所不同,它只是在list拖到邊界處時做了一個發光的動畫,個人覺得體驗比IOS差遠了。而且這個黃色的發光在黑色背景下雖然效果不錯,在其它背景下可就難說了,因此很多人想要關掉它。 


      日前google上搜索“android overscroll”,對此效果的介紹很多,但關於其具體使用方式和實現,則很少涉及,偶有提及,也經常答非所問或似是而非,反而誤導了別人。於是我查閱了android相關原始碼,並做了一些測試,在此講講我的理解。 

      首先是overscroll功能本身,在最頂層的View類提供了支援,可通過setOverScrollMode函式控制其出現條件。但其實View中並沒有實現overscroll功能,它僅僅提供了一個輔助函式overScrollBy,該函式根據overScrollMode和內容是否需要滾動控制最大滾動範圍,最後將計算結果傳給onOverScrolled實現具體的overscroll功能,但此函式在View類中是全空的。 

      overscroll功能真正的實現分別在ScrollView、AbsListView、HorizontalScrollView和WebView中各有一份,程式碼基本一樣。以ScrollView為例,它在處理筆點移動訊息時呼叫overScrollBy來滾動檢視,然後過載了overScrollBy函式來實現具體功能,其位置計算通過OverScroller類實現。OverScroller作為一個計算引擎,應該是一個獨立的模組,具體滾動效果和範圍都不可能通過它來設定,我覺得沒有必要細看。但滾動位置最終是它給出的,那相關資料肯定要傳遞給它,回頭看overScrollBy函式,它有兩個控制overScroll出界範圍的引數,幾個實現裡面都是取自ViewConfiguration.getScaledOverscrollDistance,而這個引數的值在我的原始碼中都是0,而且我沒找到任何可以影響其結果的設定。 

      真悲催,繞了半天,android的預設實現裡面根本沒有給出overscroll功能,它只是提供了實現機制,要想用起來還得應用程式自己顯式重寫相關控制元件,估計還有一層隱含的意思,法律風險自負。在我的系統中一試,果然一個畫素都不能拉出界。但那個閃光是怎麼回事呢? 

      在處理筆點訊息處,overScrollBy後面不遠處有一段mEdgeGlowTop的操作程式碼,看名字就像,用它一搜,相關機制就全明白了。mEdgeGlowTop在setOverScrollMode函式時建立,它使用的圖片都是系統中固有的,甚至不能通過theme改變。它的實現原理也很簡單,僅僅是兩張png圖片的合成,通過透明度的變化製造閃光的效果。更無語的是它既不能被應用程式訪問,也不受任何控制,要關閉它的唯一辦法是setOverScrollMode(View.OVER_SCROLL_NEVER)。否則就重寫onTouchEvent函式吧,想幹啥都可以,只是得自己做。 

      談到overScroll,很多文章都提到了ListView的setOverscrollHeader和setOverscrollFooter,很多人想通過這個來控制那個閃光效果。這兩玩意不但可以通過函式設定,也可以在xml中指定,相當方便。但最後很多人發現沒有任何作用,百思不得其解。其實這兩張圖片是用來作為overScroll拖過界時的背景的,預設系統不能拖過界,自然永遠都看不到,有些定製的系統中能拖出界幾個畫素,但也很難看清。 

第二部分  程式碼實現
     1. 在View中增加了overSrollBy方法,用於記錄x, y 軸上滾動。 

     2. 在AbsListView的onTouchEvent中判斷是否到達邊界(頂部 或 底部) ,然後呼叫view.overScrollBy ,傳入 mScrollY等引數 

     3. overScrollBy 最終賦值給View的mScrollX, mScrollY 兩個變數 

     4. 在AbsListView中呼叫完overScrollBy之後,呼叫invalidate重繪 



自定義ListView
Java程式碼  收藏程式碼
  1. public class BounceListView extends ListView{  
  2.     private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;  
  3.     private Context mContext;  
  4.     private int mMaxYOverscrollDistance;  
  5.     public BounceListView(Context context){  
  6.         super(context);  
  7.         mContext = context;  
  8.         initBounceListView();  
  9.     }  
  10.     public BounceListView(Context context, AttributeSet attrs){  
  11.         super(context, attrs);  
  12.         mContext = context;  
  13.         initBounceListView();  
  14.     }  
  15.     public BounceListView(Context context, AttributeSet attrs, int defStyle){  
  16.         super(context, attrs, defStyle);  
  17.         mContext = context;  
  18.         initBounceListView();  
  19.     }  
  20.     private void initBounceListView(){  
  21.         //get the density of the screen and do some maths with it on the max overscroll distance  
  22.         //variable so that you get similar behaviors no matter what the screen size  
  23.         final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();  
  24.         final float density = metrics.density;  
  25.         mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);  
  26.     }  
  27.     @Override  
  28.     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent){   
  29.         //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverscrollDistance;   
  30.         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);    
  31.     }  
  32. }  


Java程式碼  收藏程式碼
  1. public class MainActivity extends Activity {    
  2.     @Override    
  3.     public void onCreate(Bundle savedInstanceState) {    
  4.         super.onCreate(savedInstanceState);    
  5.         LinearLayout linearLayout = new LinearLayout(this);    
  6.         linearLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));    
  7.         setContentView(linearLayout);    
  8.         BounceListView bounceListView = new BounceListView(this);    
  9.         String[] data = new String[30];    
  10.         for (int i = 0; i < data.length; i++) {    
  11.             data[i] = "回彈效果 " + i;    
  12.         }    
  13.         ArrayAdapter<String> arrayAdapter =     
  14.                 new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, data);    
  15.         bounceListView.setAdapter(arrayAdapter);    
  16.         linearLayout.addView(bounceListView);    
  17.     }    
  18. }    

相關推薦

Android ListView滑動——overScrollBy

註解  /**      * Scroll the view with standard behavior for scrolling beyond the normal      * content boundaries. Views that call this met

Android滑動效果

原理: addHeaderView裡做的事: 1.測量出header的寬高,呼叫了measureView方法 2.設定LayoutParams,寬:MATCH_PARENT,高:10 3.設定topMargin的值為負的header的高度,即將header隱藏在螢幕最上方

Android使用CoordinatorLayout與AppBarLayout時快速滑動問題

在使用CoordinatorLayout時,套用AppBarLayout,實現滑動效果如果快速滑動,頂部就會出現回彈問題。解決方法:重寫AppBarLayout.Behavior程式碼如下:1.public class TestBehavior extends AppBarL

使用原生js封裝webapp滑動效果(慣性滑動滑動)

pla 手指 測試 距離 ack cti 時間 .proto start PC 移動端兼容 IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+ 慣性助動,滑動回彈 門面模式 window.onload = function() { /*測試

Android ListView滑動刪除及響應事件詳解

源代碼下載 引用 example imp cor toast don float 發現 目標:實現類似QQ,微信的消息列表滑動刪除 具體操作: 1. 主頁面布局 首先在布局文件(本例是activity_main.xml)中引入ListView控件,並指定id(如下代

Android Listview滑動時不載入資料,停下來時載入資料,讓App更優

資料來源配置(Adapter) package com.zhengsonglan.listview_loading.adapter;  import android.content.Context;  import android.view.LayoutInflate

Android ListView長按出對話方塊

ListView長按彈出對話方塊可以用PopupWindow實現 今天記錄的是重寫onCreateContextMenu和onContextItemSelected實現彈出對話方塊,比前者簡單很多

移動端阻止瀏覽器中預設元素滑動效果(橡皮筋效果)

在js檔案中加如下程式碼: document.addEventListener('touchstart',function(e){ e.preventDefault(); //

Android 帶阻尼效果的ScorllView

import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.util.AttributeSet; impo

Android ListView長按出CheckBox,實現全選,反選,批量刪除功能

ListView長按彈出CheckBox,實現全選,反選,批量刪除功能. 主佈局:activity_main <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="

android ListView 仿IOS 效果

最近看IOS的下拉效果感覺很不錯,當拉倒最上面和最下面的時候繼續拉動會有緩衝,想在android裡面也做一個,到網上到處找,沒有找到好的方法,據說android新的API對ListView有這樣的支援,感覺不是特別好用。 自己利用scroller實現了一下,廢話不多說了直接

Android超簡單實現listview上下拉伸動畫效果

超簡單實現listview上下拉伸回彈動畫效果 希望能幫到大家,共同進步 import android.annotation.SuppressLint; import android.content.Context; import android.uti

Android中自定義仿IOS效果的ListView

ios中有一個控制元件回彈的效果,比如listview ,拉動到第一條或者最後一條資料的時候,還可以繼續拉動,鬆手就回彈到原來位置,很贊,其實在android中實現起來也非常簡單,我們只需要重寫listview的下面兩個 方法即可 先上圖 @Override pub

Android 自定義ScrollView 支援慣性滑動,慣性效果。支援上拉載入更多

先講下原理: ScrollView的子View 主要分為3部分:head頭部,滾動內容,fooder底部 我們實現慣性滑動,以及回彈,都是靠超過head或者fooder 就重新滾動到  ,內容的頂部或者底部。 之前看了Pulltorefresh 他是通過不斷改變 head或

Android實現ListView阻尼式(下拉)效果

最近想模仿小米MIUI V5簡訊裡面的一個功能——私密簡訊,它的入口在簡訊列表,列表往下拉到1/3左右,我用Eclipse上的工具截了圖,包括該結構的佈局,如下圖: 從它的UI結構可以看出,用的是層疊結構,即將ListView和一個普通View(取名叫privateEn

ios 下防止整個網頁滑動(阻尼 . 瞞天過海,騙IOS,把阻尼限制在滾動區div內

list ont 16px 一點 width sta 常見 沒有 手機app 下面是一個手機APP頁面,分成上中下三部分,最上面和最下面是固定的,中間可以滾動。這是常見的APP布局方式。 <style> .box{ overflow: auto; -

Android關於CoordinatorLayout和ListView滑動衝突的解決(上滑ToolBar隱藏,下滑出現)

最近專案中使用到了CoordinatorLayout這種佈局方式,搭配RecycleView,實現起來比較簡單,而且不用自己處理滑動事件,但是改為了ListView後發生了滑動衝突. 所以想到了以下解決方案: 1.使用事件分發,當ListView在Y軸滑動時,將事件交給C

android listview巢狀時,顯示不全和不能滑動的解決

在listview巢狀listview的過程中,如果我們不寫一點特殊的操作的話,可能子listview會顯示不全,並且無法滑動,那麼應該怎麼解決呢 1.子listview繼承listview,然後重寫onmeasure方法,在裡面手動的去計算高度,然後傳給super方法,這

webapp在ios中簡單實現滑動,加速等效果

-webkit-overflow-scrolling來自safari原生控制元件的實現,工作原理是:在有這個屬性的容器上,系統會建立了一個uiscrollview,應用於該元素並將之作為渲染物件,從而為我們實現體驗流暢的觸屏滑動 在Ios上的表現結果令人十分滿意,並且網

Android重寫ScrollView實現上拉下拉,下拉頭部放大功能

效果圖: 自定義ScrollView: public class MyScrollView extends ScrollView { //----頭部收縮屬性-------- // 記錄首次按下位置 private float mFirstPositi