導(dǎo)語
滑動算是Android比較常用的效果了抬闯,滑動的操作具有很好的用戶體驗性拓颓。
主要內(nèi)容
- 滑動效果是如何產(chǎn)生的
- 實現(xiàn)滑動的七種常用方法
具體內(nèi)容
滑動效果是如何產(chǎn)生的
滑動一個View的本質(zhì)其實就是移動一個View,改變其當前所在的位置语婴,它的原理和動畫效果十分的相似,就是通過不斷的改變View的坐標來實現(xiàn)這一效果录粱,動態(tài)且不斷的改變View的坐標腻格,從而實現(xiàn)View跟隨用戶觸摸滑動而滑動。
但是在講解滑動效果之前啥繁,需要先了解一下Android中窗口坐標體系和屏幕的觸控事件——MotionEvent菜职。
Android坐標系
在物理學上,要描述一個物體的運動旗闽,就必須選定一個參考系酬核,所謂滑動,正是相對于參考系的運動适室,在Android嫡意,系統(tǒng)將屏幕最左上角的頂點作為Android坐標系的原點,從這個點向右是X軸正方向捣辆,從這個點向下是Y軸正方向蔬螟,如下圖所示。
系統(tǒng)提供了getLocationOnScreen(intlocation[])來獲取Android坐標中的位置汽畴,即該視圖左上角Android的坐標旧巾,另外耸序,在觸摸事件中使用getRawX(),getRawY()方法來獲取坐標同樣是Android坐標系中的坐標。
視圖坐標系
Android中除了上面所說的這種坐標系之外們還有一個視圖坐標系鲁猩,他描述了子視圖在父視圖的位置關(guān)系坎怪,這兩個坐標系并不復(fù)雜也不矛盾,他們的作用是相輔相成的廓握,與Android坐標系類似搅窿,視圖坐標系同樣的以原點向右為X正方向,以原點向下為Y方法隙券,只不過在視圖坐標系中男应,原點不再是Android坐標系中的屏幕左上角,而是以父視圖左上角為坐標原點是尔,如下圖所示殉了。
在觸控事件中通過getX,getY來獲取的坐標就是視圖坐標中的坐標。
觸控事件——MotionEvent
觸控事件MotionEvent在用戶的交互中拟枚,占著舉足輕重的位置薪铜,學好觸控事件是掌握后續(xù)內(nèi)容的基礎(chǔ),首先恩溅,我們來看看MotionEvent中封裝的一些常量隔箍,他定義了觸摸事件的不同類型。
//單點觸摸按下的動作
public static final int ACTION_DOWN = 0;
//單點觸摸離開的動作
public static final int ACTION_UP = 1;
//單點觸摸移動的動作
public static final int ACTION_MOVE = 2;
//單點觸摸取消
public static final int ACTION_CANCEL = 3;
//單點觸摸超出邊界
public static final int ACTION_OUTSIDE = 4;
//多點觸摸按下的動作
public static final int ACTION_POINTER_DOWN = 5;
//多點觸摸離開的動作
public static final int ACTION_POINTER_UP = 6;
通常情況下脚乡,我們會在onTouchEvent(MotionEvent event)方法中通過event.getAction()來獲取觸摸事件的類型蜒滩,并使用switch來判斷,這個代碼模塊是固定的奶稠。
@Override
public boolean onTouchEvent(MotionEvent event) {
//獲取當前輸入點的X,Y坐標(視圖坐標)
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//處理輸入的按下動作
break;
case MotionEvent.ACTION_MOVE:
//處理輸入的移動動作
break;
case MotionEvent.ACTION_UP:
//處理輸入的離開動作
break;
}
return true;
}
在不涉及多點觸控的前提下俯艰,通常可以使用以上代碼來完成觸摸事件的監(jiān)聽锌订,不過這里只是一個代碼模塊竹握,后面我們會講具體的邏輯的。
Android獲取坐標的方法
在Android中辆飘,系統(tǒng)提供了非常多的方法來獲取坐標值啦辐,相對距離等,方法豐富固然好蜈项,但也給初學者帶來了很多的困擾芹关,不知道在什么情況下使用下圖總結(jié)人一下一些常用的API。
這些方法可以分成兩個類別:
- View提供的獲取坐標方法:
- getTop():獲取到的是View自身的頂部到其父布局頂部的距離紧卒。
- getLeft():獲取到的是View自身的左邊到其父布局左邊的距離侥衬。
- getRight():獲取到的是View自身的右邊到其父布局左邊的距離。
- getBottom():獲取到的是View自身的底部到其父布局頂部的距離。
- MotionEvent提供的方法:
- getX():獲取點擊事件距離控件左邊的距離轴总,即視圖坐標贬媒。
- getY():獲取點擊事件距離控件頂部的距離,即視圖坐標肘习。
- getRawX:獲取點擊事件整個屏幕左邊的距離,即絕對坐標坡倔。
- getRawY:獲取點擊事件整個屏幕頂部的距離漂佩,即絕對坐標。
實現(xiàn)滑動的七種方法
當了解了Android坐標系和觸控事件之后罪塔,我們再來看一看如何使用系統(tǒng)提供的API來實現(xiàn)動態(tài)的修改一個View的坐標投蝉,即滑動效果,而不管采用哪種方式征堪,其實現(xiàn)的思路基本上是一樣的瘩缆,當觸摸View的時候,系統(tǒng)幾下View的坐標佃蚜,從而獲得到相對于之前坐標的偏移量庸娱,并通過偏移量來修改View的坐標,這樣不斷的重復(fù)就實現(xiàn)了滑動的過程谐算。
下面通過實例來看看Android中該如何實現(xiàn)滑動效果熟尉。定義一個View,并置于一個LinearLayout中洲脂,實現(xiàn)一個簡單的布局斤儿,代碼如下所示。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.lgl.scrollviewdemo.DragView
android:layout_width="100dp"
android:layout_height="100dp" />
</RelativeLayout>
默認的顯示樣子如下圖所示恐锦。
layout方法
我們都知道往果,在View的繪制上,會調(diào)用onLayout()方法來設(shè)置顯示的位置一铅,同樣可以修改View的left陕贮,top,right馅闽,bottom四個屬性來控制View的坐標飘蚯,與前面提供的模板代碼一樣,每次調(diào)用onTouchEvent()的時候福也,我們來獲取點的坐標局骤,這里的邏輯很清楚,代碼如下所示暴凑。
//觸摸事件
private int lastX = 0;
private int lastY = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//記錄觸摸點的坐標
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_MOVE:
//計算偏移量
int officeX = rawX - lastX;
int officeY = rawY - lastY;
//在當前的left,top,right,bottom基礎(chǔ)上加上偏移量
layout(getLeft() + officeX, getTop() + officeY, getRight() + officeX, getBottom() + officeY);
//重新設(shè)置初始值
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_UP:
//處理輸入的離開動作
break;
}
return true;
}
這里我們就可以移動這個View了峦甩。
offsetLeftAndRight()與offsetTopAndBottom()
這個方法相當于系統(tǒng)提供的一個對左右,上下移動的封裝,當計算出偏移量的時候凯傲,只需要使用如下的代碼就可以完成View的重新布局犬辰,效果和使用Layout()方法是一樣的。
//同時對左右偏移
offsetLeftAndRight(officeX);
//同時對上下偏移
offsetTopAndBottom(officeY);
LayoutParams
LayoutParams保留了一個View的布局參數(shù)冰单,因此可以在程序中幌缝,通過改變LayoutParams來動態(tài)改變一個布局的位置參數(shù),從而改變View位置的效果诫欠,我們可以很方便的在程序中使用getLayoutParams()來獲取一個View的LayoutParams涵卵,當然,在計算偏移量的方法和Layout方法中計算offset是一樣的荒叼,當獲取到偏移量之后轿偎,可以通過setLayoutParams來改變LayoutParams,代碼如下所示被廓。
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft()+officeX;
layoutParams.topMargin = getTop()+officeY;
setLayoutParams(layoutParams);
不過這里需要注意的是坏晦,通過getLayoutParams()獲取layoutParams時,需要根據(jù)View所在的跟布局的類型來設(shè)置不同的類型嫁乘,比如View放在LinearLayout里那就是 LinearLayout.LayoutParams昆婿,比如在RelativeLayout里就是 RelativeLayout.LayoutParams,不然系統(tǒng)是無法獲取到layoutParams的亦渗。
在通過一個layoutParams來改變一個View的位置時挖诸,通常改變的是這個view的Margin屬性,所以除了使用布局的layoutParams屬性外法精,還需要 ViewGroup.MarginLayoutParams來實現(xiàn)這樣的功能多律。
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft()+officeX;
layoutParams.topMargin = getTop()+officeY;
setLayoutParams(layoutParams);
我們可以發(fā)現(xiàn),用ViewGroup更好搂蜓,都不用去管父布局是什么狼荞。
scrollTo與scrollBy
在一個View當中,系統(tǒng)提供了scrollTo與scrollBy這兩種方式來實現(xiàn)移動一個View的位置帮碰,這兩種方法的區(qū)別也很好理解相味,to和by,scrollTo(x,y)表示移動到一個具體的點殉挽,scrollBy(dx,dy)表示移動的增量丰涉。
int officeX = rawX - lastX;
int officeY = rawY - lastY;
scrollBy(officeX,officeY);
但是,當我們拖動View的時候斯碌,你會發(fā)現(xiàn)View并沒有移動一死,難道我們寫錯了?方法沒有寫錯傻唾,View也的確移動了投慈,但是他移動的并不是我們想要的東西承耿,他只是移動了view的content,即讓View的內(nèi)容移動了伪煤,如果用ViewGroup使用to和by的話加袋,那所有的子View都將移動,要是在View中使用的話抱既,职烧,那么移動的就是View的內(nèi)容了,我們舉個例子防泵,比如TextView阳堕,content就是他的文本,ImageView择克,drawable就是對象。
相信通過上面的分析前普,你也應(yīng)該知道為什么不能再View里面使用這個兩個方法來拖動這個view了肚邢,那么我們就該View所在的ViewGroup中使用scrollBy方法來移動這個view。
((View)getParent()).scrollBy(officeX,officeY);
但是拭卿,當再次拖動View的時候骡湖,你會發(fā)現(xiàn)View雖然移動了,但卻在亂動峻厚,并不是我們想要的跟隨觸摸點的移動而移動响蕴,這里需要先了解一下視圖移動的一些知識,大家在理解這個問題的時候惠桃,不妨想象一下手機是一個中空的蓋板浦夷,蓋板下面是一個巨大的畫布,也就是我們想要顯示的視圖辜王,當把這個蓋板蓋在畫布的某處時劈狐,透過中間空著的矩形,我們看見了手機屏幕上顯示的視圖呐馆,而畫布上其他的視圖肥缔,則被蓋板蓋住了無法看見,我們的視圖和這個例子事項相似汹来,我們沒有看見視圖续膳,但并不代表它不存在,有可能只是在屏幕外面而已收班,當調(diào)用scrollBy的方法時坟岔,可以想象外面的蓋板在移動,這么說比較抽象闺阱,我們來看一下具體的例子炮车。
上圖,中間的矩形相當于屏幕,即可是區(qū)域瘦穆,后面的content相當于畫布纪隙,代表視圖,大家可以看到扛或,只有視圖的中間部分目前是可視的绵咱,其他部分都不可見,可見區(qū)域中設(shè)置一個button,他的坐標是(20.10)熙兔,下面我們使用scrollBy方法來進行移動后如圖悲伶。
我們會發(fā)現(xiàn),雖然設(shè)置scrollBy(20.10)住涉,偏移量均為XY的正方向麸锉,但是屏幕的可視區(qū)域,Button卻向反方向移動了舆声,這就是參考系選擇的不同花沉,而產(chǎn)生的不同效果。
通過上面的分析媳握,可以發(fā)現(xiàn)碱屁,我們將scrollBy的參數(shù)dx,dy設(shè)置成正數(shù),那么content將向坐標軸負方向移動蛾找,反之娩脾,則正方向。
int officeX = rawX - lastX;
int officeY = rawY - lastY;
scrollBy(-officeX,-officeY);
再去試驗一下打毛,大家可以發(fā)現(xiàn)柿赊,效果和前面的幾種方法相同了,類似的幻枉,我們使用scrollTo也是可以實現(xiàn)的闹瞧。
Scroller
scrollTo與scrollBy是一瞬間完成的事情,很突兀展辞,而Scroller就可以實現(xiàn)平滑的效果奥邮。Scroller的原理與前面使用scrollTo與scrollBy的方法原理是一樣的。代碼如下所示罗珍。
- 初始化scroller :
首先洽腺,通過他的構(gòu)造方法來創(chuàng)建一個scroller對象。
//初始化mScroller
mScroller = new Scroller(context);
- 重寫computeScroll覆旱,實現(xiàn)模擬滑動:
下面我們需要重寫computeScroll這個方法蘸朋,他是使用Scroller的核心,系統(tǒng)在繪制View的同時扣唱,會在onDraw()方法中調(diào)用這個方法藕坯,這個方法實際上就是使用了ScrollTo()方法再結(jié)合Scroller對象团南,幫助獲取到當前的滾動值,我們可以通過不斷的瞬息移動一個小的距離來實現(xiàn)整體上的平滑移動效果炼彪,通常情況下吐根,computeScroll的代碼可以利用標準的寫法。
/**
* 模擬滑動
*/
@Override
public void computeScroll() {
super.computeScroll();
//判斷Scroller是否執(zhí)行完畢
if (mScroller.computeScrollOffset()) {
((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
}
//通過重繪來不斷調(diào)用computeScroll
invalidate();
}
Scroller類提供了computeScrollOffset()來判斷是否完成了整個頁面的滑動辐马,同時也提供了getCurrX()拷橘,getCurrY()來獲取當前滑動坐標,上面唯一要注意的就是invalidate()了喜爷,因為只能在computeScroll中獲得模擬過程中的scrollX和scrollY坐標冗疮,但computeScroll方法是不會自動調(diào)用的,只能通過invalidate→OnDraw→computeScroll()來簡介調(diào)用檩帐,所以需要這個invalidate术幔,而當模擬過程結(jié)束的時候,computeScrollOffset返回的是false湃密,從而結(jié)束循環(huán)特愿。
- startScroll開啟模擬過程:
最后,萬事俱備只欠東風了勾缭,我們需要使用平滑移動事件,使用Scroller類的startScroll()方法來開啟平滑過程目养,startScroll有兩個重載的方法俩由。
public void startScroll(int startX, int startY, int dx, int dy, int duration) {}
public void startScroll(int startX, int startY, int dx, int dy) {}
可以看到他們的區(qū)別分別是具有指定的持續(xù)時長,而另一個每有癌蚁,與在動畫中的設(shè)置時間是一樣的幻梯,而其他四個坐標,就是起始和偏移量努释,通過上述的步驟碘梢,就可以完成一個平移的效果了。
下面我們回到實例伐蒂,在構(gòu)造分鐘初始化Scroller對象煞躬,然后重寫computeScroll方法,最后需要監(jiān)聽手指離開屏幕的事件逸邦,并在該事件之后調(diào)用startScroll()完成平移恩沛,所以我們在ACTION_UP中。
case MotionEvent.ACTION_UP:
//處理輸入的離開動作
View view = ((View)getParent());
mScroller.startScroll(view.getScrollX(),view.getScrollY(),view.getScrollX(),view.getScrollY());
invalidate();
break;
屬性動畫
這一內(nèi)容比較多缕减,放到以后再詳細記錄雷客。
ViewDragHelper
Google在其support庫中為我們提供了一個DrawerLayout和SlidingPaneLayout兩個布局來幫助開發(fā)者實現(xiàn)側(cè)劃效果,這兩個布局桥狡,大大的方便了我們自己創(chuàng)建自己的滑動布局搅裙,然而皱卓,這兩個強大的布局背后,卻隱藏著一個鮮為人知部逮,卻功能強大的類——ViewDragHelper娜汁,通過ViewDragHelper,基本可以實現(xiàn)各種不同的側(cè)滑甥啄,拖放需求存炮,因此這個方法也是各種滑動解決方案的終極絕招。
ViewDragHelper雖然很強大蜈漓,但是使用也是本章節(jié)最復(fù)雜 的穆桂,我們需要了解ViewDragHelper的基本使用方法的基礎(chǔ)上,通過不斷的練習去掌握它融虽,我們這里就實現(xiàn)一個 QQ滑動側(cè)邊欄的布局享完,我么來看看具體怎么實現(xiàn)的。
- 初始化ViewDragHelper:
首先有额,自認是初始化ViewDragHelper般又,ViewDragHelper通常定義在一個ViewGroup中,通過其靜態(tài)方法初始化巍佑。
mViewDragHelper = ViewDragHelper.create(this,callback);
他的第一個參數(shù)是要監(jiān)聽的View茴迁,第二個參數(shù)是一個Callback回調(diào),這個回調(diào)是整個業(yè)務(wù)的核心萤衰。
- 攔截事件:
接下來堕义,要重寫攔截事件,將事件傳遞給ViewDragHelper進行處理脆栋。
//事件攔截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
//觸摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
//將觸摸事件傳遞給ViewDragHelper
mViewDragHelper.processTouchEvent(event);
return true;
}
- 處理computeScroll():
沒錯倦卖,使用ViewDragHelper也是需要重寫computeScroll的,因為ViewDragHelper內(nèi)部也是通過Scroller來實現(xiàn)平移的椿争,我們可以這樣使用怕膛。
@Override
public void computeScroll() {
if(mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
- 處理回調(diào)Cakkback:
我們可以直接的new出來。
//側(cè)滑回調(diào)
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
//何時開始觸摸
@Override
public boolean tryCaptureView(View child, int pointerId) {
//如果當前觸摸的child是mMainView開始檢測
return mMainView == child;
}
//處理水平滑動
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
//處理垂直滑動
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
//拖動結(jié)束后調(diào)用
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起后緩慢的移動到指定位置
if (mMainView.getLeft() < 500) {
//關(guān)閉菜單
mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
} else {
//打開菜單
mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
- 定義ViewGroup的onFinishInflate()方法
在onFinishInflate()方法中秦踪,按順序?qū)⒆覸iew分別定義為MenuView和MainView,并在onSizeChanged()方法中獲得View的寬度椅邓。如果你根據(jù)View的寬度來滑動后的效果希坚,就可以使用這個值來判斷个束。
//XML加載組建后回調(diào)
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView = getChildAt(0);
mMainView = getChildAt(1);
}
//組件大小改變時回調(diào)
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = mMenuView.getMeasuredWidth();
}
- 最后通過整個ViewDragHelper來實現(xiàn)側(cè)滑的代碼如下:
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
* QQ側(cè)滑
* Created by lgl on 16/3/22.
*/
public class DragViewGroup extends FrameLayout {
//側(cè)滑類
private ViewDragHelper mViewDragHelper;
private View mMenuView, mMainView;
private int mWidth;
public DragViewGroup(Context context) {
super(context);
initView();
}
public DragViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
//初始化數(shù)據(jù)
private void initView() {
mViewDragHelper = ViewDragHelper.create(this, callback);
}
//XML加載組建后回調(diào)
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView = getChildAt(0);
mMainView = getChildAt(1);
}
//組件大小改變時回調(diào)
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = mMenuView.getMeasuredWidth();
}
//事件攔截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
//觸摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
//將觸摸事件傳遞給ViewDragHelper
mViewDragHelper.processTouchEvent(event);
return true;
}
//側(cè)滑回調(diào)
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
//何時開始觸摸
@Override
public boolean tryCaptureView(View child, int pointerId) {
//如果當前觸摸的child是mMainView開始檢測
return mMainView == child;
}
//處理水平滑動
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
//處理垂直滑動
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
//拖動結(jié)束后調(diào)用
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起后緩慢的移動到指定位置
if (mMainView.getLeft() < 500) {
//關(guān)閉菜單
mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
} else {
//打開菜單
// mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0); // 側(cè)邊欄寬度為300
mViewDragHelper.smoothSlideViewTo(mMainView, mWidth, 0); // 側(cè)邊欄寬度為布局定義寬度
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
@Override
public void computeScroll() {
if (mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
- 最后在xml布局中使用
<?xml version="1.0" encoding="utf-8"?>
<com.example.cc.myapplication.DragViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:windowSoftInputMode="adjustPan|stateHidden">
<LinearLayout
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="@android:color/black"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="24sp"
android:textColor="@android:color/white"
android:text="側(cè)邊欄"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:textSize="24sp"
android:textColor="@android:color/white"
android:text="主界面"/>
</LinearLayout>
</com.example.cc.myapplication.DragViewGroup>
這只是簡單模擬QQ側(cè)滑菜單這個功能。ViewDragHelper還有很多強大的功能涉馁。
- ViewDragHelper.Callback的其它監(jiān)聽事件
系統(tǒng)定義了大量的監(jiān)聽事件幫助我們處理各種事件爱致,下面就列舉幾個帮坚。
事件 | 作用 |
---|---|
onViewCaptured() | 在用戶觸摸到View后回調(diào)试和。 |
onViewDragStateChanged() | 在拖拽狀態(tài)改變時回調(diào)(idle阅悍,draggin等狀態(tài))。 |
onViewPositionChanged() | 在位置改變時回調(diào)(常用于滑動時更改scale進行縮放等效果)悦昵。 |