1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > android 控件拖拽功能 Android自定义图片拖拽控件

android 控件拖拽功能 Android自定义图片拖拽控件

时间:2020-05-15 00:27:01

相关推荐

android 控件拖拽功能 Android自定义图片拖拽控件

效果图

基本思路

布局示意图

我们先考虑简单的情况,两个控件之间的图片拖拽,首先我们需要准备ImageViewA和ImageViewB两个ImageView,然后在里面设置图片。接着我们需要考虑拖拽事件的触发条件,这里假设为手指从ImageView的某个边缘滑出一段距离即触发拖拽事件

假设我们此时在ImageViewA的边缘向下滑动了一段距离,在触发拖拽事件的时候我们需要将ImageViewA的图片隐藏,然后将A的图片传递给一个半透明的ImageViewC并将C显示出来,由于这个ImageViewC同一时间只会有一个,所以我们可以在自定义的layout中创建一个ImageView类型的成员变量进行复用,在触发拖拽事件的时候ImageViewC会跟随手指滑动,在手指抬起来的时候判断ImageViewC的中心是否在另一个ImageViewB上,若在则交换A和B的图片

整体思路还是比较清晰的,主要是要创建一个自定义的layout对子View进行管理并自定义事件分发规则

代码实现

自定义Layout

此处选择继承自FrameLayout,因为可以通过margin属性自由控制View所在的位置并且不会影响到其他的View,后期可能会向Layout中添加一些EditText、TextView或者各种自定义View,而这些View可能是要叠在ImageView上面的,因此选择继承自FrameLayout无疑是最合适的,而且它已经帮我们处理了很多细节,我们可以专注于功能的实现

获取子View所在的区域信息

因为对事件进行分发需要子View的位置信息,所以我们需要一个成员变量来保存,此处选择RectF来保存一个View所在的区域,然后将所有View的位置信息存放到一个HashMap中,这样就可以处理两个以上的控件间图片拖拽了

public class ConfigurableFrameLayout extends FrameLayout implements OnTriggerDragListener {

...

// 保存所有子View的区域

private HashMap mChildViewRects;

...

@Override

protected void onLayout(boolean changed,int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right,bottom);

/* 因为layout后每个子View的位置才确定,所以在此处初始化子View的位置信息*/

initChildViewRect();

}

/**

* 获取各子View所在区域

*/

private void initChildViewRect() {

for (int i = 0; i < getChildCount(); i++) {

View child = getChildAt(i);

LayoutParams lp = (LayoutParams)child.getLayoutParams();

// 避免多次创建对象

RectF rect = mChildViewRects.get(child;

if (rect == null) {

rect = new RectF();

}

// 设置子View所在的矩形区域

rect.set(lp.leftMargin,lp.topMargin,

lp.leftMargin + child.getWidt(),

lp.topMargin +child.getHeight());

mChildViewRects.put(child, rect);

}

}

}

对事件进行分发

子View有可能比较小,如果要两根手指都在子View里面才能对图片进行操作会不太方便,而我们要实现只要一根手指在子View内,另一根手指无论在哪都可以对子View的图片进行操作,并且同一时间只能操作一个子View,此时就需要自定义事件分发规则

自定义事件分发规则可以选择重写dispatchTouchEvent()方法,但是需要考虑的细节比较多,所以我们选择拦截所有事件,然后在onTouchEvent()方法中对事件进行分发

//重写自定义Layout的onInterceptTouchEvent()和onTouchEvent()

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

super.onInterceptTouchEvent(ev);

// 拦截所有事件

return true;

}

private View mCurrentChildView; // 当前正在处理触摸事件的子View

@Override

public boolean onTouchEvent(MotionEventevent) {

// 事件是否被子View消费

boolean handled = false;

// 当前事件流若已被分发给某个子View处理,则将后续事件都分发给该子View

if (mCurrentChildView != null) {

handled = dispatchTouchEventToChild(event, mCurrentChildView);

}

switch (event.getActionMasked()) {

case MotionEvent.ACTION_DOWN:

// 获取位于触点的子View

mCurrentChildView = viewInXY(event.getX(), event.getY());

// 判断子View是否可以触发拖拽事件,可以则为其设置触发时的监听事件

if (mCurrentChildView instanceof TriggerDraggable) {

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。