android群英传 自定义滑动view,Android群英传学习之路-View的滑动
滑動效果是如何產(chǎn)生的?
滑動一個View從本質(zhì)上來說就是移動一個View,改變其當(dāng)前的坐標(biāo)。所以,想要滑動一個View,就必須監(jiān)聽該View的觸摸事件,并且根據(jù)事件的坐標(biāo),不斷的改變View的坐標(biāo)從而實(shí)現(xiàn)View的滑動。
Android中的坐標(biāo)體系
Android中的坐標(biāo)體系分為兩種:
Android坐標(biāo)系
視圖坐標(biāo)系
Android坐標(biāo)系
Android坐標(biāo)系
從圖中我們可以看的出來**在Android坐標(biāo)系中以屏幕的左上方作為坐標(biāo)系的原點(diǎn),從原點(diǎn)向右為X軸的正方向,向下為Y軸的正方向**。在觸控事件中使用**getRawX()、getRawY()**來獲得Android坐標(biāo)系的坐標(biāo)
視圖坐標(biāo)系
視圖坐標(biāo)系
視圖坐標(biāo)系主要描述的是該View和該View在父視圖中的位置關(guān)系,和Android坐標(biāo)系一樣,也是以原點(diǎn)右方為X正方向,以原點(diǎn)下方為Y軸正方向,不過這里不是以屏幕的左上角為原點(diǎn),而是**以父視圖的左上角為原點(diǎn)**。在觸控事件中使用**getX()、getY()**來獲得視圖坐標(biāo)系的坐標(biāo)
觸控事件
在上一篇文章中我們使用到了MotionEvent,這個就是觸控事件的封裝,首先看一下MotionEvent中封裝的事件常量
public static final int ACTION_DOWN = 0; //單點(diǎn)觸摸按下動作
public static final int ACTION_UP = 1; //單點(diǎn)觸摸離開動作
public static final int ACTION_MOVE = 2; //單點(diǎn)觸摸移動動作
public static final int ACTION_CANCEL = 3; //觸摸動作取消
public staiic final int ACTION_OUTSIDE = 4; //觸摸動作超出邊界
public static final int ACTION_POINTER_DOWN = 5; //多點(diǎn)觸摸按下動作
public static final int ACTION_POINTER_UP = 6; 多點(diǎn)離開動作
通常情況下我們會在onTouchEvent(MotionEvent event)方法中通過event.getAction()來獲取觸控事件的類型。知道Android中的坐標(biāo)系和觸控事件之后我們就可以來實(shí)現(xiàn)View的滑動了
滑動實(shí)現(xiàn)
實(shí)現(xiàn)滑動有好多種方法,但是其思想都是一樣的。當(dāng)觸摸到View時,記錄當(dāng)前觸摸點(diǎn)的坐標(biāo),然后當(dāng)手指移動時,獲取到相對于前一個點(diǎn)的偏移量,這樣我們就可以通過這個偏移量來進(jìn)行修改View的坐標(biāo),這樣不斷的重復(fù),就能實(shí)現(xiàn)View的滑動
舉個例子
我們自定義一個View,讓他來跟隨我們手指的移動來移動,如圖:
layout方法
我們知道在View進(jìn)行繪制的時候會通過onLayout()方法來設(shè)置View的顯示位置,這里我們通過修改View的left, top, right, bottom四個值來控制View的坐標(biāo)
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//記錄觸摸點(diǎn)的坐標(biāo)
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
//計(jì)算偏移量
int offsetX = x - lastX;
int offsetY = y - lastY;
//在當(dāng)前位置基礎(chǔ)加上偏移量
layout(
getLeft() + offsetX,
getTop() + offsetY,
getRight() + offsetX,
getBottom() + offsetY
);
break;
}
return true;
}
offsetLeftAndRight()和offsetTopAndBottom
這個方法就是相當(dāng)于系統(tǒng)提供的一個對左右、上下移動的API的封裝,計(jì)算好偏移量后,調(diào)用方法即可:
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
LayoutParams
LayoutParams保存了View的布局參數(shù),所以我們可以改變LayoutParams來動態(tài)的改變布局的位置來達(dá)到滑動的效果。在程序中使用getLayoutParams()來獲取當(dāng)前View的LayoutParams,這里就和上面一樣,獲取到偏移量后通過setLayoutParams來設(shè)置該View的LayoutParams:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();
params.leftMargin = getLeft() + offsetX;
params.topMargin = getTop() + offsetY;
setLayoutParams(params);
需要注意一點(diǎn),通過getLayoutParams()獲取LayoutParams的時候,要根據(jù)View的父布局的類型來設(shè)置,當(dāng)然前提還要有一個父布局。還有就是我們可以使用ViewGroup.MarginLayoutParams,這樣就不用考慮父布局是什么了
scrollTo、scrollBy
在View中,系統(tǒng)還提供了scrollTo、scrollBy兩種方式來改變一個View的位置。
其中scrollTo表示移動到一個具體的坐標(biāo)點(diǎn),scrollBy表示移動的偏移量,其實(shí)在scrollBy內(nèi)部也是調(diào)用的scrollTo。
和前面的方式一樣,獲取到偏移量后調(diào)用scrollBy來移動view,可是當(dāng)我們運(yùn)行程序,拖動View,發(fā)現(xiàn)View并沒有移動!這是因?yàn)閟crollTo、scrollBy方法移動的是View的內(nèi)容,如果在ViewGroup中使用scrollTo、scrollBy的滑,那么移動的就是View了,但是如果在View中使用,那么移動的將是View里面的內(nèi)容,比如TextView,那么移動的就是文本了。
所以通過上面的分析,我們把代碼改為如下:
((View)getParent()).scrollBy(offsetX, offsetY);
再次運(yùn)行程序,我們會發(fā)現(xiàn)動是動了,但是在亂動。因?yàn)檫@里我們其實(shí)是在相反的方向移動(這里由于篇幅限制,感興趣的同學(xué)自行查找一下資料),我們把偏移量改為負(fù)的之后就會發(fā)現(xiàn)滑動正常了。
Scroller
首先來想一個場景:我們需要讓一個Button向右面移動100個像素,如果我們用scrollTo/scrollBy的話,那么該View就會很突兀的移動到該點(diǎn),沒有過程,而Scroller則是可以實(shí)現(xiàn)平滑的過渡效果的
下面我們把上面跟隨手指滑動的例子改一下,我們在松開手指后,View自動回到原點(diǎn)(屏幕左上角)。使用Scroller需要三個步驟
初始化
通過構(gòu)造方法即可 Scroller mScroller = new Scroller(context);
重寫computeScroll()方法,實(shí)現(xiàn)滑動
startScroll()開啟滑動
代碼如下:
case MotionEvent.ACTION_UP:
View viewGroup = (View) getParent();
mScroller.startScroll(
viewGroup.getScrollX(),
viewGroup.getScrollY(),
-viewGroup.getScrollX(),
-viewGroup.getScrollY()
);
invalidate();
break;
----------------------------------------------------------------
@Overrid
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
當(dāng)我們手指抬起來的時候開啟Scroller滑動,獲取到當(dāng)前view的移動距離,然后我們把需要移動的偏移量設(shè)置為相反數(shù)就ok,最后調(diào)用invalidate來通知重繪,從而調(diào)用computeScroll()方法。運(yùn)行程序如下:
現(xiàn)在就把這幾種View的滑動都說完了,自己動手寫一下,感觸良多。
最后
愛生活,愛小麗,愛Android
總結(jié)
以上是生活随笔為你收集整理的android群英传 自定义滑动view,Android群英传学习之路-View的滑动的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux文件压缩与打包-1
- 下一篇: Android uevent