这个是拖动以后的效果,一个imageview和一个button控件,提供两份代码下载吧,一份是只有一个Button的,另一份就是像上图,就是多了一个imagview!先看下代码吧,比较简单:
设置View的位置。
有一点忘记说了,就是像ImageView和TextView这些控件,要想实现拖动,要在xml文件中设置它的clickable为true。
就这样,这些就是这个demo的全部内容。
最后,是代码的下载地址:
http://download.csdn.net/detail/aomandeshangxiao/4187376,
http://download.csdn.net/detail/aomandeshangxiao/4189910
========================分割线2016年4月19日10:12:02================================================
当界面如果有切换、或者刷新的动作之后,发现所有拖动的控件,都会恢复到原来的位置,应该是父类执行了onlayout方法,恢复到默认的位置了,需要重新复写父类的方法,如下:
这个更简单,在刷新子控件位置的时候,去遍历一下,找到DraggableFloatingButton,如果left不为-1则说明之前移动过了,子控件再自己调次layout用自己记录的上次移动后的坐标,即可保证位置在父布局刷新的时候不受影响
[code] @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); for (int i = 0; i < getChildCount(); i++) { if (getChildAt(i) instanceof DraggableFloatingButton) { // 为了防止浮动按钮恢复原位,布局子控件位置时使用上次记录的位置 DraggableFloatingButton child = (DraggableFloatingButton) getChildAt(i); if (child.getLastLeft() != -1) { child.layout(child.getLastLeft(), child.getLastTop(), child.getLastRight(), child.getLastBottom()); } break; } } }父类重写的代码如下:
package net.loonggg.viewgroup; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; public class MyViewGroup extends ViewGroup { public MyViewGroup(Context context) { super(context); } public MyViewGroup(Context context, AttributeSet attrs) { super(context, attrs); } public MyViewGroup(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 计算控件的大小 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measureWidth = measureWidth(widthMeasureSpec); int measureHeight = measureHeight(heightMeasureSpec); // 计算自定义的ViewGroup中所有子控件的大小 measureChildren(widthMeasureSpec, heightMeasureSpec); // 设置自定义的控件MyViewGroup的大小 setMeasuredDimension(measureWidth, measureHeight); } private int measureWidth(int pWidthMeasureSpec) { int result = 0; int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式 int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸 switch (widthMode) { /** * mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, * MeasureSpec.AT_MOST。 * * * MeasureSpec.EXACTLY是精确尺寸, * 当我们将控件的layout_width或layout_height指定为具体数值时如andorid * :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。 * * * MeasureSpec.AT_MOST是最大尺寸, * 当控件的layout_width或layout_height指定为WRAP_CONTENT时 * ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可 * 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。 * * * MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView, * 通过measure方法传入的模式。 */ case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = widthSize; break; } return result; } private int measureHeight(int pHeightMeasureSpec) { int result = 0; int heightMode = MeasureSpec.getMode(pHeightMeasureSpec); int heightSize = MeasureSpec.getSize(pHeightMeasureSpec); switch (heightMode) { case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = heightSize; break; } return result; } /** * 覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下, * 才能确定怎么摆放 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 记录总高度 int mTotalHeight = 0; // 遍历所有子视图 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); // 获取在onMeasure中计算的视图尺寸 int measureHeight = childView.getMeasuredHeight(); int measuredWidth = childView.getMeasuredWidth(); childView.layout(l, mTotalHeight, measuredWidth, mTotalHeight + measureHeight); mTotalHeight += measureHeight; } } }//==============================分割线,2016年4月25日13:59:05=================================
/** * 监听左上方悬浮的控件 */ @Override public boolean onTouch(View v, MotionEvent event) { if (DocCaptain.getInstance().isIfOrderLayout()) { webviewWidth = DocCaptain.getInstance().getWebviewWidthTrade(); webviewHeight = DocCaptain.getInstance().getWebviewHeightTrade(); } int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_POINTER_DOWN: break; case MotionEvent.ACTION_POINTER_UP: break; case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX() - lastX; int dy = (int) event.getRawY() - lastY; int left = v.getLeft() + dx; int top = v.getTop() + dy; int right = v.getRight() + dx; int bottom = v.getBottom() + dy; if (left < 0) { left = 0; right = left + v.getWidth(); } if (right > webviewWidth) { right = webviewWidth; left = right - v.getWidth(); } if (top < 0) { top = 0; bottom = top + v.getHeight(); } if (bottom > webviewHeight) { bottom = webviewHeight; top = bottom - v.getHeight(); } RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v .getLayoutParams(); layoutParams.leftMargin = left; layoutParams.topMargin = top; layoutParams.rightMargin = right; layoutParams.bottomMargin = bottom; v.setLayoutParams(layoutParams); // // DocCaptain.getInstance().setSuspendLeft(left); // DocCaptain.getInstance().setSuspendTop(top); // DocCaptain.getInstance().setSuspendRight(right); // DocCaptain.getInstance().setSuspendBottom(bottom); // v.layout(left, top, right, bottom); lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); break; } v.invalidate(); return true; }