您的位置:首页 > 移动开发 > Android开发

Android自定义View--ScrollView实现回弹效果

2016-12-08 10:13 633 查看


需要实现的功能

当下滑或上滑到尽头时还能继续滑动,释放手指后能自动回弹到原来的位置

需要用到的知识点

getScrollY()

getScrollY是当前view的左上角相对于母视图(这里是ScrollView)的左上角的Y轴偏移量,上拉值增加,反之亦然。

getMeasuredHeight()

getHeight()

1.getMeasuredHeight()返回的是原始测量高度,与屏幕无关,getHeight()返回的是在屏幕上显示的高度,项目利用子View的getMeasuredHeight()减去父类(ScrollView)的高度,判断是否滑动到底部。

MyScrollView的实现

package rc.loveq.myscrollview;

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

/**
* Author:Rc
* Csdn:http://blog.csdn.net/loveqrc
* 0n 2016/12/8 08:46
* Email:664215432@qq.com
*/

public class MyScrollView extends ScrollView {

private static final String TAG ="MyScrollView" ;
private static final long RESTORE_TIME = 300;//回弹的时间
public static final int DRAG_RATE=2;//mChildView移动的距离=手指移动的的距离/DRAG_RATE
private View mChildView;
private float mDownY;
private Rect mRect=new Rect();//用于保存子View的位置
private boolean isRestoring=false;//是否正在回弹

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

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

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

@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount()>0){//保证要有子View
mChildView = getChildAt(0);
}
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
if (!isRestoring){
handleTouchEvent(ev);//监听触摸事件
}
//因为我们要做的是当scrollView下滑或上滑到尽头还能继续滑动
//所以只有这两种情况我们才自己处理
//其他情况交由父类默认实现

Log.e(TAG, "onTouchEvent: getScrollY:"+getScrollY());
return super.onTouchEvent(ev);
}

private void handleTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
mDownY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveY = ev.getY();
int deltaY= (int) (moveY-mDownY);
if (isNeedLoadMore()){
if (mRect.isEmpty()){//如果没有记录子view位置,那么我们记录
mRect.set(mChildView.getLeft(), mChildView.getTop()
, mChildView.getRight(), mChildView.getBottom());
}
mChildView.layout(mChildView.getLeft(), mChildView.getTop()+deltaY/DRAG_RATE,
mChildView.getRight(), mChildView.getBottom()+deltaY/DRAG_RATE);
}
mDownY=moveY;//更新位置
break;
case MotionEvent.ACTION_UP://当手指释放的时候,需要回弹到原来的位置
mDownY=0;
if (isNeedRestore()){
restoreState();
}
break;
}
}

/**
* 恢复到原来的位置
*/
private void restoreState() {
//TranslateAnimation移动的相对位置
TranslateAnimation ta=new TranslateAnimation(0,0,0,mRect.top- mChildView.getTop());
ta.setDuration(RESTORE_TIME);
mChildView.startAnimation(ta);
ta.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
isRestoring=true;
}

@Override
public void onAnimationEnd(Animation animation) {
isRestoring=false;
mChildView.clearAnimation();
//保证回到原来的位置
mChildView.layout(mRect.left,mRect.top,mRect.right,mRect.bottom);
mRect.setEmpty();
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});

}

/**
* 判断是否需要回弹
* @return
*/
private boolean isNeedRestore() {
return !mRect.isEmpty();//如果保存过位置,说明需要回弹
}

/**
* 是否已经滑动尽头了
* @return
*/
private boolean isNeedLoadMore() {
int offset = mChildView.getMeasuredHeight() - getHeight();
int scrollY = getScrollY();
if (scrollY==0||offset==scrollY){//当scrollY==0表示向下滑滑到尽头了
return true;            // offset==scrollY 表示向上滑滑到尽头了
}
return  false;
}

}


布局代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<rc.loveq.myscrollview.MyScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第1个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第2个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第3个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第4个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第5个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第6个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第7个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第8个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第9个数据"/>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:textSize="36sp"
android:text="这是第10个数据"/>

</LinearLayout>
</rc.loveq.myscrollview.MyScrollView>
</RelativeLayout>


下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: