編輯:關於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機制的分析,讓我們下一次博客見。
安卓實踐開發之MVP一步步實現到高級封裝
在上家干了快2年辭職後在家休息了快一個月了,說實在的不上班的感覺爽(睡覺睡到自然醒,游戲玩到手抽筋)。哈哈,又是快到一年過中秋的時候了,好久沒有更新博客了,今天順便撸一篇
魅藍e和紅米pro哪個好 魅藍e和紅米pro詳細圖文對比
隨著最近魅族魅藍e正式發布,再次加劇了魅族和小米之間在千元機之間的對決。許多網友將魅藍e和前不久剛剛發布的紅米pro進行對比了,那麼到底魅藍e和紅米pro哪
Android Multimedia框架總結(二)MediaPlayer框架及播放網絡視頻案例
前言:前面我們介紹MediaPlayer相關方法,有人說,沒有實際例子,看得不是很明白,今天在分析MediaPlayer時,順帶一個播放網絡視頻例子。可以自行試試。同樣先
使用新版Android Studio檢測內存洩露和性能
內存洩露,是Android開發者最頭疼的事。可能一處小小的內存洩露,都可能是毀於千裡之堤的蟻穴。 怎麼才能檢測內存洩露呢?網上教程非常多,不過很多都是使用Eclipse