【Android】打造下拉放大效果

前言

在其他App上看到了這樣的一個(gè)效果,感覺有點(diǎn)意思荆几,于是決定實(shí)現(xiàn)一個(gè)類似的效果。
其實(shí)是iOS的同學(xué)在實(shí)現(xiàn)功能的時(shí)候隨意發(fā)揮了一下
效果大概值這樣子的:

下拉放大

UI看完后
“這個(gè)效果不錯(cuò)啊”
“要不你們Android也么做赊时?” 于是~~
作為一個(gè)有追求的程序員吨铸,決定也要實(shí)現(xiàn)一個(gè)這樣的效果(滿腦子都是草泥馬在奔騰)

思路

這樣的效果嘛~~
利用自定義的ViewGroup,通過對手勢的處理祖秒,應(yīng)該就能實(shí)現(xiàn)了吧诞吱?

主要應(yīng)該分兩部分:

  • 判斷手勢舟奠,如果為下拉操作,獲取下拉的距離來實(shí)現(xiàn)View的放大
  • 當(dāng)手松開的時(shí)候房维,重置View的高度

比較麻煩的應(yīng)該是在第一部分沼瘫,需要對事件的分發(fā)有一些理解。

關(guān)于事件分發(fā)

說到手勢的判斷咙俩,難免需要對事件分發(fā)進(jìn)行處理耿戚。

下拉部分
1、在onInterceptTouchEvent中對事件進(jìn)行處理阿趁,如果為下拉事件溅话,則將該事件攔截,交給onTouchEvent處理歌焦;
2飞几、在onTouchEvent中通過計(jì)算得到下拉的距離,然后動態(tài)改變Header的配置独撇,實(shí)現(xiàn)放大的效果屑墨。

重置部分
onTouchEventACTION_UP中重置Header,實(shí)現(xiàn)回彈

對事件分發(fā)不了解的纷铣,這邊有兩篇不錯(cuò)的文章
Android事件分發(fā)機(jī)制 詳解攻略卵史,您值得擁有
圖解 Android 事件分發(fā)機(jī)制

實(shí)現(xiàn)

知道思路以后,實(shí)現(xiàn)起來就比較簡單了

攔截事件

創(chuàng)建一個(gè)ViewGroup(這么命名為FlexibleLayout)繼承LinearLayout搜立。

onInterceptTouchEvent的處理

  • onInterceptTouchEvent中的DOWN事件中記錄觸摸位置
  • MOVE事件中判斷是否為下拉動作以躯,若為下拉事件則進(jìn)行攔截。
public class FlexibleLayout extends LinearLayout{

    /**
     * true:開始下拽
     */
    private boolean mIsBeingDragged;

    /**
     * 初始坐標(biāo)
     */
    private float mInitialY, mInitialX;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mInitialX = ev.getX();
                mInitialY = ev.getY();
                mIsBeingDragged = false;
                break;
            case MotionEvent.ACTION_MOVE:
                float diffY = ev.getY() - mInitialY;
                float diffX = ev.getX() - mInitialX;
                if (diffY > 0 && diffY / Math.abs(diffX) > 2) {
                    mIsBeingDragged = true;
                    return true;
                }
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }
}

先通過兩個(gè)條件判斷是否為下拉事件:

  • diffY > 0 : Y軸向下滑動
  • diffY / Math.abs(diffX) > 2: Y軸滑動的距離超過X軸的兩倍

然后通過mIsBeingDragged來標(biāo)記開始拖拽

onTouchEvent的處理

  • onTouchEvent中的MOVE事件中獲取Y軸移動的距離啄踊,動態(tài)改變頭部的大小
  • UPCANCEL事件中忧设,重置頭部
@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_MOVE:
            if (mIsBeingDragged) {
                //得到下拉的距離
                float diffY = ev.getY() - mInitialY;
                changeHeader((int) diffY);
                return true;
            }
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (mIsBeingDragged) {
                //重置頭部
                resetHeader();
                return true;
            }
            break;
    }
    return super.onTouchEvent(ev);
}

修改頭部大小

得到下拉的距離后,就可以來改變Header的大小颠通,實(shí)現(xiàn)放大效果了址晕。

放大、重置的部分大家可以自由發(fā)揮

這里利用Math.pow(offsetY, 0.8)得到實(shí)際需要增加的高度顿锰,通過計(jì)算得到對應(yīng)的寬度以及偏移(類似阻尼效果)谨垃。

/**
 * 改變頭部大小
 * @param offsetY
 */
