View的事件體系(一)

1.View的基礎(chǔ)知識(shí)

(1)什么是View

View是Android中所有控件的基類谤绳,不管是簡(jiǎn)單的TextView還是復(fù)雜的RelativeLayout和ListView抛姑,它們共同的基類都是View。

ViewGroup:內(nèi)部包含了多個(gè)控件驶赏,即一組View院喜。

在Android中,ViewGroup也繼承View证芭,這就意味著View本身就可以是單個(gè)控件也可以是由多個(gè)控件組成的一組控件瞳浦。

(2)View的位置參數(shù)

View的四個(gè)屬性:top、left废士、right叫潦、bottom,其中top是左上角縱坐標(biāo)官硝,left是左上角橫坐標(biāo)矗蕊,right是右下角橫坐標(biāo),bottom是右下角縱坐標(biāo)氢架。

//這些坐標(biāo)都是相對(duì)于view父容器的
//view 左上角的坐標(biāo)(mTop傻咖,mLeft)
//view 右上角坐標(biāo)(mBottom,mRight)
mTop = mBtView.getTop();
mLeft = mBtView.getLeft();
mBottom = mBtView.getBottom();
mRight = mBtView.getRight();

//得出當(dāng)前view的寬和高  單位是像素  px
int width = mRight - mLeft;
int height = mBottom - mTop;

從Android3.0開始岖研,View增加了額外的幾個(gè)參數(shù):x卿操、y、translationX孙援、translationY害淤。

其中x和y是View左上角的坐標(biāo),translationX和translationY是View左上角相對(duì)于父容器的偏移量

x = left+translationX
y = top+translationY

(3)MotionEvent和TouchSlop

MotionEvent

在手指接觸屏幕后所產(chǎn)生的一系列事件中拓售,典型的事件類型有以下幾種:

  • ACTION_DOWN:手指剛接觸屏幕
  • ACTION_MOVE:手指在屏幕上移動(dòng)
  • ACTION_UP: 手指在屏幕上松開

正常情況下窥摄,一次手指接觸屏幕的行為會(huì)觸發(fā)一些列點(diǎn)擊事件

  • 點(diǎn)擊屏幕后離開松開,事件序列為:DOWN->UP
  • 點(diǎn)擊屏幕滑動(dòng)一會(huì)再松開邻辉,事件序列為:DOWN->MOVE->.....>MOVE->UP

通過MotionEvent對(duì)象我們可以得到點(diǎn)擊事件發(fā)生的x和y的坐標(biāo)溪王。

getX和getY:返回的是相對(duì)于當(dāng)前View左上角的x和y坐標(biāo)

getRawX和getRawY:返回到是相當(dāng)于手機(jī)屏幕左上角的x和y坐標(biāo)

TouchSlop

是系統(tǒng)所能識(shí)別出的被認(rèn)為是滑動(dòng)的最小距離腮鞍,是個(gè)常量,與設(shè)備有關(guān)莹菱。

可以通過
ViewConfiguration.get(getContext()).getScaledTouchSlop()獲取

(4)VelocityTracker移国、GestureDetector和Scroller

VelocityTracker

速度追蹤,用于追蹤手指在滑動(dòng)過程中的速度道伟,包括水平和豎直方向的速度迹缀,首先在View的onTouchEvent方法中追蹤當(dāng)前單擊事件的速度

VelocityTracker mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);

獲取當(dāng)前的滑動(dòng)速度


mVelocityTracker.computeCurrentVelocity(1000);
//x方向的速度
int xVelocity = (int) mVelocityTracker.getXVelocity();
//y方向的速度
int yVelocity = (int) mVelocityTracker.getYVelocity();

注意:獲取速度之前必須先加速速度,即在獲取速度之前要先調(diào)用computeCurrentVelocity方法

最后蜜徽,當(dāng)不在使用的時(shí)候祝懂,需要調(diào)用clear方法來重置并回收內(nèi)存

