当原生的listview不能满足用户在审美,功能上不断提高的需求时,我们就需要对原生的listview进行自定义。
1.具有弹性的listiew
玩过iOS的朋友都会注意到它所有的列表都是具有弹性的,即滚动到底部或者是顶部的时候都会继续向下滑动一段距离。Android在5.X以后,为列表添加了一个半月形的阴影效果。网上也有很多来重写listview来实现弹性的效果,比如说增加一个headerView或者是使用scrollView来进行嵌套。
在listview的源码中有这样一个方法:
/**
* Scroll the view with standard behavior for scrolling beyond the normal
* content boundaries.Views can use this method to handle any touch or fling-based scrolling.
* 该方法可以用来处理滑动超出屏幕范围的事件或者是惯性滑动事件都可以
* @param maxOverScrollX X轴的最大的像素数
* @param maxOverScrollY Y轴的最大的像素数
* @param isTouchEvent
*/
@Override
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
maxOverScrollY表示的是在Y轴上可以滑动的像素数,看源码可知该值默认值是0.所以只要修改这个值即可,设置滑动的屏幕的边缘像素即可。
public class FliexListview extends ListView {
private Context mContext;
private static int mMaxOverScrollY = 30; // 设置滑动的距离值
public FliexListview(Context context) {
this(context,null);
}
public FliexListview(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FliexListview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initView();
}
private void initView() {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
float density = metrics.density; // 获取到屏幕的密度
mMaxOverScrollY = (int) (density * mMaxOverScrollY); // 此处可针对不同的手机屏幕设置相同的距离(屏幕适配)
}
/**
* Scroll the view with standard behavior for scrolling beyond the normal
* content boundaries.Views can use this method to handle any touch or fling-based scrolling.
* 该方法可以用来处理滑动超出屏幕范围的事件或者是惯性滑动事件都可以
* @param maxOverScrollX X轴的最大的像素数
* @param maxOverScrollY Y轴的最大的像素数
* @param isTouchEvent
* @return
*/
@Override
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, maxOverScrollX, mMaxOverScrollY, isTouchEvent);
}
}
2带自动隐藏和显示的listview
现在的APP中会看到当我们在listview上滑动的时候,顶部的toorBar或者是ActonBar就会进行自动的隐藏或者是显示。也就是说在滚动之前加载了上方的标题栏好一些悬浮编辑按钮,当用户去滚动的时候,标题栏和悬浮按钮就会消失。
思路:我们知道让一个布局显示或者是隐藏并带有动画的效果,可以通过属性动画的效果来进行实践,所以这个问题的关键就是在于如何获取到listview的各种滑动事件。借助view的OnTouchListener接口来监听Listview的滑动,通过比较与上次坐标的大小,来判断滑动的方向,并且通过滑动的方向判断是否要进行显示或者是隐藏对应的布局。
1.在判断滑动事件之前,首先要给listview添加一个HeaderView控件
private void addHeaderView() {
View headerView = new View(this);
headerView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
(int) getResources().getDimension
(android.support.v7.appcompat.R.dimen.abc_action_bar_default_height_material)));
mListView.addHeaderView(headerView);
注意:R.dimen.abc_action_bar_default_height_material是V7包中的,用的是activity时要注意。
2.判断滑动事件
通过滑动点的坐标改变的大小,用来判断移动的方向,并且根据不同的移动方向来执行不同的动画效果。向下滑动一定的距离就显示toorBar,向上滑动一定的距离就隐藏toorBar。
View.OnTouchListener myToucheListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
currentMoveY = event.getY();
// 判断滑动的方向
if ((currentMoveY - downY) > touchSlop) {
direction = 0; //down
} else if ((downY - currentMoveY) > touchSlop) {
direction = 1; // up
}
if (direction == 1) {
if (visible) {
// 可见
// 设置可见
toolBarAnima(1); //
visible = !visible;
}
} else if (direction == 0) {
if (!visible) {
// 不可见
toolBarAnima(0);
visible = !visible;
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
};
3.控制布局的隐藏于显示
动画使用的是位移属性动画:
private void toolBarAnima(int flag) {
if (mAnimator != null && mAnimator.isRunning()) {
// 如果正在运行,取消动画
mAnimator.cancel();
}
if (flag == 0) {
mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY",
mToolbar.getTranslationY(), 0);
} else {
mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY",
mToolbar.getTranslationY(), -mToolbar.getHeight());
}
mAnimator.start();
效果图: