1. 程式人生 > >購買欄懸浮效果實現

購買欄懸浮效果實現

在各電商APP的商品詳情頁中,我們經常會看到這種效果。

預設情況下,購買欄顯示在商品圖片下方:


當頁面向上滑動,購買欄滑動到螢幕頂部時,會一直固定在螢幕頂部:

今天我們來實現這種顯示效果。

實現思路:
首先,頁面能夠滾動,需要ScrollView的支援。在ScrollView內部,包含一個垂直方向的LinearLayout,商品圖片和購買欄呈垂直線性排列,這些都比較容易想到。難點在於如何把頁面中的購買欄固定住,而頁面還可以繼續滾動。那麼我們就變換一下思維,如果從一開始,在螢幕的頂部就一直存在著一個一模一樣的購買欄,只不過是隱藏狀態,當商品圖片下邊的購買欄滑動到螢幕頂部時,我們將螢幕頂部已有的購買欄顯示出來就好啦。

思路圖:


基於上述思路,我們就有了下面的佈局程式碼:

好了,下面開始用程式碼實現邏輯了。
我們首先要獲取到商品圖片區域的高度,然後監聽ScrollView在垂直方向的滾動距離,當滾動距離大於商品圖片的高度時,就將螢幕頂部的購買欄顯示出來,否則將其隱藏。

監聽滾動,很容易會想到setOnScrollChangeListener(OnScrollChangeListener l)方法。不過,很遺憾的是,ScrollView只有在api level 23以上,才提供了該方法。那麼,在低版本中,我們如何監聽ScrollView的滾動呢?

我們發現,在ScrollView中,有如下方法。
/**
  * This is called in response to an internal scroll in this view (i.e., the
  * view scrolled its own contents). This is typically as a result of
  * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been
  * called.
  *
  * @param l Current horizontal scroll origin.
  * @param t Current vertical scroll origin.
  * @param oldl Previous horizontal scroll origin.
  * @param oldt Previous vertical scroll origin.
  */
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  // ...
}
而且,該方法是protected的,那麼我們可以自定義一個View,繼承自ScrollView,然後重寫onScrollChanged()方法,將引數t(垂直方向的滾動距離)回調出去為我們所用。

實現如下。
package net.csdn.blog.ruancoder;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;

public class ScrollChangedView extends ScrollView {
    private OnScrollChangedListener mListener;

    public void setOnScrollChangedListener(OnScrollChangedListener listener) {
        this.mListener = listener;
    }

    public ScrollChangedView(Context context) {
        super(context);
    }

    public ScrollChangedView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrollChangedView(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 (mListener != null) {
            // 將ScrollView垂直方向滾動的距離回調出去
            mListener.onScrollChanged(t);
        }
    }

    public interface OnScrollChangedListener {
        void onScrollChanged(int scrollY);
    }
}

然後在Activity中,監聽ScrollChangedView.OnScrollChangedListener,根據scrollY的大小來控制頂部購買欄的顯示或隱藏,就可以實現上述效果。
package net.csdn.blog.ruancoder;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewTreeObserver;

public class MainActivity extends Activity implements ScrollChangedView.OnScrollChangedListener {
    private View mFixedBuyBar;// 頂部固定的購買欄
    private int mTopViewHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final View topView = findViewById(R.id.top_view);
        mFixedBuyBar = findViewById(R.id.fixed_buy_button_bar);
        mFixedBuyBar.setVisibility(View.GONE);

        final ScrollChangedView scrollView = (ScrollChangedView) findViewById(R.id.scrollview);
        scrollView.setOnScrollChangedListener(this);

        scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 獲取頂部檢視的高度
                mTopViewHeight = topView.getHeight();
                scrollView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });
    }

    @Override
    public void onScrollChanged(int scrollY) {
        if (scrollY > mTopViewHeight) {// 滾動超出頂部檢視的高度,此時顯示頂部固定的購買欄
            mFixedBuyBar.setVisibility(View.VISIBLE);
        } else {// 否則,隱藏頂部固定的購買欄
            mFixedBuyBar.setVisibility(View.GONE);
        }
    }
}

最後附上完整工程程式碼下載連結:
http://download.csdn.net/detail/ruancoder/9594054