[TOC]
聲明:此系列的部分內(nèi)容出自《Android開發(fā)藝術(shù)探索》一書眶明,是我當(dāng)初學(xué)習(xí)時候的一些筆記和總結(jié)诵原,在這里留個記錄愤诱。
View是android中所有控件的基類。
位置參數(shù)
在Android系統(tǒng)中丐膝,左上角為坐標(biāo)原點量愧,x和y軸正方向分別是往右和下。View的位置由它的4個頂點來決定帅矗,即top偎肃,left,right浑此,bottom累颂。需要注意的是這4個點是相對坐標(biāo),相對于view的父容器來說的凛俱。獲取方法:
- top: getTop()
- left: getLeft()
- right: getRight()
- bottom: getBottom()
從Android3.0開始紊馏,View增加了4個額外的參數(shù):x料饥,y,translationX瘦棋,translationY。其中x和y指view左上角的坐標(biāo)暖哨,translationX和translationY指view左上角相對于父容器的偏移量赌朋。這4個參數(shù)也都是相對坐標(biāo),他們之間的相互關(guān)系如下:
- x = left + translationX;
- y = top + translationY;
即:在view發(fā)生平移的過程中篇裁,left和top始終是不變的沛慢,指view原始位置的左上角坐標(biāo),發(fā)生改變的只是x达布,y团甲,translationX,translationY這4個參數(shù)黍聂。
觸摸事件
MotionEvent
手指的觸摸事件一般可以分為兩種(姑且把單擊和長按當(dāng)成一種躺苦,滑動和多點觸控當(dāng)成一種吧,起碼觸發(fā)的事件是差不多的):
- 手指按下产还,不滑動匹厘,放開:DOWN--->UP。
- 手指按下脐区,滑動一段距離愈诚,再松手:DOWN--->MOVE--->...--->MOVE--->UP。
通過MotionEvent對象我們可以得到點擊位置的坐標(biāo):
- getX()和getY():得到的是相對當(dāng)前view左上角的坐標(biāo)牛隅。
- getRawX()和getRawY():得到的是相對手機屏幕左上角的坐標(biāo)炕柔。
TouchSlop
即系統(tǒng)所能識別出的被認為是滑動的最小距離。常量媒佣,和硬件設(shè)備有關(guān)匕累,可以通過ViewConfiguration.get(context).getScaledTouchSlop()得到,手指移動小于這個值得話則認為這次操作不是滑動默伍。
VelocityTracker
用來測量某個觸摸事件的速度哩罪。
@Override
public boolean onTouchEvent(MotionEvent event) {
/**
* 某個觸摸時間的速度測量:
* 1.通過obtain()方法獲得velocityTracker變量,并添加需要測量的事件
* 2.通過computeCurrentVelocity計算速度(參數(shù)單位為ms)巡验,再通過getter方法獲取速度值(右下滑為正數(shù)际插,反之為負數(shù))
* 3.釋放velocityTracker對象。
*/
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);//秒速
int v_x = (int) velocityTracker.getXVelocity();
int v_y = (int) velocityTracker.getYVelocity();
LogUtils.i(TAG,"\t\tX:" + v_x + "\t\tY:" + v_y);
velocityTracker.recycle();
return true;
}
02-17 11:26:55.483 27154-27154/lxf.androiddemos I/TestView: X:5656 Y:1203
02-17 11:26:55.500 27154-27154/lxf.androiddemos I/TestView: X:6255 Y:1202
02-17 11:26:55.509 27154-27154/lxf.androiddemos I/TestView: X:0 Y:0
02-17 11:26:55.510 27154-27154/lxf.androiddemos I/TestView: X:0 Y:0
02-17 11:27:01.207 27154-27154/lxf.androiddemos I/TestView: X:0 Y:0
02-17 11:27:01.248 27154-27154/lxf.androiddemos I/TestView: X:-421 Y:49
02-17 11:27:01.265 27154-27154/lxf.androiddemos I/TestView: X:-2978 Y:372
02-17 11:27:01.282 27154-27154/lxf.androiddemos I/TestView: X:-3426 Y:426
GestureDetector
手勢檢測显设,用來輔助檢測用戶的滑動框弛、單擊、雙擊捕捂、長按等行為瑟枫。
//1.實現(xiàn)OnGestureListener接口
public class TestView extends View implements GestureDetector.OnGestureListener{
//2.獲得GestureDetector對象,
gestureDetector = new GestureDetector(getContext(),this);
//如果要監(jiān)聽雙擊斗搞,可以實現(xiàn)DoubleTapListener接口
gestureDetector.setOnDoubleTapListener(mDoubleTapListener);
...
//3.接管onTouchEvent(event)方法。
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
//4.在接口的相應(yīng)回調(diào)方法中實現(xiàn)自己的邏輯慷妙。
...
}
View的滑動
scrollTo/scrollBy
scrollBy內(nèi)部實際上就是調(diào)用的scrollTo方法僻焚,它實現(xiàn)了view基于當(dāng)前位置的相對滑動,而scrollTo是相對于初始位置滾動某段距離膝擂,可以變向理解為絕對滑動弧可。
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
在滑動過程中带族,mScrollX的值總是等于view的左邊緣(left)和view的內(nèi)容的左邊緣在水平方向上的距離,mScrollY同理。scrollTo/scrollBy只能改變view的內(nèi)容位置而不能改變view在布局中的位置侨把。
使用動畫
使用動畫使view平移的方式有兩種:
- 補間動畫:實際上是對view的影像進行操作兄旬,并不會改變view本身的位置赖瞒、內(nèi)容等參數(shù)翁逞。
TranslateAnimation animation = new TranslateAnimation(0,100,0,0);
setAnimation(animation);
animation.start();
- 屬性動畫:直接操作view的屬性,可以改變view自身屏鳍。
ObjectAnimator.ofInt(targetView,"translationX",0,100).setDuration(500).start();
改變LayoutParams
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
params.leftMargin += 100;
setLayoutParams(params);
// 或requestLayout();
彈性滑動
使用Scroller
Scroller的典型用法:
scroller = new Scroller(getContext());
private void smoothScrollTo(int x, int y) {
int scrollX = getScrollX();
int delayX = x - scrollX;
scroller.startScroll(scrollX, 0, delayX, 0, 1000);//僅僅保存相應(yīng)參數(shù)
invalidate();//draw方法中會調(diào)用computeScroll
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
Scroller本身并不能使View滑動勘纯,它需要配合View的computeScroll方法才能實現(xiàn)彈性滑動的效果。它不斷讓view重繪钓瞭,每一次重繪距離view的起始滑動會有一個時間間隔屡律,通過這個時間間隔Scroller可以得到view的當(dāng)前滑動位置,通過scrollTo()完成滑動降淮。
使用屬性動畫
值動畫:其實屬性動畫的根本就是屬性值的改變超埋。
ValueAnimator animator = ValueAnimator.ofFloat(0,1).setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float flag = animation.getAnimatedFraction();
scrollTo(startX + (int)(delayX * flag),0);
}
});
animator.start();
其實所謂彈性滑動,就是將一次滑動分成了若干個短距離滑動佳鳖。