一痛阻、概念
View是Android中所有控件的基類靖秩,是一種界面層的控件的一種抽象,它代表了一個(gè)控件鱼响。除了View鸣剪,還有ViewGroup,ViewGroup內(nèi)部可以包含許多控件丈积,即一組View筐骇。ViewGroup繼承View,這就意味著View本身就可以是單個(gè)控件也可以是由多個(gè)控件組成的一組控件江滨,通過(guò)這種關(guān)系就形成了View樹的結(jié)構(gòu)铛纬。
二、View的位置參數(shù)
在Android中唬滑,x軸和y軸的正方向分別為右和下告唆。
View的四個(gè)屬性:top棺弊、left、right擒悬、bottom模她。
top:左上角的縱坐標(biāo),通過(guò)getTop()獲取懂牧。
left:左上角的橫坐標(biāo)侈净,通過(guò)getLeft()獲取。
right:右下角的橫坐標(biāo)僧凤,通過(guò)getRight()獲取畜侦。
bottom:右下角的縱坐標(biāo),通過(guò)getBottom()獲取拼弃。
注意:這些坐標(biāo)都是相對(duì)于View的父容器來(lái)說(shuō)的夏伊,是一種相對(duì)坐標(biāo)。
width = right - left;
height = bottom - top;
從Android3.0開始吻氧,View增加了額外幾個(gè)參數(shù):x溺忧、y、translationX和translationY盯孙。
x:左上角橫坐標(biāo)鲁森,通過(guò)getX()獲取。
y:左上角縱坐標(biāo)振惰,通過(guò)getY()獲取歌溉。
translationX:左上角相對(duì)于父容器橫向的偏移量,通過(guò)getTranslationX()獲取骑晶,默認(rèn)值為0痛垛。
translationY:左上角相對(duì)于父容器縱向的偏移量,通過(guò)getTranslationY()獲取桶蛔,默認(rèn)值為0匙头。
x = left + translationX;
y = top + translationY;
注意:View在平移的過(guò)程中,top和left表示的是原始左上角的位置信息仔雷,其值并不會(huì)發(fā)生改變蹂析,此時(shí)發(fā)生改變的是x、y碟婆、translationX和translationY這四個(gè)參數(shù)电抚。
三、MotionEvent和TouchSlop
1.MotionEvent
典型的事件類型:ACTION_DOWN竖共、ACTION_MOVE蝙叛、ACTION_UP。
getX():獲取相對(duì)于當(dāng)前View左上角的x坐標(biāo)公给。
getY():獲取相對(duì)于當(dāng)前View左上角的y坐標(biāo)甥温。
getRawX():獲取相對(duì)于手機(jī)屏幕左上角的x坐標(biāo)锻煌。
getRawY():獲取相對(duì)于手機(jī)屏幕左上角的y坐標(biāo)。
2.TouchSlop
TouchSlop是系統(tǒng)所能識(shí)別出的被認(rèn)為是滑動(dòng)的最小距離姻蚓。
獲取方法:
ViewConfiguration.get(getContext()).getScaledTouchSlop();
四、VelocityTracker匣沼、GestureDetector和Scroller
1.VelocityTracker
速度追蹤狰挡,用于追蹤手指在滑動(dòng)過(guò)程中的速度,包括水平和豎直方向的速度释涛。
使用方法:
首先加叁,在View的onTouchEvent方法中追蹤當(dāng)前單擊事件的速度:
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
然后,獲取當(dāng)前的速度:
VelocityTracker.computeCurrentVelocity(1000); //計(jì)算速度
int xVelocity = (int) velocityTracker.getXVelocity(); //獲取速度
int yVelocity = (int) velocityTracker.getYVelocity(); //獲取速度
注意:
1.獲取速度之前必須先計(jì)算速度唇撬;
2.這里的速度是指一段時(shí)間內(nèi)手指所滑過(guò)的像素?cái)?shù)豫柬;
速度 = (終點(diǎn)位置 - 起點(diǎn)位置) / 時(shí)間段;
速度扑浸,可以為負(fù)值;
時(shí)間段础嫡,為computeCurrentVelocity方法傳遞的參數(shù)值,單位為毫秒(ms)巫财;
最后,當(dāng)不需要使用的時(shí)候葵礼,重置并回收內(nèi)存:
velocityTracker.clear();
velocityTracker.recycle();
例子:
public class VelocityView extends View {
private static final String TAG = "VelocityView";
private VelocityTracker velocityTracker;
public VelocityView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
// setClickable(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(velocityTracker==null){
velocityTracker=VelocityTracker.obtain();
}
velocityTracker.addMovement(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
Log.d(TAG,"zwm, ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG,"zwm, ACTION_UP");
release();
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG,"zwm, ACTION_MOVE");
velocityTracker.computeCurrentVelocity(1000);
float xVelocity = velocityTracker.getXVelocity();
float yVelocity = velocityTracker.getYVelocity();
Log.d(TAG,"zwm, " + String.format("velocityX --> %f, velocityY --> %f",xVelocity,yVelocity));
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG,"zwm, ACTION_CANCEL");
release();
break;
}
// 如果這里使用了super.onTouchEvent(event)届谈,那么就只會(huì)觸發(fā)ACTION_DOWN, 因?yàn)槭录粫?huì)往下面?zhèn)鬟f湖雹。
// 解決辦法,返回true征讲,或者調(diào)用setClickable(true), 實(shí)際上二者的效果是一樣的。
return true;
}
public void release(){
if(velocityTracker!=null){
velocityTracker.clear();
velocityTracker.recycle();
velocityTracker=null;
}
}
}
//MainActivity
VelocityView veloctiyView=new VelocityView(this);
veloctiyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
veloctiyView.setBackgroundColor(Color.BLUE);
setContentView(veloctiyView);
2.GestureDetector
手勢(shì)檢測(cè),用于輔助檢測(cè)用戶的單擊、滑動(dòng)俏让、長(zhǎng)按、雙擊等行為。
使用方法:
首先赊颠,需要?jiǎng)?chuàng)建一個(gè)GestureDetector對(duì)象并實(shí)現(xiàn)OnGestureListener接口,根據(jù)需要還可以實(shí)現(xiàn)OnDoubleTapListener從而能夠監(jiān)聽雙擊行為:
GestureDetector mGestureDetector = new GestureDetector(this);
//解決長(zhǎng)按屏幕后無(wú)法拖動(dòng)的現(xiàn)象
mGestureDetector.setIsLongpressEnabled(false);
接著,接管目標(biāo)View的onTouchEvent方法挠日,在待監(jiān)聽View的onTouchEvent方法中添加如下實(shí)現(xiàn):
boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
然后,就可以有選擇地實(shí)現(xiàn)OnGestureListener和OnDoubleTapListener中的方法了。在日常開發(fā)中属愤,比較常用的有:onSingleTapUp(單擊)、onFling(快速滑動(dòng))丧诺、onScroll(拖動(dòng))馁蒂、onLongPress(長(zhǎng)按)和onDoubleTap(雙擊)饵隙。
在實(shí)際開發(fā)中,可以不使用GestureDetector沮脖,完全可以在View的onTouchEvent方法中實(shí)現(xiàn)所需的監(jiān)聽勺届,這個(gè)就看個(gè)人的喜好了。
建議:如果只是監(jiān)聽滑動(dòng)相關(guān)的,建議自己在onTouchEvent方法中實(shí)現(xiàn)奈应,如果需要監(jiān)聽雙擊這種行為的話,那么就使用GestureDetector。
例子:
public class GestureView extends View {
private static final String TAG = "GestureView";
public GestureView(Context context) {
super(context);
gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.d(TAG, "zwm, onSingleTapConfirmed");
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.d(TAG, "zwm, onDoubleTap");
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
Log.d(TAG, "zwm, onDoubleTapEvent");
return false;
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return true;
}
GestureDetector gestureDetector = new GestureDetector(getContext(), new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
Log.d(TAG, "zwm, onDown");
return false;
}
@Override
public void onShowPress(MotionEvent e) {
Log.d(TAG, "zwm, onShowPress");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.d(TAG, "zwm, onSingleTapUp");
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.d(TAG, "zwm, onScroll");
return false;
}
@Override
public void onLongPress(MotionEvent e) {
Log.d(TAG, "zwm, onLongPress");
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.d(TAG, "zwm, onFling, velocityX --> " + velocityX + ", velocityY --> " + velocityY);
return false;
}
});
}
//MainActivity
GestureView gestureView=new GestureView(this);
gestureView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
gestureView.setBackgroundColor(Color.BLUE);
setContentView(gestureView);
3.Scroller
彈性滑動(dòng)對(duì)象氓皱,用于實(shí)現(xiàn)View的彈性滑動(dòng)。
當(dāng)使用View的scrollTo / scrollBy方法進(jìn)行滑動(dòng)時(shí),其過(guò)程是瞬間完成的身隐,這個(gè)沒(méi)有過(guò)渡效果的滑動(dòng)用戶體驗(yàn)不好廷区,可以使用Scroller來(lái)實(shí)現(xiàn)有過(guò)渡效果的滑動(dòng)。
使用方法及工作原理將在"滑動(dòng)"小節(jié)介紹贾铝。