Android 仿當(dāng)樂游戲詳情頁(yè)面(三)


在上兩篇文章中奉呛,我們已經(jīng)實(shí)現(xiàn)了基本的界面的布局和移動(dòng)效果胯陋,但是mImgShotViewmContentView卻不能響應(yīng)事件扒磁,而事件的響應(yīng)就需要我們手動(dòng)進(jìn)行事件分發(fā)庆揪!</br>
android 仿當(dāng)樂游戲詳情頁(yè)面(一)</br>
android 仿當(dāng)樂游戲詳情頁(yè)面(二)

事件分發(fā)分析

在前面第二篇中,我們是通過手勢(shì)來實(shí)現(xiàn)布局的移動(dòng)妨托,為了讓系統(tǒng)能響應(yīng)手勢(shì)缸榛,在onTouchEvent(MotionEvent event)方法里面,調(diào)用了mDetector.onTouchEvent(event);將系統(tǒng)的焦點(diǎn)傳遞給了手勢(shì)始鱼,因此仔掸,當(dāng)滑動(dòng)mImgShotView這個(gè)ViewPager時(shí)脆贵,會(huì)出現(xiàn)焦點(diǎn)丟失医清,截圖不能進(jìn)行切換的問題。</br>
因此卖氨,解決這個(gè)問題最好的方法就是重寫dispatchTouchEvent(MotionEvent ev)方法会烙,對(duì)事件分發(fā)進(jìn)行處理。</br>
在上一篇文章中筒捺,已經(jīng)介紹了柏腻,在仿當(dāng)樂的游戲詳情頁(yè)面中,mContentView有三種不同的狀態(tài):

  1. 頂部狀態(tài)時(shí)系吭,ToolBarmContentView將獲取到焦點(diǎn)五嫂。
  2. 中間狀態(tài)時(shí),ToolBarmImgShotView將獲取到焦點(diǎn)肯尺。
  3. 底部狀態(tài)時(shí)沃缘,上一篇文章中已經(jīng)介紹了,這個(gè)狀態(tài)则吟,mImgShotView的參數(shù)將發(fā)生改變槐臀,因此,事件焦點(diǎn)的分發(fā)便需要進(jìn)行改變氓仲。

事件分發(fā)的實(shí)現(xiàn)

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (mRawY <= mTopL) {
        mCurrentState = STATE_TOP;
    } else if (mTopL < mRawY && mRawY <= mCenterL + (mBarH >> 1)) {
        mCurrentState = STATE_CENTER;
    } else if (mCenterL + (mBarH >> 1) <= mRawY && mRawY < mBottomL + mBarH) {
        mCurrentState = STATE_BOTTOM;
    } else {
        mCurrentState = STATE_OTHER;
    }
    boolean isTop = mRawY == mTopL;
    // 處理橫向滑動(dòng)的事件
    if (Math.abs(ev.getX() - mOldX) >= 0 && Math.abs(ev.getY() - mOldY) < 300 && isTop) {
        mOldX = ev.getX();
        return super.dispatchTouchEvent(ev);
    }

    float t = Math.abs(ev.getY() - mOldY);
    //處于頂部時(shí)的事件過濾區(qū)域
    if (isTop && (ev.getY() < mTopL || t < 10)) {
        return super.dispatchTouchEvent(ev);
    }

    //處于中間時(shí)的事件過濾區(qū)域
   if (mCurrentState == STATE_CENTER && ev.getY() < (mCenterL + mBarH) && mRawY >= mCenterL) {
        return super.dispatchTouchEvent(ev);
    }

    //處于底部時(shí)的事件過濾區(qū)域
    if (mCurrentState == STATE_BOTTOM && ev.getY() < (mBottomL + mBarH) && mRawY >= mBottomL) {
        return super.dispatchTouchEvent(ev);
    }

    boolean isUp = ev.getY() - mOldY < 0;

    if (isTop && mCurrentState == STATE_TOP) {
        mOldY = (int) ev.getY();
        if (isScrollTop && !isUp) {
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                return super.dispatchTouchEvent(ev);
            }
            return onTouchEvent(ev);
        } else {
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                return super.dispatchTouchEvent(ev);
            }
            return super.dispatchTouchEvent(ev);
        }
    }

    return onTouchEvent(ev);
}

以上便是事件分發(fā)的全部代碼</br>
我們從最簡(jiǎn)單的地方開始分析代碼水慨,在上一篇文章中得糜,定義了幾個(gè)變量mTopL、mCenterL晰洒、mBottomL用來確定布局移動(dòng)的基準(zhǔn)位置朝抖,mRawY用來確定布局的當(dāng)前的Y坐標(biāo)。</br>
因此谍珊,便可以使用這幾個(gè)變量來確認(rèn)當(dāng)前布局所處的狀態(tài):

1. mRawY <= mTopL                                                 ==>   布局處于頂部狀態(tài)
2. mTopL < mRawY && mRawY <= mCenterL + (mBarH >> 1)              ==>   布局處于中間狀態(tài)槽棍。
3. mCenterL + (mBarH >> 1) <= mRawY && mRawY < mBottomL + mBarH   ==>   布局處于底部狀態(tài)

在2、3中抬驴,mBarH表示的是ToolBar的高度常量炼七,+ mBarH,表示往下移動(dòng)的偏移常量布持。</br>

處理普通的事件過濾

繼續(xù)看代碼豌拙,

float t = Math.abs(ev.getY() - mOldY);
//處于頂部時(shí)的事件過濾區(qū)域
if (isTop && (ev.getY() < mTopL || t < 10)) {
    return super.dispatchTouchEvent(ev);
}

//處于中間時(shí)的事件過濾區(qū)域
if (mCurrentState == STATE_CENTER && ev.getY() < (mCenterL + mBarH) && mRawY >= mCenterL) {
    return super.dispatchTouchEvent(ev);
}

//處于底部時(shí)的事件過濾區(qū)域
if (mCurrentState == STATE_BOTTOM && ev.getY() < (mBottomL + mBarH) && mRawY >= mBottomL) {
    return super.dispatchTouchEvent(ev);
}
  1. 第一個(gè)if語(yǔ)句,是用來處理頂部狀態(tài)的事件過濾的题暖,但是由于布局處于頂部狀態(tài)時(shí)按傅,mContentView需要獲取事件,而mContentView是一個(gè)ViewPager胧卤,如果ViewPager加載的Fragment有滑動(dòng)控件唯绍,將是一個(gè)很復(fù)雜的分發(fā)過程,而Fragment滑動(dòng)控件的處理我們是必須考慮的枝誊。</br>
    因此况芒,第一個(gè)if語(yǔ)句里面,只處理mContentView的處于頂部狀態(tài)時(shí)的點(diǎn)擊事件叶撒,只要t小于10绝骚,就判斷當(dāng)前的事件為點(diǎn)擊事件。而為了讓焦點(diǎn)從手勢(shì)交還給系統(tǒng)祠够,只需要return super.dispatchTouchEvent(ev);便能將事件焦點(diǎn)攔截交還給系統(tǒng)压汪。
  2. 第二個(gè)if語(yǔ)句就比較簡(jiǎn)單了,當(dāng)處于中間狀態(tài)時(shí),只要事件的Y坐標(biāo)小于mCenterL + mBarH坐標(biāo)時(shí),統(tǒng)統(tǒng)將事件焦點(diǎn)交還給系統(tǒng), mRawY >= mCenterL缀磕,有這個(gè)判斷時(shí),系統(tǒng)才能確定是中間狀態(tài)時(shí)的事件過濾穿香,不會(huì)導(dǎo)致晚上移動(dòng)的情況下,莫名奇妙事件就交給了系統(tǒng)叽奥。
  3. 第三個(gè)if語(yǔ)句和第二個(gè)if語(yǔ)句差不多扔水,mRawY >= mBottomL這句代碼同上所示,只有這個(gè)判斷時(shí)朝氓,才能確認(rèn)是底部事件的過濾魔市,如果沒有這句話主届,mContentView在中間狀態(tài)時(shí),就會(huì)處理待德,底部事件的過濾君丁,將導(dǎo)致,mContentView處于中間狀態(tài)時(shí)将宪,將失去對(duì)手勢(shì)的控制绘闷。

