在Android中,若是出現須要展現的內容超過屏幕的大小,一般咱們會使用ScrollView和ListView來解決。本文將介紹這兩種方法的原理。android
咱們先看看mScrollX/mScrollY在代碼中的註釋:canvas
mScrollX/mScrollY相對這個View的內容(文字,圖片,子View)垂直/水平的像素偏移。以下圖:緩存
在設置mScrollX / mScrollY後,就能夠滾動到指定的「內容",而mScrollX/mScrollY 就是將內容原點(0,0)進行偏移的數值。函數
而這種內容大小以及偏移是如何發生的?在ViewGroup中,存在一個API drawChild(),這個函數主要完成對子View的空間大小的限制以及偏移,見以下的描述:rest
protected boolean drawChild(Canvas canvas, View child, long drawingTime) { boolean more = false; //獲取子View的空間大小 final int cl = child.mLeft; final int ct = child.mTop; final int cr = child.mRight; final int cb = child.mBottom; //通知子View進行判斷是否完成滾動,這裏就是經過Scroller代碼實現滾動的關鍵點 child.computeScroll(); //獲取最新的偏移量 final int sx = child.mScrollX; final int sy = child.mScrollY; //建立一個還原點 final int restoreTo = canvas.save(); //偏移,經過這個API,實現了scroll對內容偏移, 先把內容的原點進行偏移到負數區域 canvas.translate(cl - sx, ct - sy); //剪切,由於以前有一個translate操做,全部剪切出來的空間就是父View給定的可見區域 //因此若是子View填充Canvas的內容超出給定的空間,也不會顯示出來 canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct)); //讓子View進行繪圖,注意子View不用處理Scroll屬性,既能夠實現內容偏移 child.draw(canvas); //還原 canvas.restoreToCount(restoreTo); return more; }
經過設置canvas的可見區域以及偏移平移座標原點(0,0),就能夠完成在固定大小內經過滾動顯示被覆蓋的部分。code
ListView和ScrollView有很大的區別:ListView僅僅須要幾個View既能夠實現滾動效果,而ScrollView須要所有的View。咱們來看一下ListView緩存機制:圖片
因此ListView的滾動效果是經過替換ViewGroup上的子View來實現的。ip
在android中,爲了實現滾動效果,一般有兩種方式:原理
而ScrollView和ListView就是這兩種實現的表明了。cli