編輯:關於Android編程
本菜開源的一個自己寫的Demo,希望能給Androider們有所幫助,水平有限,見諒見諒…
https://github.com/zhiaixinyang/MDoveApp/
實現這種效果有很多種方案,今天在這就主要借這個機會來記錄一下scrollTo,scrollBy以及Scroller的用法。
/** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the x position to scroll to * @param y the y position to scroll to */ //翻譯過來:設置視圖的滾動位置。 這將導致調用{@link #onScrollChanged(int,int,int,int)},並且視圖將失效。
說實話不是很好理解。但是根據效果我們可以這麼理解:scrollTo的效果是移向你傳進的坐標。如果你再次調用這個方法,傳值不變時!你會發現並沒有任何的位置移動。(和scrollBy方法有區別)因為它已經到達了這個位置因此不會再移動,而scrollBy卻不然。
此外此方法移動的是View內部的位置而不是View整體。如果View不是一個ViewGroup的話,例如TextView,那麼移動的就是TextView的文字內容;如果是ViewGroup那麼便是ViewGroup中的子元素。
//注釋基本和scrollTo相同 /** * Move the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the amount of pixels to scroll by horizontally * @param y the amount of pixels to scroll by vertically */ public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
我們可以看出,scrollBy內部是調用的scrollTo,但是這裡的傳參導致了它們二者的不同。
scrollBy傳入了mScrollX…這是個什麼東西?我們在View中可以調用getScrollX()方法拿到這個值;其實這個值就是滑動的距離,對於X軸來說左滑動為正(增加),對於Y軸上滑動為正(增加)。
scrollBy的效果與scrollTo也截然相反。scrollBy就基於當前位置的移動,簡單說它可以不斷的移動。
在傳值的時候,我們需要注意正負號問題:簡單來說往左滑動時x為正,否則為負;上滑動時y為正,反之為負。
因為這裡和mScrollX和mScrollY這倆個變量有關。這兩個方法最終都會直接或間接的引用到這倆個變量。而它們倆的正負是這麼判斷的:如果View的左邊緣在View內容區域(這倆個方法的移動都只是移動自己的內容區域)左邊緣的右邊為正,反之為負;如果View的上邊緣在View內容區域的上邊緣的下邊mScrollY為正反之為負。
為什麼是這樣:當我們把內容區域的某個邊緣當做參考點來理解就是這種情況。如果View的內容區域的左邊緣為(0,…)那麼View的左邊緣在它的右邊,理所應當為(+…,…)。同理mScrollY也是如此。
//簡單重寫了onTouchEvent @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: int x=-5; //在0.2內使View的x軸從0移到x //但是具體怎麼移動需要我們自己去實現,解釋在下面 scroller.startScroll(0,0,x,0,200); invalidate(); break; } return true; } /** * invalidate()最終會調用computeScroll() * 而View中的computeScroll()是一個空實現 * 因此需要我們自己去重寫這個方法,去實現對應的效果 */ @Override public void computeScroll() { super.computeScroll(); //如果返回true,說明滑動還不到結束的時候,應當繼續。 if (scroller.computeScrollOffset()){ //而促使它滑動的方式依舊是scrollBy或是scrollTo //注意此處x的位置,我們是使用的scroller.getCurrX()的返回值,至於它的作用往下來 scrollBy(scroller.getCurrX(),0); //請求重新繪制View invalidate(); } }
Scroller這個類本身不具備任何移動View的作用。它的startScroll方法,我們進源碼就會發現僅僅是一些簡單的賦值。真正起到移動效果的是invalidate()方法,通過這個方法使得View重繪,因此就會調用computeScroll(),所以我們重寫computeScroll()。
可能有朋友在這裡會由衷的贊歎一句:尼瑪SB嗎?饒了這麼一大圈不還是scrollTo/scrollBy麼!
不不不,它有一個最重要的作用。先讓我們注意一下我們在傳參的時候,傳了一個時間參數(200)。
這個值在computeScrollOffset()中體現它的作用:
//根據代碼中的變量名,我們也能猜出:這裡通過時間的流逝來計算移動進行的比例 int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); //如果時間流逝小於應該傳入的值,那麼就繼續執行 if (timePassed < mDuration) { switch (mMode) { //如果是滾動狀態 case SCROLL_MODE: //通過類插值器的效果來計算x的變化量,使其隨時間進行均勻變化。 final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); break; //省略部分代碼 }
這裡用於計算移動的比例,因此Scroller最大的效果就是移動可以隨時間的變化而變化,簡單說可以做一些彈性的效果。讓滑動不在單點生硬。
其實理解這些方法的使用,最開始的那個效果真的很簡單,所以接下來就是簡單貼一下代碼:
@Override public boolean onTouchEvent(MotionEvent event) { float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (!scroller.isFinished()) scroller.abortAnimation(); //記錄手指按下時的坐標 lastY = y; downY=event.getY(); //消費點擊事件 return true; case MotionEvent.ACTION_MOVE: float dy = y - lastY; scrollBy(0, (int) -dy); lastY = y; break; } return super.onTouchEvent(event); }
//topViewHeight就是我們需要滑動的View的高度 @Override public void scrollTo(int x, int y) { if (y < 0) { y = 0; } if (y > topViewHeight) { y = topViewHeight; } if (y != getScrollY()) { super.scrollTo(x, y); } }
//此方法在布局加載完成後回調,因此在此獲得View的引用 @Override protected void onFinishInflate() { super.onFinishInflate(); topView=getChildAt(0); }
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //獲取topView的高度 topViewHeight = topView.getMeasuredHeight(); //畫三角形所需的路線 path=new Path(); path.moveTo(avatarLeft-25,topViewHeight); path.lineTo(avatarLeft+25,topViewHeight); path.lineTo(avatarLeft,topViewHeight-25); path.close(); } //畫三角形 @Override protected void dispatchDraw(Canvas canvas) { canvas.drawPath(path,paint); super.dispatchDraw(canvas); }
OK,到此關於scrollTo和scrollBy以及Scroller的用法就結束了,接下來就是關於NestedScrolling機制的分析,讓我們下一次博客見。
在上家干了快2年辭職後在家休息了快一個月了,說實在的不上班的感覺爽(睡覺睡到自然醒,游戲玩到手抽筋)。哈哈,又是快到一年過中秋的時候了,好久沒有更新博客了,今天順便撸一篇
隨著最近魅族魅藍e正式發布,再次加劇了魅族和小米之間在千元機之間的對決。許多網友將魅藍e和前不久剛剛發布的紅米pro進行對比了,那麼到底魅藍e和紅米pro哪
前言:前面我們介紹MediaPlayer相關方法,有人說,沒有實際例子,看得不是很明白,今天在分析MediaPlayer時,順帶一個播放網絡視頻例子。可以自行試試。同樣先
內存洩露,是Android開發者最頭疼的事。可能一處小小的內存洩露,都可能是毀於千裡之堤的蟻穴。 怎麼才能檢測內存洩露呢?網上教程非常多,不過很多都是使用Eclipse