android:電商app商品詳情頁(yè)按鈕浮動(dòng)特效

1发绢、前言

很多電商類app的商品詳情頁(yè)(其他app也有類似效果好港,比如qq音樂(lè))都有這么一個(gè)效果:當(dāng)用戶向上滑動(dòng)頁(yè)面內(nèi)容超過(guò)一定距離后媒怯,中間的標(biāo)題欄會(huì)卡在頂部,往下拉回到固定高度后又會(huì)消失纵装。效果圖如下:


這里寫圖片描述

這效果用戶體驗(yàn)還是很酷炫征讲,今天我們就來(lái)講解如何實(shí)現(xiàn)這個(gè)效果。

2橡娄、分析

為了方便理解诗箍,作圖分析

這里寫圖片描述

如圖所示,整個(gè)頁(yè)面分為四個(gè)部分:

  • 懸浮內(nèi)容,floatView
  • 頂部?jī)?nèi)容,headView
  • 中間內(nèi)容,與懸浮內(nèi)容相同,middleView
  • 商品詳情展示頁(yè)面,detailView

因?yàn)轫?yè)面內(nèi)容高度會(huì)超出屏幕挽唉,所以用Scrollview實(shí)現(xiàn)滾動(dòng)滤祖,懸浮view與scrollview同級(jí)筷狼,都在一個(gè)幀布局或者相對(duì)布局中。

當(dāng)y方向的滾動(dòng)距離小于中間的內(nèi)容middleView到頂部的距離時(shí)匠童,middleView理所當(dāng)然的會(huì)隨這頁(yè)面向上滑動(dòng)而消失埂材,我們顯示懸浮view,從而實(shí)現(xiàn)middleView一直卡在頂部的效果俏让。

當(dāng)y方向滾動(dòng)距離大于中間的內(nèi)容middleView容到頂部的距離時(shí)楞遏,懸浮view隱藏即可茬暇。

通過(guò)分析首昔,我們發(fā)現(xiàn)只要知道scrollview的滾動(dòng)距離和middleView到頂部的高度即可。至此將復(fù)雜的交互特效變成了倆個(gè)簡(jiǎn)單的api糙俗。

3勒奇、第一種方法實(shí)現(xiàn)

3.1 獲取middleView的到父容器頂部的距離

 tv_title.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
        {
            @Override
            public void onGlobalLayout()
            {
                mTitleTopAndHeight = tv_title.getTop();

                tv_title.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });

在activity的oncreate()中直接通過(guò)view的getTop()方法獲取到view的高度會(huì)返回0,這是因?yàn)榇藭r(shí)view還沒(méi)有繪制到界面巧骚,所以我們采用上面的方法給view設(shè)置監(jiān)聽(tīng)獲取赊颠,由于可能發(fā)生多次繪制,所以最后記得移除監(jiān)聽(tīng)事件劈彪。

以下代碼同樣可以獲瓤⒈摹:

      tv_title.post(new Runnable()
        {
            @Override
            public void run()
            {
                mTitleTopAndHeight = tv_title.getTop();
            }
        });

利用post方法將操作放到隊(duì)列中,等系統(tǒng)布局完成后執(zhí)行隊(duì)列中的事件沧奴,同樣可以獲取到正確的view的top值痘括。

3.2 獲取垂直方向滾動(dòng)距離

在Scrollview的父類View中有個(gè)內(nèi)容變化的方法onScrollChanged(),雖然該方法是protect的外部不可調(diào)用,但是在內(nèi)部滔吠,當(dāng)scrollview滾動(dòng)時(shí)就會(huì)執(zhí)行該方法纲菌,所以我們自定義一個(gè)MyScrollViewonScrollChanged()通過(guò)回調(diào)將滾動(dòng)的距離傳遞給外部。

自定義scrollview完整代碼如下:

public class MyScrollView extends ScrollView
{
    private OnScrollListener mOnScrollListener;

    /**
     * 是否用戶手指觸摸滑動(dòng)
     */
    private boolean mIsTouch = false;

    public MyScrollView(Context context)
    {
        this(context, null);
    }

    public MyScrollView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt)
    {
        super.onScrollChanged(l, t, oldl, oldt);

        if (mOnScrollListener != null)
        {
            mOnScrollListener.onScroll(t, mIsTouch ? OnScrollListener.SCROLL_STATE_TOUCH_SCROLL : OnScrollListener.SCROLL_STATE_FLING);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        switch (ev.getAction())
        {
            case MotionEvent.ACTION_MOVE:
                mIsTouch = true;

                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsTouch = false;

                break;
        }

        return super.onTouchEvent(ev);
    }

    public void setOnScrollListener(OnScrollListener onScrollListener)
    {
        mOnScrollListener = onScrollListener;
    }

    public interface OnScrollListener
    {
        /**
         * 用戶手指拖動(dòng)滾動(dòng)
         */
        int SCROLL_STATE_TOUCH_SCROLL = 0x0;

        /**
         * 慣性滑行滾動(dòng)
         */
        int SCROLL_STATE_FLING = 0x1;

        /**
         * 滾動(dòng)時(shí)的回調(diào)
         *
         * @param scrollY      Y方向滾動(dòng)的距離
         * @param scroll_state 當(dāng)前滾動(dòng)狀態(tài):自由滾動(dòng)或者手勢(shì)拖動(dòng)滾動(dòng)
         */
        void onScroll(int scrollY, int scroll_state);
    }
}

3.3 使用

