1、效果圖如下:

這效果用戶體驗還是很酷炫,今天我們就來講解如何實現這個效果。
2、分析
為了方便理解,作圖分析

如圖所示,整個頁面分為四個部分:
1、懸浮內容,floatView
2、頂部內容,headView
3、中間內容,與懸浮內容相同,middleView
4、商品詳情展示頁面,detailView
因為頁面內容高度會超出屏幕,所以用Scrollview實現滾動,懸浮view與scrollview同級,都在一個幀布局或者相對布局中。
當y方向的滾動距離小于中間的內容middleView到頂部的距離時,middleView理所當然的會隨這頁面向上滑動而消失,我們顯示懸浮view,從而實現middleView一直卡在頂部的效果。
當y方向滾動距離大于中間的內容middleView容到頂部的距離時,懸浮view隱藏即可。
通過分析,我們發現只要知道scrollview的滾動距離和middleView到頂部的高度即可。至此將復雜的交互特效變成了倆個簡單的api。
3、第一種方法實現
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()中直接通過view的getTop()方法獲取到view的高度會返回0,這是因為此時view還沒有繪制到界面,所以我們采用上面的方法給view設置監聽獲取,由于可能發生多次繪制,所以最后記得移除監聽事件。
以下代碼同樣可以獲取:
tv_title.post(new Runnable() { @Override public void run() { mTitleTopAndHeight = tv_title.getTop(); } });利用post方法將操作放到隊列中,等系統布局完成后執行隊列中的事件,同樣可以獲取到正確的view的top值。
3.2 獲取垂直方向滾動距離
在Scrollview的父類View中有個內容變化的方法onScrollChanged(),雖然該方法是protect的外部不可調用,但是在內部,當scrollview滾動時就會執行該方法,所以我們自定義一個MyScrollView在onScrollChanged()通過回調將滾動的距離傳遞給外部。
自定義scrollview完整代碼如下:
public class MyScrollView extends ScrollView{ private OnScrollListener mOnScrollListener; /** * 是否用戶手指觸摸滑動 */ 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 { /** * 用戶手指拖動滾動 */ int SCROLL_STATE_TOUCH_SCROLL = 0x0; /** * 慣性滑行滾動 */ int SCROLL_STATE_FLING = 0x1; /** * 滾動時的回調 * * @param scrollY Y方向滾動的距離 * @param scroll_state 當前滾動狀態:自由滾動或者手勢拖動滾動 */ void onScroll(int scrollY, int scroll_state); }}3.3 使用
在acitivity中給scrollview設置自定義滾動監聽事件即可
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); } } });這樣,通過垂直方法的滾動值來控制floatView的顯示隱藏,
tv_float.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mScrollView.onTouchEvent(event); return false; } });給懸浮view設置觸摸監聽,將用戶手勢傳遞給scrollView,這樣用戶滑動懸浮view時,內容區域也可以跟隨滾動。
下面是布局代碼
<?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="標題view"/> <TextView android:layout_width="match_parent" android:layout_height="600dp" android:background="#a2bb" android:gravity="center" android:text="詳情頁面"/> </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="標題view" android:visibility="invisible"/></RelativeLayout>
4、第二種方式
本方法與第一種方式的區別就是獲取滾動位置的方法不同,該方法更簡單一些:
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); } } });可能有讀者要問,既然有這種簡單的方法直接設置監聽,為什么還介紹第一種方法。細心的你可能已經發現,在第一種方法中,我在自定義的監聽事件中,還回調了代表當前回調狀態的參數statue,因為很多app,在用戶手動拖動滾動跟慣性滾動的處理是不能的。比如淘寶商品詳情頁面,當達到邊界值中間view的top值時,只有用戶手動拖動一段距離后才會拉出底部的詳情類容,而慣性滑動的話只會停在那里。
5、總結
以上就是關于安卓實現按鈕隨著上下滾動而懸浮頂在固定位置的方法,希望本文的內容對大家開發Android能有所幫助。
新聞熱點
疑難解答