接着前面几篇文章,我们这篇文章实现拖动控件的效果:
实现如上的效果有以下几种方法:
layout()
offsetLeftAndRight(dx)和offsetTopAndBottom(dy)
LayoutParams
scrollTo和scrollBy
首先实现这样的一个效果,我们需要重写控件DragView继承自View,然后在控件中监听手势动作,就是需要重写onTouchEvent();
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//记录初始位置
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int dx = x - lastX;
int dy = y - lastY;
//*****在这里实现控件的拖动*****
// 放入下面的代码
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
实现控件的拖动,事实上就是根据手势不断的重新绘制控件。在视觉上就是跟着手势进行移动。
layout()
我们都知道控件中有一个layout,作用就是让绘制控件显示到屏幕上。
layout(getLeft() + dx, getTop() + dy, getRight() + dx, getBottom() + dy);//重新绘制
让我们的控件也更加手势来重新绘制到,移动后的位置。
offsetLeftAndRight(dx)和offsetTopAndBottom(dy)
这个方法相当于系统提供的一个对左右上下移动的API的封装,当计算出偏移量后,只需要将参数分别给到方法中,就可以实现控件的重新布局,效果与上面的Layout方法一样。
//同时对left和right进行偏移
// offsetLeftAndRight(dx);
//同时对top和buttom进行偏移
//offsetTopAndBottom(dy);
LayoutParams
我们知道动态设置控件的位置等参数可以通过LayoutParams,那么这个方法当然也可以实现动态的设置布局的绘制。
代码如下:
// 使用LayoutParams进行设置,这里除了父布局的LayoutParams,也可以使用ViewGroup.MarginLayoutParams来实现这一功能。
LinearLayout.LayoutParams params = ( LinearLayout.LayoutParams) getLayoutParams();
params.leftMargin = getLeft() + dx;
params.topMargin = getTop() + dy;
setLayoutParams(params);
当然LayoutParams是我们控件的父布局对应的Params.当然我们也可以使用ViewGroup.MarginLayoutParams来实现,代码一样。很简单,不做详解。
scrollTo和scrollBy
在View中为我们提供了scrollTo和scrollBy两种方式来改变一个View的位置,scroolTo(x,y)表示从移动到一个具体的位置,而scrollBy(dx,dy)表示移动量为d x,dy.
代码如下:
//如果使用就需要对ViewGroup,对于View,就是父布局
((View) getParent()).scrollBy(-dx, -dy);//这里移动的不是控件而是坐标系,所以参数为负,同理,scrollTo()是绝对坐标
scrollBy(-dx, -dy)其实这里移动的并不是控件本身,从代码中我们可以看出实际上是移动的父控件中的content,还是该控件,呀?这不相当于没说么?这里再重点解释一下。
不妨这样想象我们的手机屏幕是一块中间被挖掉的纸板,纸板下面是一个巨大的画布,也就是我们想要展示的视图,当我们把这个纸板盖在画布上时,透过中间的部分可以看到画布上的视图,画布其余部分我们是看不到的。我们的scrollBy方法实际相当于你移动外面的纸板,当你移动移动,也相当于移动视图的坐标,那么我们相当于控件的移动正好相反,所以使用的是负值。
以上四种实现可拖动的控件的方法特别简单,其实还有其他的方法来实现。例如动画,ViewDragHelper等。这个以后有时间再加上。