1. 實現(xiàn)滑動的三種方式
- 通過View本身提供的scrollTo/scrollBy方法
- 通過動畫給View施加平移效果
- 通過改變View的LayoutParams使得View重新布局,實現(xiàn)滑動
2. scrollTo/scrollBy
使用:
view.scrollTo(200,200);
view.scrollBy(200,200);
源碼:
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
scrollBy實際上是調(diào)用了scrollTo方法,他實現(xiàn)的是相對滑動;而scrollTo實現(xiàn)的是絕對滑動。
在滑動過程中,mScrollX的值總是等于View的左邊緣和View的內(nèi)容的左邊緣在水平方向的距離,而mScrollY的值等于View上邊緣和View內(nèi)容的上邊緣的豎直距離。
View的邊緣指View的位置。內(nèi)容邊緣指View中的內(nèi)容的邊緣。scrollTo/scrollBy只能改變View的內(nèi)容邊緣,而不能改變View在布局中的位置。mScrollX和mScrollY的單位是像素,是有正負(fù)的。起始位置-終點位置的結(jié)果值就是scrollX和scrollY的值,是正就是正,是負(fù)就是負(fù)。也就是當(dāng)View左邊緣在View內(nèi)容左邊緣的右邊時,mScrollX為正。反之為負(fù)。
3. 使用動畫
objectAnimator = ObjectAnimator.ofFloat(view,"translationX",0,500).setDuration(5000);
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
Log.e("aaa", "x=" + view.getX() + ",y=" + view.getY() + ",translationX=" + view.getTranslationX() + ",translationY=" + view.getTranslationY());
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("aaa", "x=" + view.getX() + ",y=" + view.getY() + ",translationX=" + view.getTranslationX() + ",translationY=" + view.getTranslationY());
objectAnimator.start();
}
});
動畫啟動前打印x,translationX的值,動畫結(jié)束后,也打印他們的值如下:
x=30.0,y=30.0,translationX=0.0,translationY=0.0
x=530.0,y=30.0,translationX=500.0,translationY=0.0
前文說過
x=left + translationX
3.0以上的屬性動畫其位置是隨著動畫移動了的,而3.0以下的機(jī)器由于不支持屬性動畫,所以位置不隨著動畫移動,這是動畫的主要缺點。
4. 改變布局參數(shù)
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) view.getLayoutParams();
lp.width+=100;
lp.leftMargin+=100;
view.requestLayout();
// 或者 view.setLayoutParams(lp);
5. 三種方式的比較
- scrollTo/scrollBy:操作簡單,適合對View內(nèi)容的滑動
- 動畫:操作簡單,主要用于沒有交互的View或者復(fù)雜動畫。
- 改變參數(shù)布局:操作稍微復(fù)雜,適用于有交互的Veiw
6. 小栗子
public class DemoButton extends Button {
int mLastX, mLastY;
public DemoButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastX;
int deltaY = y - mLastY;
int translationX = (int) getTranslationX() + deltaX;
int translationY = (int) getTranslationY() + deltaY;
setTranslationX(translationX);
setTranslationY(translationY);
break;
}
mLastX = x;
mLastY = y;
return true;
}
}
這個例子其實不用動畫,因為move的響應(yīng)非???,已經(jīng)達(dá)到了動畫要求的梯度值,所以直接設(shè)置其值就可以。