原理:
在大部分情况下都会出现父容器重绘,当视图位置发生改变时,需要相应更新其相对于父布局的当前所在位置,否则父布局重绘时,由于没有在父布局中更新视图位置,导致重绘的时候视图会回到初始位置,所以在拖动视图控件位置的同时,还需设置其layoutparams参数。
代码:
核心代码:
//拖动完毕,更新view在父布局中的位置参数,避免刷新父布局view又回到原点
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)getLayoutParams();
params.setMargins(mLeft,mTop,0,0);
//这里指定下宽高,否则如果布局文件指定了match_parent/wrap_content,会导致自动伸缩宽高
params.width = getMeasuredWidth();
params.height = getMeasuredHeight();
setLayoutParams(params);
自定义控件示例:
/**
* 可拖拽LinearLayout
*/
public class DragLinearLayout extends LinearLayout {
/*
private boolean
onlyX,//仅X轴可移动
onlyY;//仅Y轴可移动*/
private int
lastX,lastY,//记录上一次的x,y坐标
mLeft,mTop,mRight,mBottom,//记录当前元素的的上下左右(相对于父元素)
startX,startY,//记录初始x,y坐标
endX,endY;//移动结束x,y坐标,用于计算是否点击事件
//用于点击事件触发
public interface OnClickListener
{
void onClick(View view);
}
OnClickListener clickListener = null;
public DragLinearLayout(Context context) {
super(context);
}
public void setOnClickListener(OnClickListener listener)
{
clickListener = listener;
}
public DragLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
/*
//获取属性值
TypedArray type = context.obtainStyledAttributes(attrs, R.styleable.DragLinearLayout);
onlyX = type.getBoolean(R.styleable.DragLinearLayout_onlyX,false);
onlyY = type.getBoolean(R.styleable.DragLinearLayout_onlyY,false);
type.recycle();*/
}
public DragLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int rawX = (int)event.getRawX();
int rawY = (int)event.getRawY();
switch (action)
{
case MotionEvent.ACTION_DOWN://按下记录初始坐标
startX = lastX = rawX;
startY = lastY = rawY;
break;
case MotionEvent.ACTION_MOVE:
//计算偏移量
int dx = rawX - lastX;
int dy = rawY - lastY;
/*
//限制只能x轴方向拖动
if (onlyX)
{
dy = 0;
//限制只能y轴方向拖动
}else if (onlyY)
{
dx = 0;
}*/
//计算控件坐标距离父控件原点各方向距离
mLeft = getLeft() + dx;
mRight = getRight() + dx;
mTop = getTop() + dy;
mBottom = getBottom() + dy;
layout(mLeft,mTop,mRight,mBottom);
//拖动时背景半透明
//setBackground(getResources().getDrawable(R.drawable.draglinearlayout_press));
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_UP:
endX = rawX;
endY = rawY;
//拖动完毕背景恢复
//setBackground(getResources().getDrawable(R.drawable.draglinearlayout_up));
//点击事件
if (Math.abs(endX - startX) < 3 || Math.abs(endY - startY) < 3) {
this.performClick();
}
//拖动完毕,更新view在父布局中的位置参数,避免刷新父布局view又回到原点
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)getLayoutParams();
params.setMargins(mLeft,mTop,0,0);
//这里指定下宽高,否则如果布局文件指定了match_parent/wrap_content,会导致自动伸缩宽高
params.width = getMeasuredWidth();
params.height = getMeasuredHeight();
setLayoutParams(params);
break;
}
return true;
}
}