需要實現的功能
當下滑或上滑到盡頭時還能繼續滑動,釋放手指後能自動回彈到原來的位置
需要用到的知識點
- 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:[email protected]
*/
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>