自已写的一个带反弹效果的ScrollView,供参考
package cn.bassy.library.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.OvershootInterpolator;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Scroller;
/ **
* 概述:滑动反弹组件
*
* 创建:2017-3-30
*
*
* @author Bassy Wain
*/
public class BounceScrollView extends LinearLayout {
private static final String TAG = "BounceScrollView";
private enum PullAction {
PullDown, PullUp, None
}
/ **
* 内容视图
*/
private ScrollView mContentLayout;
/ **
* 子View
*/
private View mChildView;
/ **
* 反弹效果
*/
private Scroller mScroller;
/ **
* 记录触摸按下位置
*/
private float mTouchDownY;
/ **
* 下拉偏移量与展示头部布局高度之间的比率,控制手势偏移与View偏移的比例
*/
private static final float mPullRatio = 2.5f;
/ **
* 当前操作类型
*/
private PullAction mPullAction = PullAction.None;
public BounceScrollView(Context context) {
super(context);
init(context, null);
}
public BounceScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public BounceScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
setClickable(true);//设置为可点击,否则无法滚动
mScroller = new Scroller(context, new OvershootInterpolator());//带弹性效果
mContentLayout = createContentLayout(context);
addView(mContentLayout);
}
private ScrollView createContentLayout(Context context) {
ScrollView sv = new ScrollView(context);
sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return sv;
}
@Override
public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
if (child == mContentLayout) {
//内容视图交给父类处理
super.addView(child, index, params);
} else {
//其它情况,交给ContentLayout处理
mContentLayout.addView(child, index, params);
mChildView = mContentLayout.getChildAt(0);
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
//记录第一个手指的按下位置
mTouchDownY = ev.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
//对上拉和下拉进行计算和移动
final float deltaY = mTouchDownY - ev.getY();
mPullAction = (deltaY < 0) ? (PullAction.PullDown) :
(deltaY > 0 ? PullAction.PullUp : PullAction.None);
if (canPull()) {
mScroller.abortAnimation();
scrollTo(getScrollX(), (int) (deltaY / mPullRatio));
if (mChildView != null) {
mChildView.clearFocus();//清空子View的ACTION_DOWN状态
}
} else {
mTouchDownY = ev.getY();
}
break;
}
case MotionEvent.ACTION_UP: {
//回弹
mPullAction = PullAction.None;
smoothScrollTo(getScrollX(), 0);
break;
}
default:
}
return super.dispatchTouchEvent(ev);
}
private boolean canPull() {
if (mChildView == null) {
//子视图为空
return true;
} else if (mPullAction == PullAction.PullDown && mContentLayout.getScrollY() <= 0) {
//ScrollView滚动位置在开始位置并且操作为下拉
return true;
} else if (mPullAction == PullAction.PullDown && getScrollY() > 0) {
//ScrollView先经过上拉拉出了一段距离(正数),再进行下拉操作,此时需要恢复位置
return true;
} else if (mPullAction == PullAction.PullUp &&
(mContentLayout.getHeight() >= mChildView.getHeight())) {
//ScrollView的高度大于或等于子View的高度,此时允许上拉
return true;
} else if (mPullAction == PullAction.PullUp &&
(mContentLayout.getHeight() + mContentLayout.getScrollY() >=
mChildView.getHeight())) {
//ScrollView的高度 + ScrollView的滚动高度 >= 子View的高度(说明已经滚动到底部)
return true;
} else if (mPullAction == PullAction.PullUp && getScrollY() < 0) {
//ScrollView先经过下拉拉出了一段距离(负数),再进行上拉操作,此时需要恢复位置
return true;
} else {
return false;
}
}
/ **
* 平滑滚动到指定位置
*
* @param toX 目标水平位置
* @param toY 目标垂直位置
*/
private void smoothScrollTo(int toX, int toY) {
mScroller.abortAnimation();
mScroller.forceFinished(true);
int fromX = getScrollX();
int fromY = getScrollY();
mScroller.startScroll(fromX, fromY, toX - fromX, toY - fromY, 300);
invalidate();//要求重绘(即调用draw,该方法会调用computeScroll)
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();//要求重绘(即调用draw,该方法会调用computeScroll)
}
}
}
android带反弹效果ScrollView
最新推荐文章于 2021-05-29 06:18:46 发布