ListView实战
弹性ListView
相当多的大陆应用厂商开发安卓应用时不仅界面上会效仿ios,连用户的操作体验也都要效仿。比如,现在说的弹性ListView。相比android,在ios上窗口和界面之间的关系不是很紧密,界面的自由度更高,所以界面可以随着手指的上下滑动呈现一种弹性动效,即界面滚动到底端或者顶端后会随手势继续往上或往下滑动一段距离,手一离开屏幕,界面恢复原位。(笔者不懂ios开发,纯就使用体验猜测,或许是一种苹果官方推荐的效果,可加可不加),所以那些产品需求也要求我们去做一个类似的效果。
网上有很多通过重写ListView来实现弹性效果的方法,比如增加HeaderView或者使用ScrollView进行嵌套,方法有很多,不过这里介绍一种非常简单的方法来实现这个效果。
View的源码中,有个控制滑动到边缘的方法overScrollBy
/**
* Scroll the view with standard behavior for scrolling beyond the normal
* content boundaries. Views that call this method should override
* {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the
* results of an over-scroll operation.
*
* Views can use this method to handle any touch or fling-based scrolling.
*
* @param deltaX Change in X in pixels
* @param deltaY Change in Y in pixels
* @param scrollX Current X scroll value in pixels before applying deltaX
* @param scrollY Current Y scroll value in pixels before applying deltaY
* @param scrollRangeX Maximum content scroll range along the X axis
* @param scrollRangeY Maximum content scroll range along the Y axis
* @param maxOverScrollX Number of pixels to overscroll by in either direction
* along the X axis.
* @param maxOverScrollY Number of pixels to overscroll by in either direction
* along the Y axis.
* @param isTouchEvent true if this scroll operation is the result of a touch event.
* @return true if scrolling was clamped to an over-scroll boundary along either
* axis, false otherwise.
*/
@SuppressWarnings({"UnusedParameters"})
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
final int overScrollMode = mOverScrollMode;
final boolean canScrollHorizontal =
computeHorizontalScrollRange() > computeHorizontalScrollExtent();
final boolean canScrollVertical =
computeVerticalScrollRange() > computeVerticalScrollExtent();
final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||
(overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);
final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||
(overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);
int newScrollX = scrollX + deltaX;
if (!overScrollHorizontal) {
maxOverScrollX = 0;
}
int newScrollY = scrollY + deltaY;
if (!overScrollVertical) {
maxOverScrollY = 0;
}
// Clamp values if at the limits and record
final int left = -maxOverScrollX;
final int right = maxOverScrollX + scrollRangeX;
final int top = -maxOverScrollY;
final int bottom = maxOverScrollY + scrollRangeY;
boolean clampedX = false;
if (newScrollX > right) {
newScrollX = right;
clampedX = true;
} else if (newScrollX < left) {
newScrollX = left;
clampedX = true;
}
boolean clampedY = false;
if (newScrollY > bottom) {
newScrollY = bottom;
clampedY = true;
} else if (newScrollY < top) {
newScrollY = top;
clampedY = true;
}
onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);
return clampedX || clampedY;
}
从对参数maxOverScrollY的注释中可以看出,修改其值,就可以让ListView具有弹性。那我们就自定义一个ListView,继承自ListView,重写此方法,将maxOverScrollY的默认值修改成我们想要的,注意修改的值是像素值,我们可以通过density和一个我们预想的dp值让不同分辨率的弹性距离基本一致。
注意:此种方法修改后的效果感人,弹入弹出动画比较生硬,且这种该法似乎无法加入动画以控制弹入弹出过程,所以笔者不建议使用此方法。
根据ListView的滑动状态判断隐藏布局
添加OnTouchListener,在MotionEvent。ACTION_MOVE中进行判断
聊天ListView显示不同布局的item
详见Adapter
动态改变ListViewItem的布局
两种方法:
在Adapter中的getView()进行设置,详见Adapter
ListView条目设置监听事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//1.改变布局
//2.adapter.notifyDataSetChanged();
}
});
不可滑动的ListView
public class NoScrollListView extends ListView {
public NoScrollListView(Context context) {
super(context);
}
public NoScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* 设置listView不可滑动
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}