接下來便是處理mContentView的滑動(dòng)控件的事件處理了!</br>
在當(dāng)樂的游戲詳情界面中较坛,mContentView處于頂部時(shí)印蔗,里面的ListView或者ScrollView,只有滑動(dòng)到最頂部時(shí)丑勤,再外下滑動(dòng)华嘹,mContentView才能將焦點(diǎn)交還給系統(tǒng)。

處理Fragment 中滑動(dòng)事件過濾

boolean isUp = ev.getY() - mOldY < 0;

if (isTop && mCurrentState == STATE_TOP) {
    mOldY = (int) ev.getY();
    if (isScrollTop && !isUp) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            return super.dispatchTouchEvent(ev);
        }
        return onTouchEvent(ev);
    } else {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            return super.dispatchTouchEvent(ev);
        }
        return super.dispatchTouchEvent(ev);
    }
}

如上的代碼所示法竞,如果耙厚,當(dāng)mContentView中的Fragment的滑動(dòng)控件滑動(dòng)到頂部,并且mContentView處于頂部岔霸,并且手勢(shì)向上則將事件焦點(diǎn)交給手勢(shì)薛躬,否則,交還給系統(tǒng)呆细。</br>
這里需要注意以下兩行代碼:

if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    return super.dispatchTouchEvent(ev);
}

這兩行代碼是整個(gè)滑動(dòng)事件分發(fā)的靈魂!!!型宝,這兩句代碼是告訴系統(tǒng),當(dāng)焦點(diǎn)進(jìn)行交換時(shí)侦鹏,告訴當(dāng)前掌控焦點(diǎn)的服務(wù)(系統(tǒng)诡曙、手勢(shì))交出焦點(diǎn)臀叙,重新進(jìn)行分配B运!如果沒有這兩句代碼劝萤,焦點(diǎn)的切換將很有可能失斣ɡ浴(就為了寫出兩行代碼,工期延期了整整一個(gè)星期床嫌,說多了都是淚?缡汀!Q岽Α1钐浮!@妗@峦蕖)捷绒。

處理橫向事件過濾

if (Math.abs(ev.getX() - mOldX) >= 0 && Math.abs(ev.getY() - mOldY) < 300 && isTop) {
     mOldX = ev.getX();
     return super.dispatchTouchEvent(ev);
 }

以上代碼是實(shí)現(xiàn)mContentViewfragment的切換的,這代碼很簡(jiǎn)單贯要,只要是橫向手勢(shì)暖侨,并且X的偏差小于300就認(rèn)為其是橫向事件。

最終效果

最終效果

寫在最后

來來回回一個(gè)多月崇渗,這個(gè)頁(yè)面的blog算是寫完了(整個(gè)功能實(shí)現(xiàn)也就7字逗、8天,寫著blog寫了快兩個(gè)月了宅广,懶癌晚期傷不起)『簦現(xiàn)在的效果已經(jīng)和當(dāng)樂的差不多了,但是還是有點(diǎn)差別跟狱,比如挖息,我這沒有底部欄,比如兽肤,我這中間狀態(tài)不能對(duì)mContentView進(jìn)行切換套腹,其實(shí)這些都很容易實(shí)現(xiàn)(其實(shí)我是懶癌晚期,不想寫了..)</br>
最后還是說個(gè)思路吧:

  1. 底部導(dǎo)航欄那個(gè)资铡,在布局里面寫FrameLayout电禀,然后編寫自定義View,在主界面的代碼里面笤休,給mContentView設(shè)置addOnPageChangeListener事件監(jiān)聽尖飞,在滑動(dòng)的過程中,F(xiàn)rameLayout動(dòng)態(tài)添加你的自定義的導(dǎo)航欄View店雅。(我在公司的APP里面采用的是這個(gè)思路)
  2. mContentView中間狀態(tài)的切換政基,這個(gè)只需要在下面的語(yǔ)句中添加橫向狀態(tài)的添加橫向手勢(shì)移動(dòng)的判斷方法便可以了,需要注意下事件分發(fā)的范圍
if (mCurrentState == STATE_CENTER && ev.getY() < (mCenterL + mBarH) && mRawY >= mCenterL) {
    return super.dispatchTouchEvent(ev);
}

源代碼

其實(shí)上面說的全部都是廢話闹啦,真正重要的還是源代碼>诿鳌!</br>
點(diǎn)擊我獲取源代碼窍奋,最后跪求star和issues

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荐健,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子琳袄,更是在濱河造成了極大的恐慌江场,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窖逗,死亡現(xiàn)場(chǎng)離奇詭異址否,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碎紊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門佑附,熙熙樓的掌柜王于貴愁眉苦臉地迎上來用含,“玉大人,你說我怎么就攤上這事帮匾∽暮В” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵瘟斜,是天一觀的道長(zhǎng)缸夹。 經(jīng)常有香客問我,道長(zhǎng)螺句,這世上最難降的妖魔是什么虽惭? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮蛇尚,結(jié)果婚禮上芽唇,老公的妹妹穿的比我還像新娘。我一直安慰自己取劫,他們只是感情好匆笤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谱邪,像睡著了一般炮捧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惦银,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天咆课,我揣著相機(jī)與錄音,去河邊找鬼扯俱。 笑死书蚪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迅栅。 我是一名探鬼主播殊校,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼库继!你這毒婦竟也來了箩艺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宪萄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后榨惰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拜英,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年琅催,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了居凶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虫给。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖侠碧,靈堂內(nèi)的尸體忽然破棺而出抹估,到底是詐尸還是另有隱情,我是刑警寧澤弄兜,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布药蜻,位于F島的核電站,受9級(jí)特大地震影響替饿,放射性物質(zhì)發(fā)生泄漏语泽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一视卢、第九天 我趴在偏房一處隱蔽的房頂上張望踱卵。 院中可真熱鬧,春花似錦据过、人聲如沸惋砂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)班利。三九已至,卻和暖如春榨呆,著一層夾襖步出監(jiān)牢的瞬間罗标,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工积蜻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留闯割,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓竿拆,卻偏偏與公主長(zhǎng)得像宙拉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丙笋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,867評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)谢澈、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,066評(píng)論 4 62
  • 在上一篇文章里面御板,基本上算是實(shí)現(xiàn)了該效果的布局锥忿,有了布局,接下來就要對(duì)布局進(jìn)行移動(dòng)處理怠肋。 android 仿當(dāng)樂游...
    dorn19978閱讀 1,035評(píng)論 0 11
  • 微信每一次新功能的推出都令用戶的神經(jīng)為之振奮,紅包照片這一功能更是讓我對(duì)微信產(chǎn)品經(jīng)理的膜拜之情上升到一個(gè)前所未...
    析思閱讀 624評(píng)論 1 1
  • 21天踐行打卡 Day13 【靜心】每天有一段時(shí)間钉答,關(guān)注自己础芍。 【動(dòng)身】去小學(xué)聽課。 【成長(zhǎng)】不斷學(xué)習(xí)数尿。 【助人】...
    石頭縫里的小嫩芽變大樹閱讀 114評(píng)論 0 1