這裡寫自定義目錄标題
- Android 仿支付寶首頁下拉重新整理
-
- 圖檔示範
- 源碼
Android 仿支付寶首頁下拉重新整理
頁面上的布局是從支付寶首頁上截取下來的,這裡定義(掃一掃到卡包)的布局為藍布局,(轉載到更多)的布局為白布局。
市面上實作支付寶首頁頭部效果的Demo,我能百度到的案例,基本上使用CoordinatorLayout布局方案。
這些方案嵌套下拉重新整理後體驗不是很友好,是以自己撸一個。
圖檔示範
連結: link.
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmL2IzM0UzN0MTM1ITOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
源碼
源碼位址: https://gitee.com/sophuron/copy_alipay_home.
下載下傳體驗: https://www.pgyer.com/EXOu.
最好直接打開源碼運作一下吧,下面都是廢話。
布局結構
布局整體都是靠NestedScrollView的滾動來實作支付寶首頁效果的。
ll_offset布局頂部預留280dp為了避免布局遮蓋并且隐藏下拉重新整理提示布局。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".AliPayHomeActivity"
android:background="#f4f4f4">
<android.support.v4.widget.NestedScrollView
android:id="@+id/nsv_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll_offset"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="280dp"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tv_refresh"
android:layout_width="match_parent"
android:layout_height="60dp"
android:paddingTop="10dp"
android:gravity="center"
android:text="下拉重新整理"/>
<TextView
android:layout_width="match_parent"
android:layout_height="1000dp"
android:gravity="center"
android:text="内容"
android:background="#fff"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@+id/ll_offset"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.constraint.ConstraintLayout
android:id="@+id/cl_parallax"
android:layout_width="match_parent"
android:layout_height="140dp"
android:text="Hello World!"
android:gravity="center"
android:background="#3e7fcb"
android:orientation="horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" >
<LinearLayout
android:id="@+id/ll_category1"
android:layout_width="match_parent"
android:layout_height="90dp"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/ic_category1"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
<LinearLayout
android:id="@+id/ll_category2"
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="horizontal"
android:background="#fff"
app:layout_constraintTop_toBottomOf="@+id/cl_parallax">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/ic_category2"/>
</LinearLayout>
<View
android:id="@+id/view_toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#3e7fcb"
android:alpha="0"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="這個是仿支付寶首頁"
android:textColor="#fff"
app:layout_constraintTop_toTopOf="@+id/view_toolbar"
app:layout_constraintLeft_toLeftOf="@+id/view_toolbar"
app:layout_constraintRight_toRightOf="@+id/view_toolbar"
app:layout_constraintBottom_toBottomOf="@+id/view_toolbar"/>
</android.support.constraint.ConstraintLayout>
根據 nsv_scroll 的滾動事件來移動cl_parallax和ll_category2的位置,也就是藍布局和白布局。
nsv_scroll.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
@Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if (lastScrollY < hScrollParallax) {
scrollY = Math.min(hScrollParallax, scrollY);
m_scroll_y = scrollY > hScrollParallax ? hScrollParallax : scrollY;
cl_parallax.setTranslationY((m_offset - m_scroll_y) / 2);
ll_category2.setTranslationY(m_offset - m_scroll_y);
}
if(scrollY <= hCategory1) {
float alpha = 1 - (float) scrollY / hCategory1;
ll_category1.setAlpha(alpha);
}
if(scrollY >= hCategory1) {
view_toolbar.setAlpha(1.0f);
}else {
view_toolbar.setAlpha(0);
}
lastScrollY = scrollY;
}
});
根據 nsv_scroll 的觸摸事件來實作一些效果。
當 nsv_scroll 已經滑動到頂部時,判斷使用者手勢是否繼續向下拖拽。
使用者繼續向下拖拽則将 ll_offset 布局整個向下偏移。
使用者手指擡起後判斷拖拽距離是否大于重新整理距離。
大于則執行重新整理方法。
nsv_scroll.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(refreshState == refreshing) {
return true;
}
m_event = event;
//繼承了Activity的onTouchEvent方法,直接監聽點選事件
if(event.getAction() == MotionEvent.ACTION_DOWN) {
//當手指按下的時候記錄手指點選的坐标
y1 = event.getY();
y3 = event.getY();
setRefreshTips(R.string.pull_to_refresh);// 展示下拉提示内容
}
if(event.getAction() == MotionEvent.ACTION_UP) {
y2 = event.getY();
//當手指離開的時候根據refreshState的狀态判斷是否需要執行重新整理方法
if(refreshState == toRefresh) {
setRefreshTips(R.string.is_refreshing);
refreshState = refreshing;
ll_offset.setTranslationY(position + refreshableDistance);
new Handler().postDelayed(runnable, 3000);
}else {
// 根據拖拽距離判斷是否需要執行收縮方法
if(ll_offset.getTranslationY() > position) {
endPosition = ll_offset.getTranslationY();
timer.start();
}
}
quickScrollDistance = y2 - y3;
}
if(event.getAction() == MotionEvent.ACTION_MOVE) {
//當手指離開的時候
y2 = event.getY();
// 當nsv_scroll移動到頂部,并且y2 - y1 > 0(表示使用者正在下拉)
if(y2 - y1 > 0 && nsv_scroll.getScrollY() == 0) {
// 下拉距離大于可重新整理距離
if((int)((y2 - y1) / pullDamp) > refreshableDistance) {
refreshState = toRefresh;
setRefreshTips(R.string.loosen_refresh);
}else {
refreshState = refreshNoTrigger;
setRefreshTips(R.string.pull_to_refresh);
}
float py = y2 - y1;
ll_offset.setTranslationY(py / pullDamp);// 移動布局
return true;
}
if(y1 - y2 >0) {
y3 = Math.min(y3, y2);
}
}
return false;
}
});
寫完收工,代碼會慢慢完善。