private void changeHeader(int offsetY) {
    int pullOffset = (int) Math.pow(offsetY, 0.8);
    int newHeight = pullOffset + mHeaderHeight;
    int newWidth = (int) ((((float) newHeight / mHeaderHeight)) * mHeaderWidth);
    mHeaderView.getLayoutParams().height = newHeight;
    mHeaderView.getLayoutParams().width = newWidth;
    int margin = (newWidth - mHeaderWidth) / 2;
    mHeaderView.setTranslationX(-margin);
    mHeaderView.requestLayout();
}

重置頭部

直接將寬高以及偏移設(shè)置成原來的參數(shù)即可。
(如果覺得這樣重置過程不夠絲滑硼控,可以通過動畫來完成一個(gè)流暢的重置效果刘陶,這里就不演示了)

/**
 * 重置頭部
 */
private void resetHeader() {
    mHeaderView.getLayoutParams().height = mHeaderHeight;
    mHeaderView.getLayoutParams().width = mHeaderWidth;
    mHeaderView.setTranslationX(0);
    mHeaderView.requestLayout();
}

到這里,一個(gè)簡易拉下放大的效果就做完了牢撼。試試效果

使用

直接在需要下拉放大的布局外面套上FlexibleLayout即可匙隔,例如ScrollView

<com.gavin.view.flexible.FlexibleLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ScrollView
        ... >
        <LinearLayout
            ... >
            <ImageView
                android:id="@+id/iv_header"
                ... />
        </LinearLayout>
    </ScrollView>
</com.gavin.view.flexible.FlexibleLayout>

效果

ScrollVIew:


scrollview.gif

RecyclerView:


recyclerview.gif

CoordinatorLayout:


coordinator.gif

大功告成!@四牡直!
當(dāng)然里面還有一些細(xì)節(jié)的處理,比如下拉的條件纳决、回彈的動畫碰逸、最大高度等,具體內(nèi)容的可以在源碼中看到阔加。

完善

完成下拉放大后饵史,貌似把一個(gè)很重要的功能遺忘了下拉刷新 ?胜榔?
光顧這下拉放大胳喷,刷新怎么辦?【黑人問號】

這個(gè)功能留著下周實(shí)現(xiàn)吧夭织,我的7小時(shí)睡眠已遙遙無期~~

雖然沒有直接實(shí)現(xiàn)下拉刷新的功能吭露,不過源碼中已經(jīng)暴露了一個(gè)下拉的監(jiān)聽,你也可以通過這個(gè)監(jiān)聽實(shí)現(xiàn)下拉刷新的操作

public interface OnPullListener {
    /**
     * 下拉
     * @param offset
     */
    void onPull(int offset);

    /**
     * 松開
     */
    void onRelease();
}

到這里就結(jié)束了

下拉刷新(2018-6-24補(bǔ)充)

(來還上周欠下的債~~)

和下拉放大類似尊惰,通過希手指下滑的監(jiān)聽讲竿,利用ViewtranslationYrotation實(shí)現(xiàn)移動和旋轉(zhuǎn)。
具體的實(shí)現(xiàn)過程這里就不貼出來了弄屡,直接看效果吧

有興趣的可以直接去Github上看源碼以及用法题禀。

源碼

Github

參考

PullZoomView
Android事件分發(fā)機(jī)制 詳解攻略,您值得擁有

以上有錯(cuò)誤之處膀捷,感謝指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迈嘹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子全庸,更是在濱河造成了極大的恐慌秀仲,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壶笼,死亡現(xiàn)場離奇詭異啄育,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拌消,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門挑豌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人墩崩,你說我怎么就攤上這事氓英。” “怎么了鹦筹?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵铝阐,是天一觀的道長。 經(jīng)常有香客問我铐拐,道長徘键,這世上最難降的妖魔是什么练对? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮吹害,結(jié)果婚禮上螟凭,老公的妹妹穿的比我還像新娘。我一直安慰自己它呀,他們只是感情好螺男,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纵穿,像睡著了一般下隧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谓媒,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天淆院,我揣著相機(jī)與錄音,去河邊找鬼句惯。 笑死迫筑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宗弯。 我是一名探鬼主播脯燃,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蒙保!你這毒婦竟也來了辕棚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤邓厕,失蹤者是張志新(化名)和其女友劉穎逝嚎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體详恼,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡补君,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昧互。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挽铁。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖敞掘,靈堂內(nèi)的尸體忽然破棺而出叽掘,到底是詐尸還是另有隱情,我是刑警寧澤玖雁,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布更扁,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏浓镜。R本人自食惡果不足惜溃列,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望膛薛。 院中可真熱鬧听隐,春花似錦、人聲如沸相叁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽增淹。三九已至,卻和暖如春乌企,著一層夾襖步出監(jiān)牢的瞬間虑润,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工加酵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拳喻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓猪腕,卻偏偏與公主長得像冗澈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子陋葡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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