【大圣代的技術(shù)專欄 http://blog.csdn.net/qq_23191031 轉(zhuǎn)載煩請注明出處栅哀,尊重他人勞動成功就是對您自己的尊重】
相關(guān)文章
詳解Android控件體系與常用坐標(biāo)系
Android常用觸控類分析:MotionEvent 甚亭、 ViewConfiguration、VelocityTracker
Android View事件(二)詳解事件分發(fā)機制
一, 前言
在前面的幾篇文章,我向大家介紹的都是單一View事件,而在這篇文章中,我將向大家介紹連續(xù)的事件 —— 滑動累舷。
在安卓設(shè)備上滑動幾乎是應(yīng)用的標(biāo)配,由于安卓手機屏幕較小夹孔,為了給用戶呈現(xiàn)更多的內(nèi)容被盈,就需要使用滑動來隱藏和顯示一些內(nèi)容析孽。學(xué)習(xí)View的滑動對于自定義控件的掌握、日持辉酰滑動沖突的處理都有很多裨益袜瞬。為了很好的理解滑動事件,掌握Android坐標(biāo)系與觸控事件就變得格外重要身堡,在此強烈建議先閱讀上面的提到的幾篇相關(guān)文章打好基礎(chǔ)邓尤。
二, View滑動產(chǎn)生的原理
從原理上講View滑動的本質(zhì)就是隨著手指的運動不斷地改變坐標(biāo)贴谎。當(dāng)觸摸事件傳到View時汞扎,系統(tǒng)記下觸摸點的坐標(biāo),手指移動時系統(tǒng)記下移動后的觸摸的坐標(biāo)并算出偏移量擅这,并通過偏移量來修改View的坐標(biāo)澈魄,不斷的重復(fù)這樣的過程,從而實現(xiàn)滑動過程蕾哟。
三一忱,實現(xiàn)滑動的7種方法
在學(xué)習(xí)Android坐標(biāo)系和觸控事件之后我們就可以看看系統(tǒng)為開發(fā)者提供了那些方法來實現(xiàn)滑動效果吧莲蜘!
3.0 代碼實例介紹
為了讓大家更好的理解過程谭确,設(shè)計如下代碼實例
MainActivity中沒有任何改動,而CustomView只是繼承了View票渠,并重寫了 onToucnEvent()
方法逐哈。
可以看到代碼很簡單,這篇文章中我就不提供項目地址了问顷。
3.1 layout 方法
在View繪制的時候昂秃,系統(tǒng)都會調(diào)用layout(int l, int t, int r, int b)
方法來確定View的具體位置。系統(tǒng)既然是這樣來設(shè)置View的位置的杜窄,那么我們也可以通過調(diào)用layout(int l, int t, int r, int b)`方法修改left肠骆,top,right塞耕,bottom這四個屬性來控制View的位置蚀腿。
// 視圖坐標(biāo)方式
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 記錄觸摸點坐標(biāo)
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
// 計算偏移量
int offsetX = x - lastX;
int offsetY = y - lastY;
// 在當(dāng)前l(fā)eft、top扫外、right莉钙、bottom的基礎(chǔ)上加上偏移量
layout(getLeft() + offsetX,
getTop() + offsetY,
getRight() + offsetX,
getBottom() + offsetY);
break;
}
return true;
}
當(dāng)然使用 getX()
、getY()
方法和使用getRawX()
筛谚、geRawtY()
的效果是一樣的磁玉,只不過前者使用的是相對位置,而后者使用的是絕對位置驾讲。
但是要注意蚊伞,在使用絕對坐標(biāo)系的時候席赂,每次執(zhí)行完 ACTION_MOVE的邏輯后,一定要重新設(shè)置初始坐標(biāo)时迫,這樣才能獲得準確的偏移量氧枣。
case MotionEvent.ACTION_MOVE:
// 計算偏移量
…………
//重新設(shè)置初始坐標(biāo)
x = (int)(event.getRawX());
y = (int)(event.getRawY());
break;
3.2 offsetLeftAndRight() 與 offsetTopAndroidBottom()
// 視圖坐標(biāo)方式
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 記錄觸摸點坐標(biāo)
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
// 計算偏移量
int offsetX = x - lastX;
int offsetY = y - lastY
//同時對于left 和 right進行偏移
offsetLeftAndRight(offsetX);
//同時對于top 和 bottom進行偏移
offsetTopAndBottom(offsetY);
break;
}
return true;
}
3.3 LayoutParams
LayoutParams
類是子View向父View傳遞位置意圖的橋梁,告訴父View他想要變成的樣子别垮。所以我們可以通過LayoutParams
中的參數(shù)來改變View的位置便监。
@Override
public boolean onTouchEvent(MotionEvent event) {
int startX = (int) event.getX();
int startY = (int) event.getY();
int lastX = 0;
int lastY = 0;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = startX;
lastY = startY;
Log.v(TAG, "startX " + startX + " startY " + startY);
break;
case MotionEvent.ACTION_MOVE:
Log.v(TAG, "offsetX --- " + startX + " offsetY --- " + startY);
int offsetX = startX - lastX;
int offsetY = startY - lastY;
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
break;
}
//注明消費此事件,不然無效果
return true;
}
注意:
在獲得 LayoutParams對象的時候碳想,需要將其轉(zhuǎn)換成直接父View(這個View的上一層布局)的類型烧董,不然會報錯。
例如胧奔,將
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
改為錯誤的:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
報錯如下:
3.4 scrollTo與ScrollBy
在View中系統(tǒng)為開發(fā)者提供了兩個關(guān)于移動的方法: scrollTo 與 scroolBy逊移。其實這兩個方法非常好理解,單從字面上的意思就知道
scrollTo(x,y) : 移動到 (x,y) 這個坐標(biāo)點
scrlollBy(dx,dy) : 移動的增量為 dx龙填,dy胳泉。
我們對于原有代碼進行如下更改
但是,當(dāng)我們拖動View的時候卻沒有移動Q乙拧I壬獭!這是為什么呢宿礁?
其實View是移動了地案铺,只不過和我們設(shè)想的結(jié)果不同。scrollTo()梆靖、scrollBy()表示的是 移動當(dāng)前ViewGroup的所有子View控汉,如果在View中使用,那么移動的就是View的內(nèi)容(content)返吻。例如TextView它的content就是文本姑子。這就解釋了為什么我們的代碼看不到效果了。
將原有代碼更改為如下所示:
((ViewGroup) getParent()).scrollBy(offsetX, offsetY);
這回的確是動了测僵,但是他卻在亂動街佑。并不是像我們想象中的那樣跟隨著手指的移動而移動。
導(dǎo)致這個的原因是什么呢恨课? 答案請見《Scroll類源碼分析與應(yīng)用》第一節(jié) scrollTo與ScrollBy
3.5 Scroller
請見《Scroll類源碼分析與應(yīng)用》 第二節(jié)Scroller
關(guān)于屬性動畫舆乔、ViewDragHelper
二者也是實現(xiàn)View滑動的良好辦法,但是他們都有一定的復(fù)雜性直接展開不僅顯得突兀剂公、而且篇幅較大不利于學(xué)習(xí)希俩,所以屬性動畫與ViewDragHelper我都會以單獨的篇幅展開,方便同學(xué)們更好的理解與學(xué)習(xí)纲辽,敬請期待
版權(quán)聲明:
禁止一切商業(yè)行為颜武,轉(zhuǎn)載請著名出處 http://blog.csdn.net/qq_23191031璃搜。作者: 大圣代
Copyright (c) 2017 代圣達. All rights reserved.