原理:
在大部分情況下都會出現父容器重繪,當視圖位置發生改變時,需要相應更新其相對于父布局的目前所在位置,否則父布局重繪時,由于沒有在父布局中更新視圖位置,導緻重繪的時候視圖會回到初始位置,是以在拖動視圖控件位置的同時,還需設定其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;
}
}