Android ViewGroup中的Scroller與computeScroll的有什麼關系?
答:沒有直接的關系
知道了答案,是不是意味著下文就沒必要看了,如果說對ViewGroup自定義控件不感興趣,可以不用看了。
1.Scroller到底是什麼?
答:Scroller只是個計算器,提供插值計算,讓滾動過程具有動畫屬性,但它並不是UI,也不是輔助UI滑動,反而是單純地為滑動提供計算。
無論從構造方法還是其他方法,以及Scroller的屬性可知,其並不會持有View,輔助ViewGroup滑動
2.Scroller只是提供計算,那誰來調用computeScroll使得ViewGroup滑動
答:computeScroll也不是來讓ViewGroup滑動的,真正讓ViewGroup滑動的是scrollTo,scrollBy。computeScroll的作用是計算ViewGroup如何滑動。而computeScroll是通過draw來調用的。
3.computeScroll和Scroller都是計算,兩者有啥關系?
答:文章開始已作答,沒有直接的關系。computeScroll和Scroller要是飛得拉關系的話,那就是computeScroll可以參考Scroller計算結果來影響scrollTo,scrollBy,從而使得滑動發生改變。也就是Scroller不會調用computeScroll,反而是computeScroll調用Scroller。
4.滑動時連續的,如何讓Scroller的計算也是連續的?
這個就問到了什麼時候調用computeScroll了,如上所說computeScroll調用Scroller,只要computeScroll調用連續,Scroller也會連續,實質上computeScroll的連續性又invalidate方法控制,scrollTo,scrollBy都會調用invalidate,而invalidate回去觸發draw,從而computeScroll被連續調用,綜上,Scroller也會被連續調用,除非invalidate停止調用。
5.computeScroll如何和Scroller的調用過程保持一致。
computeScroll參考Scroller影響scrollTo,scrollBy,實質上,為了不重復影響scrollTo,scrollBy,那麼Scroller必須終止計算currX,currY。要知道計算有沒有終止,需要通過mScroller.computeScrollOffset()
6.如上問題應該說的很清楚了吧,如果不明白,請留言。
7.通過一個SlidePanel的例子,我們來深刻的了解一下
注意:在移動平台中,要明確知道“滑動”與“滾動”的不同,具體來說,滑動和滾動的方向總是相反的。
public class SlidingPanel extends RelativeLayout {
private Context context;
private FrameLayout leftMenu;
private FrameLayout middleMenu;
private FrameLayout rightMenu;
private FrameLayout middleMask;
private Scroller mScroller;
public final int LEFT_ID = 0xaabbcc;
public final int MIDEELE_ID = 0xaaccbb;
public final int RIGHT_ID = 0xccbbaa;
private boolean isSlideCompete;
private boolean isHorizontalScroll;
private Point point = new Point();
private static final int SLIDE_SLOP = 20;
public SlidingPanel(Context context) {
super(context);
initView(context);
}
public SlidingPanel(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
this.context = context;
mScroller = new Scroller(context, new DecelerateInterpolator());
leftMenu = new FrameLayout(context);
middleMenu = new FrameLayout(context);
rightMenu = new FrameLayout(context);
middleMask = new FrameLayout(context);
leftMenu.setBackgroundColor(Color.RED);
middleMenu.setBackgroundColor(Color.GREEN);
rightMenu.setBackgroundColor(Color.RED);
middleMask.setBackgroundColor(0x88000000);
addView(leftMenu);
addView(middleMenu);
addView(rightMenu);
addView(middleMask);
middleMask.setAlpha(0);
}
public float onMiddleMask(){
return middleMask.getAlpha();
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
onMiddleMask();
// Log.e("getScrollX","getScrollX="+getScrollX());//可以是負值
int curX = Math.abs(getScrollX());
float scale = curX/(float)leftMenu.getMeasuredWidth();
middleMask.setAlpha(scale);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
middleMask.measure(widthMeasureSpec, heightMeasureSpec);
int realWidth = MeasureSpec.getSize(widthMeasureSpec);
int tempWidthMeasure = MeasureSpec.makeMeasureSpec(
(int) (realWidth * 0.8f), MeasureSpec.EXACTLY);
leftMenu.measure(tempWidthMeasure, heightMeasureSpec);
rightMenu.measure(tempWidthMeasure, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
middleMenu.layout(l, t, r, b);
middleMask.layout(l, t, r, b);
leftMenu.layout(l - leftMenu.getMeasuredWidth(), t, r, b);
rightMenu.layout(
l + middleMenu.getMeasuredWidth(),
t,
l + middleMenu.getMeasuredWidth()
+ rightMenu.getMeasuredWidth(), b);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!isSlideCompete) {
handleSlideEvent(ev);
return true;
}
if (isHorizontalScroll) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
int curScrollX = getScrollX();
int dis_x = (int) (ev.getX() - point.x);
//滑動方向和滾動滾動條方向相反,因此dis_x必須取負值
int expectX = -dis_x + curScrollX;
if(dis_x>0)
{
Log.d("I","Right-Slide,Left-Scroll");//向右滑動,向左滾動
}else{
Log.d("I","Left-Slide,Right-Scroll");
}
Log.e("I","ScrollX="+curScrollX+" , X="+ev.getX()+" , dis_x="+dis_x);
//規定expectX的變化范圍
int finalX = Math.max(-leftMenu.getMeasuredWidth(),Math.min(expectX, rightMenu.getMeasuredWidth()));
scrollTo(finalX, 0);
point.x = (int) ev.getX();//更新,保證滑動平滑
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
curScrollX = getScrollX();
if (Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1) {
if (curScrollX < 0) {
mScroller.startScroll(curScrollX, 0,
-leftMenu.getMeasuredWidth() - curScrollX, 0,
200);
} else {
mScroller.startScroll(curScrollX, 0,
leftMenu.getMeasuredWidth() - curScrollX, 0,
200);
}
} else {
mScroller.startScroll(curScrollX, 0, -curScrollX, 0, 200);
}
invalidate();
isHorizontalScroll = false;
isSlideCompete = false;
break;
}
} else {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_UP:
isHorizontalScroll = false;
isSlideCompete = false;
break;
default:
break;
}
}
return super.dispatchTouchEvent(ev);
}
/**
* 通過invalidate操縱,此方法通過draw方法調用
*/
@Override
public void computeScroll() {
super.computeScroll();
if (!mScroller.computeScrollOffset()) {
//計算currX,currY,並檢測是否已完成“滾動”
return;
}
int tempX = mScroller.getCurrX();
scrollTo(tempX, 0); //會重復調用invalidate
}
private void handleSlideEvent(MotionEvent ev) {
switch (ev.getAction()&MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
point.x = (int) ev.getX();
point.y = (int) ev.getY();
super.dispatchTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
int dX = Math.abs((int) ev.getX() - point.x);
int dY = Math.abs((int) ev.getY() - point.y);
if (dX >= SLIDE_SLOP && dX > dY) { // 左右滑動
isHorizontalScroll = true;
isSlideCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
} else if (dY >= SLIDE_SLOP && dY > dX) { // 上下滑動
isHorizontalScroll = false;
isSlideCompete = true;
point.x = (int) ev.getX();
point.y = (int) ev.getY();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_CANCEL:
super.dispatchTouchEvent(ev);
isHorizontalScroll = false;
isSlideCompete = false;
break;
}
}
}
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11