我们经常看到这样的效果,一个ListView和GridView亦或者是RecycleView,再上拉或下拉到顶部的时候,还能再拖拽一段距离,这种效果是是非常常见的,因为用的比较多,所以记录一下.
实现思路是自定义一个ScrollView:
具体代码如下
package fenganoschina.fenganoschina;
import android.annotation.SuppressLint;
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.ListView;
import android.widget.ScrollView;
/**
* 可以拖动的ScrollView
*/
public class CustomerScrollView extends ScrollView {
private static final int size = 4;//拖动的距离为屏幕的高度的1/4
private View inner;
private float y;
private Rect normal = new Rect();;
public CustomerScrollView(Context context) {
super(context);
}
public CustomerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
setOverScrollMode(ListView.OVER_SCROLL_NEVER);
}
@Override
protected void onFinishInflate() {
if (getChildCount() > 0) {
inner = getChildAt(0);
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (inner == null) {
return super.onTouchEvent(ev);
} else {
commOnTouchEvent(ev);
}
return super.onTouchEvent(ev);
}
public void commOnTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
y = ev.getY();
break;
case MotionEvent.ACTION_UP:
if (isNeedAnimation()) {
// Log.v("mlguitar", "will up and animation");
animation();
}
break;
case MotionEvent.ACTION_MOVE:
final float preY = y;
float nowY = ev.getY();
/**
* size=4 表示 拖动的距离为屏幕的高度的1/4
*/
int deltaY = (int) (preY - nowY) / size;
// 滚动
// scrollBy(0, deltaY);
y = nowY;
if (isNeedMove()) {
if (normal.isEmpty()) {
normal.set(inner.getLeft(), inner.getTop(),
inner.getRight(), inner.getBottom());
return;
}
int yy = inner.getTop() - deltaY;
// 移动布局
inner.layout(inner.getLeft(), yy, inner.getRight(),
inner.getBottom() - deltaY);
}
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();
}
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;
}
}
布局文件
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.fengan.CustomerScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.fengan.ListViewForSc
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
com.fengan.ListViewForSc>
com.fengan.CustomerScrollView>
RelativeLayout>
需要注意的是:因为涉及到ScrollView和ListView的嵌套,会导致ListView上显示数据不完全
可以简单的自定义ListView代码:
(具体见上篇http://blog.csdn.net/fenganit/article/details/53732479)
代码如下:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
/**
* Created by fengan on 2016/12/19.
*/
public class ListViewForSc extends ListView{
public ListViewForSc(Context context) {
super(context);
}
public ListViewForSc(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ListViewForSc(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
是不是很简单呢