Android自定义弹性ScrollView

Android自定义弹性ScrollView

总结了下最近写的弹性ScrollView,如下代码主要是通过触摸事件加动态更改布局实现的弹性ScrollView,具体分析都在注解中!

package ljh.android.view;

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

/**
 * 弹性ScrollView 实现下拉弹回和上拉弹回
 *
 * @author Ljh
 * 2015年8月26日
 */

public class ReboundScrollView extends ScrollView {
	// 保存ScrollView中子控件
	private View contentView = null;
	// 用来保存唯一子控件的布局信息
	private Rect contentViewRect = new Rect();
	// 移动开始时候的Y坐标
	private float startY;
	// 线性阻尼 缓冲过量移动的移动速度
	private static float MOVE_FACTOR = 0.5f;
	//过度位移恢复的动画持续时间
	private static long DURATION_MILLIS = 280;

	public ReboundScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

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

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

	/**
	 * 在布局完成后得到ScrollView的唯一子View,并存在contentView中
	 */
	@Override
	protected void onFinishInflate() {
		if (getChildCount() > 0) {
			contentView = getChildAt(0);
		}
	}

	/**
	 * 在事件分发其中处理触摸事件
	 * 根据android中事件分发的机制判断,个人觉得把事件处理逻辑写在分发器中比写在onTouchEvent中好些,
	 * 因为在其子View没有接收到该触摸事件之前自己就处理了触摸事件。
	 */
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {

		if (contentView != null)
			switch (ev.getAction()) {
			case MotionEvent.ACTION_DOWN:
				startY = ev.getY();
				break;
			case MotionEvent.ACTION_UP:
				if (isNeedAnimation()) {
					playAnimation();
				}
				break;
			case MotionEvent.ACTION_MOVE:
				float nowY = ev.getY();
				int detailY = (int) (nowY - startY);
				if (isNeedMove(detailY)) {
					// 超出屏幕后滚动的View移动的距离为滑动位移的MOVE_FACTOR倍
					detailY = (int) (detailY * MOVE_FACTOR);
					//重新布局子View,并且只修改顶部与底部的位置
					contentView.layout(contentViewRect.left, contentViewRect.top + detailY, contentViewRect.right,
							contentViewRect.bottom + detailY);
				}
				break;
			default:
				break;
			}

		return super.dispatchTouchEvent(ev);
	}

	/**
	 * 在布局都完成后contentView的布局也就确定了
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		//在未超出移动前contentView的布局没有发生变化 即全局中contentView的布局不变
		if(contentView != null){
			contentViewRect.set(contentView.getLeft(), contentView.getTop(), contentView.getRight(),
					contentView.getBottom());
			}
	}

	/**
	 * 判断是否需要超出屏幕移动
	 *
	 * 通过三个量来判断是否需要移动及如何移动,这三个量分别为scrollY、
	 * contentViewHeight和scrollViewHeight外加辅助detailY手指移动的位移。分三种情况:
	 *
	 * 其中两种均为contentViewHeight>scrollViewHeight:
	 * 1、当contentView的顶部处于ScrollView顶部且向下滑动手指时候需要超出屏幕移动条件为:
	 * scrollY == 0 && detailY > 0, 如图:
	 * |-----scrollViewHeight-----|
	 * |----------contentViewHeight--------|
	 *  -----detailY---->
	 *
	 * 2、当contentView的底部处于ScrollView底部且向上滑动手指时候需要超出屏幕移动条件为:
	 * scrollY + scrollViewHeight >= contentViewHeight && detailY < 0, 如图:
	 * |--scrollY--|
	 *             |-----scrollViewHeight-----|
	 * |-----------contentViewHeight----------|
	 *                       <-----detailY----
	 *
	 * 另外一种情况是contentViewHeight<=scrollViewHeight上下滑动都需要做超出屏幕移动
	 * 3、当contentView的本身处于ScrollView内部时候无论向上或向下滑动手指时候都需要超出屏幕移动条件为:
	 * contentViewHeight <= scrollViewHeight,如图:
	 * |-----scrollViewHeight-----|
	 * |---contentViewHeight---|
	 *  <-----detailY---->
	 *
	 * @param detailY
	 *            手指移动的位移(向下或向右滑动为正方向)
	 * @return 是否需要移动
	 */
	private boolean isNeedMove(int detailY) {
		int scrollY = getScrollY();
		int contentViewHeight = contentView.getHeight();
		int scrollViewHeight = getHeight();

		return (scrollY == 0 && detailY > 0)|| (scrollY + scrollViewHeight >= contentViewHeight && detailY < 0)
				|| (contentViewHeight <= scrollViewHeight);
	}

