1. 程式人生 > >Android仿IOS上拉/下拉彈性效果ScrollView

Android仿IOS上拉/下拉彈性效果ScrollView

效果圖如下:
這裡寫圖片描述

①實現原理:

Android自帶的ScrollView滑動到頂部和底部後,就不能繼續拖動了,因此要實現IOS的拉動彈性效果,可以自定義一個佈局,繼承ScrollView。

  1. 在最頂部時,可以向下拉動,並且彈回。
  2. 在最底部時,可以向上拉動,並且彈回。
  3. 不在最底部和最頂部時,就是預設的ScrollView的滑動效果。

如何判斷ScrollView處於最頂部和最底部呢?

// 最頂部時,ScrollView的縱向滑動座標值為0
getScrollY() == 0
// 最底部時,(ScrollView的子佈局的高度 <= ScrollView縱向滑動座標值 + ScrollView的高度)
contentView.getMeasuredHeight() <= getScrollY() + getHeight()

②具體程式碼如下:

/**
 * 仿IOS上拉下拉彈性效果ScrollView
 * @author yangmbin
 * created at 2016/12/4 16:48
 */
public class IOSScrollView extends ScrollView {

    // 上下文
    private Context context;

    // ScrollView子佈局
    private View contentView;

    // 手勢按下Y座標
    private float startY;

    // 手勢按下時,是否可以下拉/上拉標誌
    private
boolean isCanPullDown, isCanPullUp; // 儲存ScrollView子佈局的初始位置資訊 private int leftPosition, topPosition, rightPosition, bottomPosition; public IOSScrollView(Context context) { super(context); this.context = context; } public IOSScrollView(Context context, AttributeSet attrs) { super
(context, attrs); this.context = context; } /** * 獲取ScrollView的子佈局 */ @Override protected void onFinishInflate() { if (getChildCount() > 0) { contentView = getChildAt(0); } } /** * 獲取初始子佈局的位置資訊 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (contentView != null) { leftPosition = contentView.getLeft(); topPosition = contentView.getTop(); rightPosition = contentView.getRight(); bottomPosition = contentView.getBottom(); } } /** * 判斷是否在ScrollView頂部,在頂部時可以下拉 */ private boolean isScrollViewTop() { if (getScrollY() == 0) return true; return false; } /** * 判斷是否在ScrollView底部,在頂部時可以上拉 */ private boolean isScrollViewBottom() { if (contentView.getMeasuredHeight() <= getScrollY() + getHeight()) return true; return false; } /** * 觸控事件處理 */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (contentView == null) return super.dispatchTouchEvent(ev); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: startY = ev.getY(); isCanPullDown = isScrollViewTop(); isCanPullUp = isScrollViewBottom(); break; case MotionEvent.ACTION_UP: float endY = ev.getY(); // 手勢放開時,採用動畫形式返回原位置 if (endY > startY && isCanPullDown || endY < startY && isCanPullUp) { ObjectAnimator animator = ObjectAnimator.ofFloat(contentView, "translationY", contentView.getTop(), topPosition); animator.setDuration(500); animator.setInterpolator(new AccelerateInterpolator()); animator.start(); // 設定佈局到正常位置 contentView.layout(leftPosition, topPosition, rightPosition, bottomPosition); } break; case MotionEvent.ACTION_MOVE: // 如果不在ScrollView的最頂部或最底部(startY需要是在最頂部或最底部時按下的座標) if (!isCanPullUp && !isCanPullDown) { startY = ev.getY(); isCanPullDown = isScrollViewTop(); isCanPullUp = isScrollViewBottom(); break; } // 在最上部或最底部時,拉動移動佈局 // 1、下拉 2、上拉 3、佈局內容比ScrollView小,則既可以上拉,也可以下拉 if (isCanPullDown && ev.getY() > startY || isCanPullUp && ev.getY() < startY || isCanPullDown && isCanPullUp) { int deltaY = (int) (ev.getY() - startY); contentView.layout(leftPosition, topPosition + deltaY, rightPosition, bottomPosition + deltaY); } break; } return super.dispatchTouchEvent(ev); } }

XML中的使用方法:

<?xml version="1.0" encoding="utf-8"?>
<com.demo.IOSScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.demo.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="300dp"
            android:text="111111111"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="300dp"
            android:text="222222222"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="300dp"
            android:text="333333333"/>
    </LinearLayout>

</com.demo.IOSScrollView>