ScrollView阻尼效果

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.scrollviewdemo.MainActivity" >

    <com.example.scrollviewdemo.CustomScrollView

        android:id="@+id/scrollview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>
             <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>
             <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>
             <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>
             <TextView
                android:layout_width="fill_parent"
                android:layout_height="100dp"
                android:text="AAA" >
            </TextView>
        </LinearLayout>
    </com.example.scrollviewdemo.CustomScrollView
>

</LinearLayout>

MainActivity

package com.example.scrollviewdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ScrollView;

public class MainActivity extends Activity {
	ScrollView scrollView;
	private static final int TOUCH_EVENT_ID = 1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		scrollView = (ScrollView) findViewById(R.id.scrollview);

		
	}
}
方式一

ElasticScrollView

package com.example.scrollviewdemo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.TranslateAnimation;

public class ElasticScrollView extends ScrollView {
	//scrollView下的控件
	private View inner;

	private float y;

	//保存状态的矩形框
	private Rect normal = new Rect();

	//是否要计算
	private boolean isCount = false;

	@SuppressLint("NewApi")
	public ElasticScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	//载入完布局文件之后调用
	@Override
	protected void onFinishInflate() {
		if (getChildCount() > 0) {
			//获取控件
			inner = getChildAt(0);
		}
	}

	@SuppressLint("ClickableViewAccessibility")
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (inner != null) {
			commOnTouchEvent(ev);
		}
		return super.onTouchEvent(ev);
	}

	//处理触摸事件
	public void commOnTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			break;
		case MotionEvent.ACTION_UP:
			//是不是须要动画
			if (isNeedAnimation()) {
				animation();
				isCount = false;
			}
			break;
		case MotionEvent.ACTION_MOVE:
			final float preY = y;
			float nowY = ev.getY();
			int deltaY = (int) (preY - nowY);
			if (!isCount) {
				deltaY = 0;
			}

			y = nowY;
			if (isNeedMove()) {
				if (normal.isEmpty()) {
					normal.set(inner.getLeft(), inner.getTop(),inner.getRight(), inner.getBottom());
				}
				inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2,inner.getRight(), inner.getBottom() - deltaY / 2);
			}
			isCount = true;
			break;

		default:
			break;
		}
	}

	public void animation() {
		TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),normal.top);
		ta.setDuration(200);
		inner.startAnimation(ta);
		inner.layout(normal.left, normal.top, normal.right, normal.bottom);
		normal.setEmpty();

	}

	// return left >= right || top >= bottom;
	public boolean isNeedAnimation() {
		return !normal.isEmpty();
	}

	public boolean isNeedMove() {
		int offset = inner.getMeasuredHeight() - getHeight();
		int scrollY = getScrollY();
		if (scrollY == 0 || scrollY == offset) {
			return true;
		}
		return false;
	}
}


——————————————————————————方式二——————————————————————————

CustomScrollView

package com.example.scrollviewdemo;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.ScrollView;

public class CustomScrollView extends ScrollView {

	// y方向上当前触摸点的前一次记录位置
		private int previousY = 0;
		// y方向上的触摸点的起始记录位置
		private int startY = 0;
		// y方向上的触摸点当前记录位置
		private int currentY = 0;
		// y方向上两次移动间移动的相对距离
		private int deltaY = 0;

		// 第一个子视图
		private View childView;

		// 用于记录childView的初始位置
		private Rect topRect = new Rect();

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

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

		public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
			super(context, attrs, defStyle);
			;
		}

		@Override
		protected void onFinishInflate() {
			if (getChildCount() > 0) {
				childView = getChildAt(0);
			}
		}

		@Override
		public boolean dispatchTouchEvent(MotionEvent event) {
			if (null == childView) {
				return super.dispatchTouchEvent(event);
			}

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				startY = (int) event.getY();
				previousY = startY;
				break;
			case MotionEvent.ACTION_MOVE:
				currentY = (int) event.getY();
				deltaY = previousY - currentY;
				previousY = currentY;

				if (0 == getScrollY()
						|| childView.getMeasuredHeight() - getHeight() <= getScrollY()) {
					// 记录childView的初始位置
					if (topRect.isEmpty()) {
						topRect.set(childView.getLeft(), childView.getTop(),
								childView.getRight(), childView.getBottom());
					}

					// 更新childView的位置
					childView.layout(childView.getLeft(), childView.getTop()
							- deltaY / 3, childView.getRight(),
							childView.getBottom() - deltaY / 3);
				}
				break;
			case MotionEvent.ACTION_UP:
				if (!topRect.isEmpty()) {
					upDownMoveAnimation();
					// 子控件回到初始位置
					childView.layout(topRect.left, topRect.top, topRect.right,
							topRect.bottom);
				}

				startY = 0;
				currentY = 0;
				topRect.setEmpty();
				break;
			default:
				break;
			}

			return super.dispatchTouchEvent(event);
		}

		// 初始化上下回弹的动画效果
		private void upDownMoveAnimation() {
			TranslateAnimation animation = new TranslateAnimation(0.0f, 0.0f,
					childView.getTop(), topRect.top);
			animation.setDuration(200);
			animation.setInterpolator(new AccelerateInterpolator());
			childView.setAnimation(animation);
		}
}


原文地址:https://www.cnblogs.com/brucemengbm/p/7191278.html