	/**
	 * 播放contentView复位的动画并将contentView复位
	 * 动画可以自定义
	 * 动画执行时间随拉伸的距离增加而减少
	 */
	private void playAnimation() {
		int contentViewTop = contentView.getTop();
		int scrollViewHeight = this.getHeight();
		float factor = 1-Math.abs(contentViewTop - contentViewRect.top)/(scrollViewHeight*1.0f);
		TranslateAnimation ta = new TranslateAnimation(0,0,contentViewTop,contentViewRect.top);
		ta.setDuration((long) (DURATION_MILLIS*factor));
		contentView.startAnimation(ta);
		contentView.layout(contentViewRect.left, contentViewRect.top
				,contentViewRect.right,contentViewRect.bottom);
	}

	/**
	 * 判断是否需要动画效果
	 * @return
	 */
	private boolean isNeedAnimation() {
		return contentView.getTop() != contentViewRect.top;
	}

}

该实现方式中存在的问题或者是有待优化的问题,当ReboundScrollView处在最顶端或最低端拖动实现过量位移中不松开手指再反向减小偏移量时,滚动条会滚动!如果还有其他问题可以留言看到了一定回复!小伙伴有更好的弹性ScrollView的话可以分享给我!邮箱[email protected] 谢谢啦。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-01 07:56:50

Android自定义弹性ScrollView的相关文章

Android自定义之ScrollView下拉刷新

公司项目,需要用到ScrollView的下拉刷新,一开始使用的时候PullToRefresh三方库的下拉刷新,我比较纠结第三档库,很强大,但是,公司项目的需求,PullToRefresh就不能做到了,改来改去的还是自己写一个下拉刷新比较靠谱,很多东西能够自己去控制.效果图就不上传了.直接解释关键代码. ScrollView的下拉刷新比ListView的好做多了. 因为ScroTo的性质,ScrollView的下拉刷新,需要在外部添加一个父布局,通过父布局来控制触摸手势时候下传,什么时候下拉. 我

android 弹性ScrollView(已优化)

想要的效果 最近项目中想实现一个效果,效果如下: 网上demo展示 就是上滑或者下滑,能实现弹性效果,刚开始在网上找了好几个demo,代码大致如下: public class BounceScrollView extends ScrollView { private View inner;// 孩子View private float y;// 点击时y坐标 private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.) private

Android自定义ScrollView实现一键置顶功能

效果图如下: (ps:动态图有太大了,上传不了,就给大家口述一下要实现的功能吧) 要实现的功能:当ScrollView向上滑动超过一定距离后,就渐变的出现一个置顶的按钮,当滑动距离小于我们指定的距离时,按钮又消失. 实现原理:就是监听View的onScrollChanged()方法(回调方法),获取到ScrolView滑动的距离,如果大于我们的距离,则出现置顶按钮,否则,直接隐藏,且当按钮出现点击事件,让整个ScrollView滑动到(0,0)位置即可,不废话,直接上代码 自定义的ScrollV

android 有弹性的ScrollView 简单实现,与处理ScrollView和ListView,GridView之间的冲突

处理ScrollView和ListView,GridView之间的冲突, 最好的办法就是继承这两个类,重写他们的onMeasure方法即可: ListView: import android.widget.ListView; /** * ScrollView中嵌入ListView,让ListView全显示出来 * @author John * */ public class MyListView extends ListView{ public MyListView(android.conten

Android 自定义ScrollView ListView 体验各种纵向滑动的需求

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38950509,本文出自[张鸿洋的博客] 1.概述 群里的一个哥们有个需求是这样的:问题:主要功能就是:1.循环的一个滑动:2.每次滑动结束,保持每个Item的完整.然后我当时给他写了个Demo,所有代码都在Activity里面,后期看来其太恶心了,修改也不方便:貌似那哥们还因为那代码修改到12点,大大的赞一下这哥们的毅力,也深表歉意,今天特意把代码抽取成自定义的ScrollVi

android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变

首先要知道  自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置[注此处是伸缩隐藏,不是同比例放大] inner.layout(normal.left, (int) (normal.top + inner_move_H), normal.right, (int) (normal.bottom + inner_move_H)); 关于“自定义scrollview 仿

弹性ScrollView,和下啦刷新的效果类似 实现下拉弹回和上拉弹回

今天做了一个弹性ScrollView,和下啦刷新的效果类似,我想这个很多需求都用的这种效果 其实这是一个自定义的scrollView,上代码,这是我写在一个公共的组件包里的 package com.pb.soft.widget; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import

Android 自定义Adapter 但listview 只显示第一条数据

楼主让这个问题郁闷了一晚上.....在logcat里明明显示adapter的getview方法里的list大于一条数据 ,但posotion却一直是0.....运行后也只显示list[0]里面的数据....最后的最后原来错误出在布局文件上 我以前的是这样的; <ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content" > <!-- listv

弹性ScrollView,和下啦刷新的效果相似 实现下拉弹回和上拉弹回

今天做了一个弹性ScrollView,和下啦刷新的效果类似,我想这个非常多需求都用的这样的效果 事实上这是一个自己定义的scrollView,上代码.这是我写在一个公共的组件包里的 package com.pb.soft.widget; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; im