mVelocityTracker.clear();
mVelocityTracker.recycle();

GestureDetector

手勢(shì)檢測(cè),用戶輔助檢測(cè)用戶的點(diǎn)擊拘鞋、滑動(dòng)砚蓬、長(zhǎng)按、雙擊等行為盆色。

首先灰蛙,創(chuàng)建一個(gè)GestureDetector對(duì)象并實(shí)現(xiàn)OnGestureListener接口

GestureDetector mGestureDetector = new GestureDetector(MainActivity.this);
//解決長(zhǎng)按屏幕后無法拖動(dòng)的現(xiàn)象
mGestureDetector.setIsLongpressEnabled(false);

接著,接管目標(biāo)View的onTouchEvent方法隔躲,在待監(jiān)聽的onTouchEvent方法中添加如下實(shí)現(xiàn)


    @Override
    public boolean onTouchEvent(MotionEvent event) 
    {
        boolean  mBoolean = mMGestureDetector.onTouchEvent(event);
        return mBoolean;
    }

然后摩梧,可以有選擇的實(shí)現(xiàn)OnGestureListener和OnDoubleTabListener

OnGestureListener中要實(shí)現(xiàn)方法

 /**
     * 手指輕輕觸摸屏幕的一瞬間
     * @param event
     * @return
     */
    @Override
    public boolean onDown(MotionEvent event) {
        return false;
    }

    /**
     * 手指輕輕觸摸屏幕,尚未松開或拖動(dòng)
     * @param event
     */

    @Override
    public void onShowPress(MotionEvent event) {

    }

    /**
     * 用戶單擊
     * @param event
     * @return
     */

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        return false;
    }

    /**
     * 手指滑動(dòng)
     * @param event
     * @param event1
     * @param v
     * @param v1
     * @return
     */

    @Override
    public boolean onScroll(MotionEvent event, MotionEvent event1, float v, float v1) {
        return false;
    }

    /**
     * 長(zhǎng)按
     * @param event
     */
    @Override
    public void onLongPress(MotionEvent event) {

    }

    /**
     * 快速滑動(dòng)
     * @param event
     * @param event1
     * @param v
     * @param v1
     * @return
     */

    @Override
    public boolean onFling(MotionEvent event, MotionEvent event1, float v, float v1) {
        return false;
    }

Scroller

彈性滑動(dòng)對(duì)象宣旱,用于實(shí)現(xiàn)View的彈性滑動(dòng)仅父。

scrollTo/scrollBy方法來進(jìn)行滑動(dòng),其過程是瞬間完成的浑吟。

Scroller本身無法讓View彈性滑動(dòng)笙纤,它需要和View的computeScroll方法配合使用才能共同完成這個(gè)功能。

2.View的滑動(dòng)

三種方式實(shí)現(xiàn)View滑動(dòng):

  • 通過View本身提供的scrollTo/scrollBy方法來實(shí)現(xiàn)滑動(dòng)
  • 通過動(dòng)畫給View添加平移效果來實(shí)現(xiàn)滑動(dòng)
  • 通過改變View的LayoutParams使得View重新布局而實(shí)現(xiàn)滑動(dòng)

使用scrollTo/scrollBy

 public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            invalidateParentCaches();
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                postInvalidateOnAnimation();
            }
        }
    }

public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

從上面源碼可以看出scrollBy實(shí)際上是調(diào)用了scrollTo方法买置。

注意:scrollTo和scrollBy只能改變View的內(nèi)容位置而不能改變View在布局中的位置粪糙。

使用動(dòng)畫

可以采用View動(dòng)畫
也可以采用屬性動(dòng)畫,為了兼容3.0以前的版本忿项,可以采用開源動(dòng)畫庫nineoldandroids

nineoldandroids實(shí)現(xiàn)的屬性動(dòng)畫本質(zhì)上仍然是View動(dòng)畫蓉冈。

