一团赏、View 坐標體系
以下方法獲取的是相對于父控件的坐標箕般,是在回調 onLayout 方法時 view.layout(t,l,b,r) 方法設置的 mLeft、mTop舔清、mBottom丝里、mRight 等屬性,mRight = mLeft + 控件自身寬度体谒,mBottom = mTop + 控件自身高度杯聚,除非調用 layout、setLeft抒痒、setFrame 等方法幌绍,否則是不會改變的;
getTop() //獲取子 View 頂邊距父 View 頂邊的距離
getLeft() //獲取子 View 左邊距父 View 左邊的距離
getBottom() //獲取子 View 底邊距父 View 頂邊的距離
getRight() //獲取子 View 右邊距父 View 左邊的距離
getTranslationX 方法和 getTranslationY 方法獲取的是 View 相對于父控件的偏移量故响,初始時為 0纷捞,向左(上)偏移為負,向右(下)偏移為正被去;
getX 和 getY 獲取的是 View 左邊或上邊距離父 View 左邊和上邊的實際距離主儡,是移動后的值;
getX() //返回值為getLeft()+getTranslationX()惨缆,當setTranslationX()時getLeft()不變糜值,getX()變
getY() //返回值為getTop()+getTranslationY()丰捷,當setTranslationY()時getTop()不變,getY()變
二寂汇、MotionEvent 單點觸控中的坐標
Android 將所有的輸入事件都放在了 MotionEvent 中病往,MotionEvent 負責集中處理所有類型設備的輸入事件,
單點觸控主要涉及以下幾個事件
- ACTION_DOWN 手指初次接觸到屏幕時觸發(fā)
- ACTION_MOVE 手指在屏幕上滑動時觸發(fā)骄瓣,會多次觸發(fā)
- ACTION_UP 手指離開屏幕時觸發(fā)
- ACTION_CANCEL 事件被上層攔截時觸發(fā)
- ACTION_OUTSIDE 手指不在控件區(qū)域時觸發(fā)
這里的坐標指的是觸摸點的坐標
getAction() //獲取事件類型
getX() //觸摸點相對于 View 的 X 軸坐標
getY() //觸摸點相對于 View 的 Y 軸坐標
getRawX() //觸摸點在整個屏幕的 X 坐標
getRawY() //觸摸點在整個屏幕的 Y 坐標
三停巷、View 在屏幕中位置
//獲取 View 自身可見的矩形坐標區(qū)域,坐標以自己的左上角為原點(0,0)榕栏,另一點為可見區(qū)域右下角相對自己(0,0)點的坐標畔勤,返回 View 所在矩形區(qū)域
getLocalVisibleRect()
// 獲取 View 在屏幕絕對坐標系中的可視區(qū)域,坐標以屏幕左上角為原點(0,0)扒磁,另一個點為可見區(qū)域右下角相對屏幕原點(0,0)點的坐標庆揪,返回 View 所在矩形區(qū)域
getGlobalVisibleRect()
//坐標是相對整個屏幕而言,坐標為 View 左上角到屏幕左端和頂部的距離妨托,返回的是左上角的坐標
getLocationOnScreen()
//如果為普通 Activity 則 Y 坐標為 View 左上角到屏幕頂部(此時 Window 與屏幕一樣大)缸榛;如果為對話框式的 Activity 則Y坐標為當前 Dialog 模式 Activity 的標題欄頂部到 View 左上角的距離。兰伤,返回左上角的坐標
getLocationInWindow()
四内颗、獲取 View 寬高的方法
getMeasuredWidth() //返回measure過程得到的mMeasuredWidth值,供layout參考敦腔,或許沒用均澳。
getMeasuredHeight() //返回measure過程得到的mMeasuredHeight值,供layout參考会烙,或許沒用负懦。
getWidth() //layout后有效,返回值是 mRight - mLeft柏腻,一般會參考 measure 的寬度(measure 可能沒用),但不是必須的五嫂。
getHeight() //layout后有效颗品,返回值是 mBottom - mTop,一般會參考 measure 的高度(measure 可能沒用)躯枢,但不是必須的锄蹂。
一般在 onCreate 方法里面獲取的控件寬高都為 0水慨。使用下面的方法可以獲得控件的寬高。
方法一啥箭、Activity/View#onWindowFocusChanged
當 Activity 窗口得到焦點和失去焦點時侮邀,onWindowFocusChanged 方法均會被調用一次陕悬。
方法二、view.post(Runnable)
將一個消息投遞到消息隊列尾部唯绍,等待 Looper 調用此 Runnable 對象時绝骚, View 已經初始化完畢了压汪。
方法三落君、手動對 View 進行 measure
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec,heightMeasureSpec);
int width = view.getMeasureSpec();
int height = view.getMeasureHeight();
方法四洒宝、使用 ViewTreeObserver 的回調
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
int height = view.getMeasuredHeight();
int width = view.getMeasuredWidth();
return true;
}
});
方法五将宪、使用 ViewTreeObserver 的回調
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int height = view.getHeight();
int width = view.getWidth();
}
});
五印蔗、屏幕尺寸
1法竞、屏幕寬高
//方法一
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
//方法二
DisplayMetrics displayMetrics = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);//this指當前activity
screenWidth =displayMetrics.widthPixels;
screenHeight =displayMetrics.heightPixels
2型宝、獲取整個應用程序區(qū)域(除狀態(tài)欄之外的區(qū)域)
Rect rect = new Rect();
getWindow().getDecorWindow().getWindowVisibleDisplayFrame(rect);
3、除了狀態(tài)欄和標題欄之外的View繪制的區(qū)域
Rect outRect = new Rect();
context.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect);
4渊涝、狀態(tài)欄高度
//方法一
Rect frame = new Rect();
context.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
//方法二
int resourceId=getResources().getIdentifier("status_bar_height","dimen","android");
if(resourceId>0){
int statusBarHeight=getResources().getDimensionPixelSize(resourceId);
}
5、標題欄高度
int contentTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
//statusBarHeight是上面所求的狀態(tài)欄的高度
int titleBarHeight = contentTop - statusBarHeight
六、View滑動
1暖侨、scrollTo和scrollBy滑動
只改變View內容的位置葫掉,實際上View的坐標沒有變化户魏,left叼丑,top笤休,x店雅,y等布局參數(shù)沒有變
getScrollX() //獲得View內容在x軸方向的偏移量闹啦,View內容的左邊緣在View左邊緣左側時為正窍奋,反之為負
getScrollY() //獲得View內容在y軸方向的偏移量,View內容的上邊緣在View上邊緣上側時為正,反之為負
scrollBy為相對滑動,View內容從左往右滑時為負音同,從右往左滑時為正蛇尚;從上往下滑時為負取劫,從下往上滑時為正
2、使用屬性動畫
改變的是 View 本身的位置
屬性動畫改變的是 translationX 和 translationY 代表的是 View
的偏移量,而不是top迅栅,left等初始參數(shù)
3读存、改變布局參數(shù)
直接對 View 的位置參數(shù)進行改變
實際上改變的是 View 的 left为流,top,right让簿,bottom 四個初始坐標
View在繪制完成后這四個初始值是不會改變的敬察,實際上setLayoutParams()對布局參數(shù)的改變,會觸發(fā)View的重新測繪拜英、布局静汤、繪制這三個流程,那么這四個值也就隨之改變
4、使用 layout
View在繪制的時候會調用layout()來確定View本身的位置虫给,那么我們可以直接調用這個方法來繪制View:
viwe.layout(int left,int top,int right,int bottom);
以上都是view相對于父容器的坐標藤抡,View的位置的確定依賴于這四個坐標,如果這四個坐標不按照view自身的縮放比例設置抹估,會造成View制圖的縮放缠黍。
所以如果為了View的正常滑動药蜻,一般可以將以上代碼修改成如下:
view.layout(view.getLeft()+offsetX,view.getTop()+offsetY,view.getRight()+offsetX,view.getBottom()+offsetY);
5瓷式、使用 offsetLeftAndRight 和 offsetTopAndBottom
直接調用View的offsetLeftAndRight(int offsetX)或者offsetTopAndBottom(int offsetY)能對view的四個坐標直接進行偏移,以達到移動view的目的语泽。
七贸典、彈性滑動
1、Scroller
Scroller常用模板
//實例化Scroller對象踱卵,在自定義View中廊驼,mContext 可以在自定義View的構造方法中獲取
Scroller mScroller = new Scroller(mContext);
//在一個自定義View中實現(xiàn)該方法,方法名可以自定義
public void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int scrollY = getScrollY();
int dx = destX - scrollX;
int dy = destY - scrollY;
//前兩個參數(shù)表示起始位置惋砂,第三第四個參數(shù)表示位移量妒挎,最后一個參數(shù)表示時間
mScroller.startScroll(scrollX,scrollY,dx,dy,1000);
invalidate();
}
//自定義View中重寫該方法
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
2、ValueAnimator
ValueAnimator animator = ValueAnimator.ofXXX();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
animation.getAnimatedValue();
}
});