上篇只实现了效果但是图片不能随手势滑动,要想实现这个效果,需要实现接口GestureDetector.OnGestureListener。
实现GestureDetector.OnGestureListener接口需要实现以下方法
- onDown
- onShowPress
- onSingleTapUp
- onScroll
- onLongPress
- onFling
在这个组件中,我们只需要实现onDown、onScroll就可以了,onDown返回true时才会响应触屏手势事件。onScroll中实现图片的滑动。
接下来,我们说下图片随手势滑动的
原理:
其实,不是图片滑动,是组件在滑动,屏幕沿X轴运动,看起来就像图片在随着手势滑动。
接下来,我们看下代码:
public class ImageWallView extends AdapterView<ListAdapter> implements GestureDetector.OnGestureListener{
private ListAdapter mAdapter;
private GestureDetector gestureDetector; //监听屏幕事件
private float offset=0; // 相对于(0,0)点水平方向滑动的距离
private int unitWidth; //每个单元的宽
private int numColumns; //屏幕展示的孩子的数目
/**
* 构造方法
*/
public ImageWallView(Context context) {
super(context);
init();
}
public ImageWallView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageWallView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
gestureDetector = new GestureDetector(this.getContext(),this);
gestureDetector.setIsLongpressEnabled(true); //监听长按事件
}
/**
* 继承AdapterView需要实现以下四个方法
* getAdapter()
* setAdapter(ListAdapter adapter)
* getSelectedView()
* setSelection(int position)
*/
@Override
public ListAdapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(ListAdapter adapter) {
this.mAdapter = adapter;
//把所有的child添加到布局中
for(int i=0;i<mAdapter.getCount();i++){
View child = mAdapter.getView(i,null,this);
addViewInLayout(child,i,child.getLayoutParams());
}
}
@Override
public View getSelectedView() {
return null;
}
@Override
public void setSelection(int position) { }
/**
* 实现GestureDetector.OnGestureListener接口需要实现以下方法
* onDown //响应触屏事件 这个必须返回true
* onShowPress
* onSingleTapUp
* onScroll
* onLongPress
* onFling
*/
public boolean onDown(MotionEvent e) {
return true;
}
public void onShowPress(MotionEvent e) {
}
/**
* 单击松开时响应
*/
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
/**
* 图片顺手势滑动
* @param distanceX 往右滑动是负值 往左滑动是正值
*/
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
offset = offset- distanceX;
//确保不滑出界
if(offset>0){
offset=0;
}
else if(offset < (getChildCount()-numColumns)*unitWidth*-1) {
offset = (getChildCount()-numColumns)*unitWidth*-1;
}
//重绘布局
requestLayout();
return true;
}
public void onLongPress(MotionEvent e) {
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {;
return true;
}
/**
* 设置布局
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int childCount = getChildCount();
int pLeft = 0;
int pTop = 0;
int childWidth=0;
int childHeight=0;
if(childCount>0){
View child = getChildAt(0);
LayoutParams p = child.getLayoutParams();
childWidth = p.width + child.getPaddingLeft() + child.getPaddingRight() ; // child 的宽
childHeight = p.height + child.getPaddingTop() + child.getPaddingBottom(); // child 的高
numColumns = (getMeasuredWidth() - getPaddingLeft() - getPaddingRight())/childWidth; //计算屏幕中可以放置几个child
int spacing = (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - numColumns * childWidth)/numColumns; //计算child之间的平均空隙
int spacingLR = (getPaddingLeft() + getPaddingRight() )/2;//组件左右边的平均空隙
if(spacing > spacingLR){
int outSpacing = spacing - spacingLR;
setPadding(spacingLR+outSpacing,getPaddingTop(),spacingLR+outSpacing,getPaddingBottom());
}
unitWidth = childWidth + spacing ;
}
for(int i=0;i<childCount;i++){
View child = getChildAt(i);
pLeft = getPaddingLeft() + i * unitWidth+(int)offset; //child距离左端的距离
pTop = getPaddingTop(); //child距离顶端的距离
child.layout(pLeft,pTop,pLeft + childWidth,pTop + childHeight);
}
}
/**
* 设置大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置宽度和高度
setMeasuredDimension(
getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec)
);
}
/**
* 响应触屏事件
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if(mAdapter == null){
return true;
}
boolean touchValue = gestureDetector.onTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_UP ){ //在手指抬起时调用onUp方法
onUp();
}
return touchValue;
}
/**
* 实现屏幕只显示整章的商品图片
*/
private void onUp(){
int index = (int) (Math.abs(offset) / unitWidth);
index += (Math.abs(offset) - index*unitWidth) > unitWidth/2 ? 1:0;
offset = offset>0? index*unitWidth : -1*index*unitWidth;
requestLayout();
}
}