最近总是感觉自己力不从心,好多都不会啊,都不会,所以想从基础学起一些东西,总结一下自定义view滑动的方式。这里以可以随手指滑动的textview 为例子:
上效果图:
直接上源码:
第一种方式:
public class MyTextView extends TextView {
private int x, y, dx, dy, offX, offY;
public MyTextView(Context context) {
this(context, null);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* getX getY ,layout实现
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getX();
y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
layout(getLeft()+offX,getTop()+offY,getRight()+offX,getBottom()+offY);
break;
}
return super.onTouchEvent(event);
}
}
第二种方式:
由于都是重写onTouch ,重复的代码就不粘贴了
/**
* getRawX getRawY 跟上面的一样,只不过需要注意的是初始化
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getRawX();
y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
layout(getLeft()+offX,getTop()+offY,getRight()+offX,getBottom()+offY);
Log.d("dx---------------------", "" + dx);
Log.d("x---------------------",""+x);
//需要重新初始化手指按下的坐标 如果dx dy不跟随手指而变化的话,会导致变化过大,view飞出去,或者连续移动一大段距离
dx=x;
dy=y;
break;
}
return super.onTouchEvent(event);
}
第三种方式:
/**
* getRawX getRawY 跟上面的一样,只不过需要注意的是初始化
* offsetLeftAndRight offsetTopAndBottom 实现
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getRawX();
y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
offsetLeftAndRight(offX);
offsetTopAndBottom(offY);
Log.d("dx---------------------", "" + dx);
Log.d("x---------------------",""+x);
//需要重新初始化手指按下的坐标 如果dx dy不跟随手指而变化的话,会导致变化过大,view飞出去,或者连续移动一大段距离
dx=x;
dy=y;
break;
}
return super.onTouchEvent(event);
}
第四种方式:
/**
* LinearLayout.LayoutParams RelativeLayout.layoutParams 需要注意父容器的类型
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getRawX();
y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
LinearLayout.LayoutParams layoutParams=(LinearLayout.LayoutParams)getLayoutParams();
layoutParams.leftMargin=getLeft()+offX;
layoutParams.topMargin=getTop()+offY;
setLayoutParams(layoutParams);
Log.d("dx---------------------", "" + dx);
Log.d("x---------------------",""+x);
//需要重新初始化手指按下的坐标 如果dx dy不跟随手指而变化的话,会导致变化过大,view飞出去,或者连续移动一大段距离
dx=x;
dy=y;
break;
}
return super.onTouchEvent(event);
}
第五种方式:
/**
* ViewGroup.MarginLayoutParams 跟上面的方法比较类似,但是不必要注意父布局的类型了,没有限制
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getRawX();
y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
ViewGroup.MarginLayoutParams layoutParams=(ViewGroup.MarginLayoutParams)getLayoutParams();
layoutParams.leftMargin=getLeft()+offX;
layoutParams.topMargin=getTop()+offY;
setLayoutParams(layoutParams);
Log.d("dx---------------------", "" + dx);
Log.d("x---------------------",""+x);
//需要重新初始化手指按下的坐标 如果dx dy不跟随手指而变化的话,会导致变化过大,view飞出去,或者连续移动一大段距离
dx=x;
dy=y;
break;
}
return super.onTouchEvent(event);
}
第六种方式:
/**
* scrollBy 实现 scroll移动的是内容,例如本例是个textview那么移动的就是textview的文字了,所以需要getParent
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
x = (int) event.getRawX();
y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
//由于参考系的不同所以需要前面加上"-"号
((ViewGroup)getParent()).scrollBy(-offX,-offY);
Log.d("dx---------------------", "" + dx);
Log.d("x---------------------",""+x);
//需要重新初始化手指按下的坐标 如果dx dy不跟随手指而变化的话,会导致变化过大,view飞出去,或者连续移动一大段距离
dx=x;
dy=y;
break;
}
return super.onTouchEvent(event);
}
第七种方式:
上效果图:
public class MyTextView extends TextView {
private int x, y, dx, dy, offX, offY;
private Scroller mScroller;
public MyTextView(Context context) {
this(context, null);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);//初始化scroller对象
}
@Override
public void computeScroll() {
super.computeScroll();
//会循环调用下面的代码直到到达指定位置
if (mScroller.computeScrollOffset()) {
((ViewGroup) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
/**
* scroller 方法实现滑动
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
ViewGroup viewGroup = (ViewGroup) getParent();
x = (int) event.getRawX();
y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = x;
dy = y;
break;
case MotionEvent.ACTION_MOVE:
offX = x - dx;
offY = y - dy;
viewGroup.scrollBy(-offX, -offY);
dx = x;
dy = y;
break;
case MotionEvent.ACTION_UP:
//回滚回原来的位置,也可以加上时间
mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(),
-(viewGroup.getScrollX()), -(viewGroup.getScrollY()));
invalidate();
break;
}
return super.onTouchEvent(event);
}
}
上面的貌似是个假的第七种方法,这里面其实主要说的是scroller这个类的使用!~