自定义view---拖拽题

示例图

思路一:

1>上下两个LinearLayout,分别addView对应的itemView

2>new一个二维数组,分别记录热区范围,选项最终要落下的位置范围

3>拖动控件的时候可以通过不停的绘制,来达到移动的效果

4>判断是否在热区范围,确定最终的位置

示例图

优点:

1.上手比较容易,获取到第一个itemView距离左边的距离,每个itemView的leftTop与rightBottom排排算就

2.由于是在一个界面不停绘制,不用考虑选项控件无法拖出去的问题

缺点:

1.数组写死的,代码量恶心,只能改动配置在dimens里面的字段

2.可读性差

思路二:

1.自定义ViewGroup,题目与选项作为子View放在父布局中,通过List记录加进来的每个view

2.无法将控件拖动出去,采用WindowManager,改变x,y,updateViewLayout来改变控件的位置

优缺点就不赘述了,这个方案我实践过,通过WindowManager来使view移动,总感觉不是很合适,并不是要做真正悬浮的弹窗。。

思路三:

动态计算热区范围,舍弃数组,舍弃绘制(位置不好控制)

问题1:怎么动态计算

view中提供了对应的方法:

getLocationOnScreen----相对于整个屏幕view的绝对坐标,顶端算起

getLocationInWindow----相对于当前窗口view的绝对坐标

但是调用这两个方法需要时机,需要在view绘制完成的时候调用

getViewTreeObserver().addOnGlobalLayoutListener(布局完成时候调用,每次布局改变时候调用),注意点是:可能会被触发多次,所以需要获取到相应数据后,注销掉

通过getLocationOnScreen可以获取到view对应leftTop的x,y数值 ,我们获取view对应的leftToprightBottom就可以计算出来。

代码实例
运行图

红色布局为我获得的热区范围:显然不对!

忽略了getLocationOnScreen是从顶端算起的,刚开始想当然的减去了状态栏的高度,发现热区范围还是不对,检查代码发现自己继承的activity是AppCompatActivity(当然界面体现的更直观一点)应该还应减去actionbar的高度。

网上

网上搜的对该方法的解释,有一定的漏洞,记住是从顶端算起就可以了,不要想当然的只减去通知栏的高度

代码实例

这样热区范围大致定下来了。。。

但是,当给父布局设置android:gravity="center"后,热区范围又乱了。。可能这时候也意识到了,通过getLocationOnScreen方法获取到的x也应该减去该view距离左边的距离。。。

示例图

其他范围的热区同理


问题2:选项作为独立的自定义View,是LinearLayout addView进去的,所以选项可以移动的范围只有下方的这片区域,无法整体移动    

在拖动选项时,父布局可以add一个新的拖动的view,原来的view invisiable

疑问:为什么不直接移动之前的,因为布局会乱掉


问题3:拖动的控件与自己手势不符

原先代码:开始代码:move-->setX(getRawX())     setY(getRawY())

忽略了需要减去偏移量。。

后来:move-->setX(getRawX()-x轴)     setY(getRawY()-y轴)

基础知识普及:


疑问:为什么不用getX

根据图示:getRawX-偏移量===getLeft()+getX()

但是在实际拖动的时候,会发现getLeft获取到的始终是初始的默认值

基础知识普及:

getLeft(): 是子View距离父View左边的距离, 这个值不会随着View的属性(transitionX和X)的改变而改变。View在layout的时候,会调用setFrame()函数来改变left的值。也可以直接调用setLeft()来改变left值,但是调用setLeft方法之后,View的宽度也会改变。因为View的大小是right - left之间的块。(好像api并不提倡直接改变调用set方法),同时调用setLeft()和setRight()方法会改变View的大小。

getTranslationX():TranslationX 是view 相对于第一初始化时候(View 相对于left的位移),自己的位置的偏移量,向右为正,向左为负,第一次初始化时候为0。可以用setTranslationX()方法,或者动画来改变这个偏移量,而TranslationX的值得改变,不会导致getLeft()的值得改变。属性动画改变的是x和translationX的值,没有改变left的值。

getX() = getLeft() + getTranslationX(), 注意setX其实是设置setTranslationX()

所以答案是:用不了

问题4:选项动画漂移

1.ObjectAnimator

需要传入(startPosition,endPositoin)

2.TranslateAnimation

只需要知道endPositoin

注意:都是差值,因为是拖动,所以startPositon差值为0

fromXDelta:这个参数表示动画开始的点离当前View X坐标上的差值;

toXDelta, 这个参数表示动画结束的点离当前View X坐标上的差值;

fromYDelta, 这个参数表示动画开始的点离当前View Y坐标上的差值;

toYDelta)这个参数表示动画开始的点离当前View Y坐标上的差值;

代码地址:GitHub - guohaiping521/QuestionView

你可能感兴趣的:(自定义view---拖拽题)