在acitivity中給scrollview設(shè)置自定義滾動(dòng)監(jiān)聽(tīng)事件即可


    mScrollView.setOnScrollListener(new MyScrollView.OnScrollListener()
        {
            @Override
            public void onScroll(int scrollY, int state)
            {
                Log.d("onScroll: ", scrollY + "" + "----------- state:" + state);

                if (scrollY <= mTitleTopAndHeight)
                {
                    tv_float.setVisibility(View.INVISIBLE);
                } else
                {
                    tv_float.setVisibility(View.VISIBLE);
                }
            }
        });

這樣疮绷,通過(guò)垂直方法的滾動(dòng)值來(lái)控制floatView的顯示隱藏翰舌,

        tv_float.setOnTouchListener(new View.OnTouchListener()
        {
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                mScrollView.onTouchEvent(event);
                return false;
            }
        });

給懸浮view設(shè)置觸摸監(jiān)聽(tīng),將用戶手勢(shì)傳遞給scrollView冬骚,這樣用戶滑動(dòng)懸浮view時(shí)椅贱,內(nèi)容區(qū)域也可以跟隨滾動(dòng)。

下面是布局代碼只冻,文章最后會(huì)附上demo下載地址:

<?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.example.qike.scrolltitle.MyScrollView
        android:id="@+id/sv_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="商品圖片"/>

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="#a3c"
                android:gravity="center"
                android:text="標(biāo)題view"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="600dp"
                android:background="#a2bb"
                android:gravity="center"
                android:text="詳情頁(yè)面"/>
        </LinearLayout>
    </com.example.qike.scrolltitle.MyScrollView>

    <TextView
        android:id="@+id/tv_float"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#a3c"
        android:gravity="center"
        android:text="標(biāo)題view"
        android:visibility="invisible"/>

</RelativeLayout>

4庇麦、第二種方式

本方法與第一種方式的區(qū)別就是獲取滾動(dòng)位置的方法不同,該方法更簡(jiǎn)單一些:


  mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener()
        {
            @Override
            public void onScrollChanged()
            {
                int scrollY = mScrollView.getScrollY();
                if (scrollY <= mTitleTopAndHeight)
                {
                    tv_float.setVisibility(View.INVISIBLE);
                } else
                {
                    tv_float.setVisibility(View.VISIBLE);
                }
            }
        });

可能有讀者要問(wèn)属愤,既然有這種簡(jiǎn)單的方法直接設(shè)置監(jiān)聽(tīng)女器,為什么還介紹第一種方法。細(xì)心的你可能已經(jīng)發(fā)現(xiàn)住诸,我在第一種方法自定義的監(jiān)聽(tīng)事件中驾胆,把表示當(dāng)前滾動(dòng)狀態(tài)的參數(shù)statue回調(diào)給了監(jiān)聽(tīng)方涣澡,因?yàn)楹芏郺pp在用戶手動(dòng)拖動(dòng)滾動(dòng)與慣性滾動(dòng)的處理是不同的。比如淘寶商品詳情頁(yè)面丧诺,當(dāng)達(dá)到邊界值中間view的top值時(shí)入桂,只有用戶手動(dòng)拖動(dòng)一段距離后才會(huì)拉出底部的詳情類容,而慣性滑動(dòng)的話只會(huì)停在那里驳阎。

5抗愁、結(jié)束

到此,關(guān)于如果實(shí)現(xiàn)按鈕隨著上下滾動(dòng)而懸浮頂在固定位置的方法就講完了呵晚。
下面是demo下載地址.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蜘腌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子饵隙,更是在濱河造成了極大的恐慌撮珠,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件金矛,死亡現(xiàn)場(chǎng)離奇詭異芯急,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驶俊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門娶耍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人饼酿,你說(shuō)我怎么就攤上這事榕酒。” “怎么了嗜湃?”我有些...
    開(kāi)封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵奈应,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我购披,道長(zhǎng)杖挣,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任刚陡,我火速辦了婚禮惩妇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筐乳。我一直安慰自己歌殃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布蝙云。 她就那樣靜靜地躺著氓皱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上波材,一...
    開(kāi)封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天股淡,我揣著相機(jī)與錄音,去河邊找鬼廷区。 笑死唯灵,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的隙轻。 我是一名探鬼主播埠帕,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼玖绿!你這毒婦竟也來(lái)了敛瓷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镰矿,失蹤者是張志新(化名)和其女友劉穎琐驴,沒(méi)想到半個(gè)月后俘种,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秤标,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年宙刘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苍姜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悬包,死狀恐怖衙猪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情布近,我是刑警寧澤垫释,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站撑瞧,受9級(jí)特大地震影響棵譬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜预伺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一订咸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酬诀,春花似錦脏嚷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春趾唱,著一層夾襖步出監(jiān)牢的瞬間屿岂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工鲸匿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爷怀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓带欢,卻偏偏與公主長(zhǎng)得像运授,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乔煞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,327評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)吁朦、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,124評(píng)論 4 61
  • 若我今日忘記進(jìn)行喜樂(lè)操練渡贾,我會(huì)不會(huì)覺(jué)得今日是快樂(lè)的逗宜?也許不會(huì)。晚上吃完飯后空骚,腰一直酸脹纺讲。從婆家把明天要首次去幼兒園...
    譚小哞Tanya閱讀 119評(píng)論 0 3
  • #雞肉韓式拌飯#我炒雞愛(ài)的半熟雞蛋還搭配愛(ài)心形,創(chuàng)意滿分囤屹!雖然色相令人一亮熬甚,味道卻相差懸殊了,韓式辣醬不足導(dǎo)...
    元?dú)菪佬?/span>閱讀 280評(píng)論 0 0
  • Matlab并行運(yùn)算過(guò)程: 1. Matlab叫做Client肋坚,里面是一個(gè)大任務(wù)total_task; 2. 把t...
    墨竹恒成立閱讀 1,092評(píng)論 0 0