編輯:關於Android編程
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能有所幫助。
Android開發必備:秒殺真機超快模擬器Genymotion介紹
第一,這貨速度太快,第二,模仿真機環境,第三,秒殺任何Android模擬器包括真機,不多說上圖,我忒忙! 官網:http://www.genymotion.com/鏡像圖
屬於自己的Android對話框(Dialog)自定義集合
Activities提供了一種方便管理的創建、保存、回復的對話框機制,例如 onCreateDialog(int), onPrepareDialog(int, Dialo
紅米note4什麼時候上市?紅米Note4真機疑曝光
前兩天,一張小米的宣傳海報在網上曝光,海報中是小米剛簽下的紅米代言人之一劉昊然,而亮點在於他手中的手機,這部手機采用了雙攝像頭設計,應該是一部還未發布的紅米
Android中:Activity、Content Provider、Broadcast和AIDLService4種跨歷程通訊的方式
由於android系統中應用程序之間不能共享內存。因此,在不同應用程序之間交互數據(跨進程通訊)就稍微麻煩一些。在android SDK中提供了4種用於跨進程通訊的方式。