注意:View動(dòng)畫并不能改變View的位置,比如把一個(gè)Button右移100px轩触,但是點(diǎn)擊事件還在原來的位置寞酿。

改變布局參數(shù)

即改變LayoutParams,比如想把一個(gè)Button右移100px脱柱,我們只需要把這個(gè)Button的LayoutParams里的marginLeft參數(shù)的值增加100px即可

MarginLayoutParams  params = (MarginLayoutParams)mButton.getLayoutParams();
params.leftMargin +=100;
mButton.requestLayout;

各種滑動(dòng)方式對(duì)比

scrollTo和scrollBy:操作簡(jiǎn)單伐弹,只能改變View的內(nèi)容位置而不能改變View在布局中的位置。不影響內(nèi)部元素的點(diǎn)擊事件

動(dòng)畫:操作簡(jiǎn)單榨为,主要用于沒有交互的View和實(shí)現(xiàn)復(fù)雜的動(dòng)畫效果惨好,影響點(diǎn)擊事件

改變布局:操作復(fù)雜煌茴,適用于有交互的view

3.彈性滑動(dòng)

  • 使用Scroller
  • 通過動(dòng)畫
  • 使用延時(shí)策略

View的事件分發(fā)機(jī)制

事件的分發(fā)機(jī)制主要是有三個(gè)重要方法共同完成

dispatchTouchEvent:用于分發(fā)事件
onInterceptTouchEvent:是否攔截事件
onTouchEvent:處理點(diǎn)擊事件

分發(fā)機(jī)制:對(duì)于一個(gè)ViewGroup來說,點(diǎn)擊事件產(chǎn)生后日川,首先會(huì)傳遞給它蔓腐,這時(shí)它的dispatchTouchEvent就會(huì)被調(diào)用。
如果dispatchTouchEvent返回true就表示它要攔截當(dāng)前事件龄句,這個(gè)事件就會(huì)交給這個(gè)ViewGroup來處理回论,那么它的onTouchEvent就會(huì)被調(diào)用

如果dispatchTouchEvent返回false就表示它不攔截當(dāng)前事件,當(dāng)前事件就會(huì)繼續(xù)傳遞給它的子元素分歇,接著子元素的dispatchTouchEvent方法就會(huì)被調(diào)用傀蓉,如此反復(fù)直到事件被最終處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末职抡,一起剝皮案震驚了整個(gè)濱河市葬燎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缚甩,老刑警劉巖萨蚕,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蹄胰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)奕翔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門裕寨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人派继,你說我怎么就攤上這事宾袜。” “怎么了驾窟?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵庆猫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我绅络,道長(zhǎng)月培,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任恩急,我火速辦了婚禮杉畜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘衷恭。我一直安慰自己此叠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布随珠。 她就那樣靜靜地躺著灭袁,像睡著了一般猬错。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茸歧,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天倦炒,我揣著相機(jī)與錄音,去河邊找鬼举娩。 笑死析校,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铜涉。 我是一名探鬼主播智玻,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼芙代!你這毒婦竟也來了吊奢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤纹烹,失蹤者是張志新(化名)和其女友劉穎页滚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铺呵,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裹驰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了片挂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幻林。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖音念,靈堂內(nèi)的尸體忽然破棺而出沪饺,到底是詐尸還是另有隱情,我是刑警寧澤闷愤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布整葡,位于F島的核電站,受9級(jí)特大地震影響讥脐,放射性物質(zhì)發(fā)生泄漏遭居。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一攘烛、第九天 我趴在偏房一處隱蔽的房頂上張望魏滚。 院中可真熱鬧,春花似錦坟漱、人聲如沸鼠次。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腥寇。三九已至成翩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赦役,已是汗流浹背麻敌。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掂摔,地道東北人术羔。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乙漓,于是被迫代替她去往敵國和親级历。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容